Vue basic 3--vue component communication

1. vue assembly

1.1 vue components_ concept

Componentization: the idea of encapsulation encapsulates the reusable parts of the page into components, so as to facilitate the development and maintenance of the project

A page can be divided into components. A component is a whole. Each component can have its own independent structure style and behavior (html, css and js)

1.2 vue components_ Basic use

Pithy formula: which part of the label is reused, which part is encapsulated in the component

(important): a template within a component can only have one root label

(important): data in the component must be a function with independent scope

Steps:

  1. Create component components/Pannel.vue

Encapsulation label + style + js - components are independent for reuse

  1. Registration component: it needs to be registered before use

Global - register for use

The global entry is in main.js and registered on new Vue

Syntax:

import Vue from 'vue'
import Component object from 'vue File path'

Vue.component("Component name", Component object)

main.js - demo now

// Target: global registration (one definition everywhere)
// 1. Create component - file name.vue
// 2. Lead in components
import Pannel from './components/Pannel'
// 3. Global - register components
/*
  Syntax: 
  Vue.component("Component name (component object)
*/
Vue.component("PannelG", Pannel)

After the PannelG component name is registered globally, it can be used as a label in any Vue file template

Both single and double labels can be in lowercase plus - form. After running, the user-defined label will be parsed as a component and replaced to this position with the label encapsulated in the component

Local - registered use

Syntax:

import Component object from 'vue File path'

export default {
    components: {
        "Component name": Component object
    }
}

1.3 vue component scoped function

Requirement: div tag name selector, setting background color

Problem: it is found that both the div in the component and the div outside the component are effective

Solution: add scoped attribute to style tag in Pannel.vue component

<style scoped>

Adding the scoped attribute to the style will add a randomly generated attribute starting with data-v to the label of this component, and it must be the element of the current component to have this custom attribute and be affected by this style

2. vue component communication

Because the variables and values of each component are independent

Component communication first focuses on the transfer of parent to child, and child to parent

Parent: vue files that use other components

Sub: introduced component (embedded)

For example: app.vue (parent) myproduct.vue (child)

2.0 vue component communication parent to child - props

Requirement: encapsulate a commodity component MyProduct.vue - externally input the specific data to be displayed, as shown in the following figure

Steps:

  1. Create component components/MyProduct.vue - copy the label below

  2. The props defined variable inside the component is used to receive the value passed in from the outside

  3. The registration component is introduced into App.vue. When used, specific data is passed in to the component for display

components/MyProduct.vue - prepare label

<template>
  <div class="my-product">
    <h3>title: {{ title }}</h3>
    <p>Price: {{ price }}element</p>
    <p>{{ intro }}</p>
  </div>
</template>

<script>
export default {
  props: ['title', 'price', 'intro']
}
</script>

<style>
.my-product {
  width: 400px;
  padding: 20px;
  border: 2px solid #000;
  border-radius: 5px;
  margin: 10px;
}
</style>

Use and pass in data in App.vue

<template>
  <div>
    <!-- 
      target: father(App.vue) -> son(MyProduct.vue) Enter by value transfer respectively
      demand: Each component displays different data information
      step(Pithy formula):
        1. Subcomponents - props - variable (Ready to receive)
        2. Parent component - Pass the value in
     -->
    <Product title="Delicious salivary chicken" price="50" intro="Grand reward for opening, 20% off"></Product>
    <Product title="What a lovely adorable" price="20" intro="The boss is not at home, 10% off the court"></Product>
    <Product title="What an expensive Beijing roast duck" price="290" :intro="str"></Product>
  </div>
</template>

<script>
// 1. Create a component (. vue file)
// 2. Lead in components
import Product from './components/MyProduct'
export default {
  data(){
    return {
      str: "How expensive, Come on, yummy"
    }
  },
  // 3. Register components
  components: {
    // Product: Product // key and value variables have the same name - short form
    Product
  }
}
</script>

<style>

</style>

2.1 vue component communication parent-child cooperation cycle

data

list: [
    { id: 1, proname: "Super delicious lollipop", proprice: 18.8, info: 'Grand reward for opening, 20% off' },
    { id: 2, proname: "Super delicious big chicken leg", proprice: 34.2, info: 'Delicious but not greasy, Come and buy it' },
    { id: 3, proname: "Super invincible ice cream", proprice: 14.2, info: 'hot summer , Have an ice cream' },
],
<template>
  <div>
    <MyProduct v-for="obj in list" :key="obj.id"
    :title="obj.proname"
    :price="obj.proprice"
    :intro="obj.info"
    ></MyProduct>
  </div>
</template>

<script>
// Target: recycle components - pass in data separately
// 1. Create component
// 2. Lead in components
import MyProduct from './components/MyProduct'
export default {
  data() {
    return {
      list: [
        {
          id: 1,
          proname: "Super delicious lollipop",
          proprice: 18.8,
          info: "Grand reward for opening, 20% off",
        },
        {
          id: 2,
          proname: "Super delicious big chicken leg",
          proprice: 34.2,
          info: "Delicious but not greasy, Come and buy it",
        },
        {
          id: 3,
          proname: "Super invincible ice cream",
          proprice: 14.2,
          info: "hot summer , Have an ice cream",
        },
      ],
    };
  },
  // 3. Register components
  components: {
    // MyProduct: MyProduct
    MyProduct
  }
};
</script>

<style>
</style>

Unidirectional data flow

The principle of one-way data flow should be followed in vue

  1. When the data of the parent component changes, the child component will automatically change
  2. The child component cannot directly modify the props passed by the parent component. Props is read-only

An object is passed from the parent component to the child component. When the child component modifies the properties of the object, it will not report an error. The object is a reference type and updates each other

2.2 Vue component communication one-way data flow

Target: the data flow from parent to child is called one-way data flow

Cause: the child component is modified without notifying the parent, resulting in data inconsistency

If the commodity price in the first MyProduct.vue is modified to 5.5, but 18.8 is still recorded in App.vue - the data is inconsistent

So: Vue specifies that the variables in props are read-only

2.3 Vue component communication child to parent

Requirements: in the example above, click the bargaining function to realize the random bargaining-1 function

Syntax:

  • Parent: @ custom event name = "parent methods function"
  • Child: this.$emit("custom event name", value transfer) - execute the function code in the parent methods

components/MyProduct_sub.vue

<template>
  <div class="my-product">
    <h3>title: {{ title }}</h3>
    <p>Price: {{ price }}element</p>
    <p>{{ intro }}</p>
    <button @click="subFn">Treasure knife-Cut 1 yuan</button>
  </div>
</template>

<script>
import eventBus from '../EventBus'
export default {
  props: ['index', 'title', 'price', 'intro'],
  methods: {
    subFn(){
      this.$emit('subprice', this.index, 1) // Son to father
      eventBus.$emit("send", this.index, 1) // Cross component
    }
  }
}
</script>

<style>
.my-product {
  width: 400px;
  padding: 20px;
  border: 2px solid #000;
  border-radius: 5px;
  margin: 10px;
}
</style>

App.vue

<template>
  <div>
    <!-- target: Son to father -->
    <!-- 1. Parent component, @Custom event name="father methods function" -->
    <MyProduct v-for="(obj, ind) in list" :key="obj.id"
    :title="obj.proname"
    :price="obj.proprice"
    :intro="obj.info"
    :index="ind"
    @subprice="fn"
    ></MyProduct>
  </div>
</template>

<script>

import MyProduct from './components/MyProduct_sub'
export default {
  data() {
    return {
      list: [
        {
          id: 1,
          proname: "Super delicious lollipop",
          proprice: 18.8,
          info: "Grand reward for opening, 20% off",
        },
        {
          id: 2,
          proname: "Super delicious big chicken leg",
          proprice: 34.2,
          info: "Delicious but not greasy, Come and buy it",
        },
        {
          id: 3,
          proname: "Super invincible ice cream",
          proprice: 14.2,
          info: "hot summer , Have an ice cream",
        },
      ],
    };
  },
  components: {
    MyProduct
  },
  methods: {
    fn(inde, price){
      // Logic code
      this.list[inde].proprice > 1 && (this.list[inde].proprice = (this.list[inde].proprice - price).toFixed(2))
    }
  }
};
</script>

<style>
</style>

2.4 vue component communication - EventBus

The relationship between the two components is very complex, and it is very troublesome to communicate through parent-child components. At this time, a general component communication scheme: event bus can be used

Core grammar

EventBus/index.js - defines the event bus object

import Vue from 'vue'
// Export blank vue objects
export default new Vue()

List.vue registration event - waiting to receive the value to be haggled - prepare brother page

<template>
  <ul class="my-product">
      <li v-for="(item, index) in arr" :key="index">
          <span>{{ item.proname }}</span>
          <span>{{ item.proprice }}</span>
      </li>
  </ul>
</template>

<script>
export default {
  props: ['arr'],
}
</script>

<style>
.my-product {
  width: 400px;
  padding: 20px;
  border: 2px solid #000;
  border-radius: 5px;
  margin: 10px;
}
</style>

components/MyProduct_sub.vue

<template>
  <div class="my-product">
    <h3>title: {{ title }}</h3>
    <p>Price: {{ price }}element</p>
    <p>{{ intro }}</p>
    <button @click="subFn">Treasure knife-Cut 1 yuan</button>
  </div>
</template>

<script>
import eventBus from '../EventBus'
export default {
  props: ['index', 'title', 'price', 'intro'],
  methods: {
    subFn(){
      this.$emit('subprice', this.index, 1) // Son to father
      eventBus.$emit("send", this.index, 1) // Cross component
    }
  }
}
</script>

<style>
.my-product {
  width: 400px;
  padding: 20px;
  border: 2px solid #000;
  border-radius: 5px;
  margin: 10px;
}
</style>

List.vue code (EventBus receiver)

<template>
  <ul class="my-product">
    <li v-for="(item, index) in arr" :key="index">
      <span>{{ item.proname }}</span>
      <span>{{ item.proprice }}</span>
    </li>
  </ul>
</template>

<script>
// Target: value transfer across components
// 1. Introduce a blank vue object (EventBus)
// 2. Receiver - $on listening event
import eventBus from "../EventBus";
export default {
  props: ["arr"],
  // 3. After the component is created, listen to the send event
  created() {
    eventBus.$on("send", (index, price) => {
      this.arr[index].proprice > 1 &&
        (this.arr[index].proprice = (this.arr[index].proprice - price).toFixed(2));
    });
  },
};
</script>

<style>
.my-product {
  width: 400px;
  padding: 20px;
  border: 2px solid #000;
  border-radius: 5px;
  margin: 10px;
}
</style>

Tags: Javascript Front-end Vue Vue.js

Posted on Sat, 04 Dec 2021 13:53:23 -0500 by brucec