Vue public component encapsulation and value passing

Three elements of Vue components

1. props parameter
2. slot custom slot
3. event custom event


Basic component development

Create a .vue file that contains template, script and style:

<template>
  <div class="headComponent">
    {
   
   { msg }}
  </div>
</template>

<script>
export default {
    props:['data','type'],
    inheritAttrs: false,
    data(){
        return{
            msg:'',
        }
    }
}
</script>
<style scoped>

</style>


So far, a basic component has been completed. To use this component, it needs to be introduced and registered in other js files:

import Head from '../components/headComponent.vue'

 

 

How to encapsulate a common component?

  1. First create a new Components folder in the src directory.
  2. The newly created component to be packaged is called a subfolder
  3. Create a new index.vue file under the subfolder to store the public components to be encapsulated
  4. Finally, create a new index.js file under the Components folder
  5. And register public components to the global
import pageTools from './pageTools/index'
 
export default {
  install(Vue) {
    Vue.component('pageTools', pageTools)
   
  }
}


In this way, common components can be used in other components without importing components

< pageTools></ pageTools>



 


Data transfer between components

 * Parent-child component communication

  Subassembly:

d0a5deb8b1cc155920e0a3a197ef25f8.png

     

    parent component:

09102a4abc7e6fc38a1568c1e1977200.png

 

 

 

1. The parent component passes data to the child component

Parent components pass data to child components in the form of attributes, and child components receive data using props. However, the application scenarios of common components are more complicated. Some validation rules should be added to the parameters passed by props, namely:

props: {
    propA: Number,  // 基础类型检测 (`null` 意思是任何类型都可以)
    propB: [String, Number],   // 多种类型
    propC: {  // 必传且是字符串
      type: String,
      required: true
    },
    propD: {   // 数字,有默认值
      type: Number,
      default: 100
    },
    propE: {   // 数组/对象的默认值应当由一个工厂函数返回
      type: Object,
      default: function () {
        return { message: 'hello' }
      }
    },
    propF: {   // 自定义验证函数
      validator: function (value) {
        return value > 10
      }
    }
  }

 


Due to the problem of a single-item data flow, the data passed from the parent component to the child component should not be modified directly, because the data in the parent component will also be modified, and problems will arise when this data is also passed to other components. Vue2.5 has been optimized for props, and this problem no longer exists. If you must have such an operation, you can write it like this:

let copyData = JSON.parse(JSON.stringify(this.data))

Why not just write let myData = this.data? Because of direct assignment, it is only a shallow copy for objects and arrays, pointing to the same memory address, and changing one of them will also change the other. However, after the reverse conversion of JSON, the deep copy is realized, which can not affect each other.

 

 

2. The child component passes data to the parent component

The child component passes data to the parent component: trigger the parent component method, and pass the parameter data to the parent component

handleSubmit(data){
    this.$emit('submitToParent', data)
}



How does the parent component get the data passed by the child component?

<header @submitToParent="parentSubmit"></header>

methods: {
    parentSubmit(data){
        // 父组件的业务逻辑
    }
}

 

3. The child component changes the data of the parent component

When we pass the data of the parent element to the child component, we need to pass a non-basic type, that is, pass the object or array, and the child component manipulates the data by accessing the properties in the object. Because objects and arrays are passed by reference, they are modified in the child component , the parent component will also change synchronously, as follows:

// 父组件要props传递给子组件的数据
data:{
    info:'父组件信息'
}
 
// 子组件
 <template id="tpl">
    <div>
        <button @click="change">change</button>
        <p>{
   
   {data.info}}</p>
    </div>
</template>
... 省略部分无关代码 ...
props:['data'],
methods:{
    change(){
        this.data.info = 'change info'
    }
}

When the child component clicks the change button to change the data, the parent component will also change synchronously



4. Use slots

A general-purpose component is often not suitable for all application scenarios, so only 80% of the function of the component needs to be completed when encapsulating the component, and the remaining 20% ​​is solved by the parent component through solt. For example: there are two buttons in a public component, one is "Add" and the other is "Delete", but when using this component in another scene, the two buttons need to do different things, such as "View" and "Modify". Therefore, when we encapsulate the component, we should not directly write the button, but place a slot in a suitable position, which is actually a placeholder. Reserve a position for the button setting in advance, and then write it in the parent component button.

 

Subassembly:

<div class="child-btn">
    <!-- 具名插槽 -->
    <slot name="button"></slot>
    <!-- 匿名插槽(每个组件只能有一个) -->
    <slot><slot>
</div>


parent component:

<child>
    <!-- 对应子组件中button的插槽 -->
    <button slot="button">slot按钮</button>
</child>

When developing common components, as long as they are not highly independent components, it is best to add a slot. Moreover, during the development process, it is often necessary to add new content in the subcomponent. At this time, one or more sockets can be left inside the subcomponent, and then add content when calling this subcomponent, and the added content will be distributed to the corresponding In the slot:

Subassembly:

<template>
  <div class="headComponent">
    <h3>这是一个头部组件</h3>
    <slot></slot>
    <slot name="s1"></slot>
    <slot name="s2"></slot>
  </div>
</template>

parent component:

<head-component>
    <h2>不具名插槽</h2>
    <h2 slot="s1">这里对应的是s1插口</h2>
    <h2 slot="s2">这里对应的是s2插口</h2>
</head-component>



The slot can also be used as a scope to define variables in the child component, and then customize the rendering method in the parent component: (it is used more in the project, the data obtained by ajax in vue+elementUI is displayed in the table, and many times every A piece of data is not displayed directly, some additional processing is required)

Subassembly:

<template>
  <div class="headComponent">
    <h3>这是一个头部组件</h3>
    <slot name="head" v-for="head in heads" :text="head.text"></slot>
  </div>
</template>

parent component:

<head-component>
    <template slot="head" scope="props">
        <li> {
   
   { props.text }} </li>
    </template>
</head-component>

In the above example, first add a slot in the child component, and define the array variable heads in the child component, and then add content in the parent component with the scope template, where scope is an inherent property, and its value corresponds to a temporary variable props, and props will be Receive the parameter heads passed from the parent component to the child component

**************************************************************************************

How to use slots:

What are slots?

  1. Slot (Slot) is a concept proposed by Vue. Just like the name, the slot is used to decide to insert the carried content into a specified position, so that the template is divided into blocks, with modular characteristics and larger of reusability.
  2. Whether the slot is displayed or not and how to display it is controlled by the parent component, and where the slot is displayed is controlled by the child component
  3. The parent component has a structure, and the child component uses a slot to occupy the place
  4. Scope slot is a way of passing parameters from child to parent, which solves the problem that ordinary slots cannot access child data in the parent;

How to use slots?

default slot

parent component

<template>
  <div>
    我是父组件
    <slotOne1>
      <p style="color:red">我是父组件插槽内容</p>
    </slotOne1>
  </div>
</template>

 

Write the content you want to display in the child component referenced by the parent component (labels can be used or not)

Subcomponent (slotOne1)

<template>
  <div class="slotOne1">
    <div>我是slotOne1组件</div>
    <slot></slot>
  </div>
</template>

Write the slot in the child component, where the slot is located is the content to be displayed by the parent component

157191a183b117bf5f57ed00c76669ea.png

  • Of course, other components can also be written in the child component referenced by the parent component

parent component

<template>
  <div>
    我是父组件
    <slotOne1>
      <p style="color:red">我是父组件插槽内容</p>
      <slot-one2></slot-one2>
    </slotOne1>
  </div>
</template>

 

Subcomponent (slotOne2)

<template>
  <div class="slotOne2">
    我是slotOne2组件
  </div>
</template>

ad03e75b766a552dd75059aca0ffe502.png

named slot

Subassembly

<template>
  <div class="slottwo">
    <div>slottwo</div>
    <slot name="header"></slot>
    <slot></slot>
    <slot name="footer"></slot>
  </div>
</template>

Three slot tags are defined in the subcomponent, two of which are added with the name attribute header and footer respectively

parent component

<template> 
  <div> 
    I am the parent component 
    <slot-two> 
      <p>La la la, la la la, I am a little expert in selling newspapers</p> <template slot="header"> 
          <p>I am The slot whose name is header</p> 
      </template> 
      <p slot="footer">I am the slot whose name is footer</p> 
    </slot-two> 
  </div> 
</template>
     

Use the template in the parent component and write the corresponding slot value to specify the actual position of the content in the child component (of course, you don’t have to write it into the template). Other content without corresponding values ​​will be placed in the child component without adding name In the slot of the attribute

4019642f15f5b1b33a1b1da75abc439b.png

The default content of the slot

parent component

<template>
  <div>
    我是父组件
    <slot-two></slot-two>
  </div>
</template>

Subassembly

<template>
  <div class="slottwo">
    <slot>我不是卖报的小行家</slot>
  </div>
</template>

 

You can write content in the slot tag of the child component. When the parent component does not write content, it will display the default content of the child component. When the parent component writes content, it will replace the default content of the child component.

db95bb91116564862420cdb8f393ae5d.png

compile scope

 

parent component

<template>
  <div>
    我是父组件
    <slot-two>
      <p>{
   
   {name}}</p>
    </slot-two>
  </div>
</template>
<script>
export default {
  data () {
    return {
      name: 'Jack'
    }
  }
}
</script>

Subassembly

<template>
  <div class="slottwo">
    <slot></slot>
  </div>
</template>

85b54c89ce5b0befda0100eb33e09d00.png

Scoped slots

  • Scope slot is a way of passing parameters from child to parent, which solves the problem that ordinary slots cannot access child data in the parent;

Subassembly

<template> 
  <div> 
    I am a subcomponent of scoped slots 
    <slot :data="user" ></slot> 
  </div> 
</template> 

<script> 
export default { 
  name: 'slotthree', 
  data ( ) { 
    return { 
      user: [ 
        {name: 'Jack', sex: 'boy'}, 
        {name: 'Jone', sex: 'girl'}, 
        {name: 'Tom', sex: 'boy'} 
      ] 
    } 
  } 
} 
</script>

Bind the required value on the slot label of the child component

 

 

parent component

<template>
  <div>
    我是作用域插槽
    <slot-three>
      <template slot-scope="user">
        <div v-for="(item, index) in user.data" :key="index">
        {
  
  {item}}
        </div>
      </template>
    </slot-three>
  </div>
</template>

 

Use the slot-scope attribute on the parent component, user.data is the value passed from the child component

7bf5cebe56c1d14351e6653cdc5e8a67.png

Comprehensive, use props attribute to pass value, scope slot

parent component:

<template>
    <div>
        <p>vue 高级特性</p>
        <hr>

        <ScopedSlotDemo :url="website.url">
            <template slot-scope="slotProps">
                {
  
  {
  slotProps.slotData.title}}
            </template>
        </ScopedSlotDemo>
    </div>
</template>
<script>
import ScopedSlotDemo from './ScopedSlotDemo'
export default {
    data() {
        return {
            name:'小米',
             website: {
                url: 'http://imooc.com/',
            },
                subTitle: 'Programmer's DreamWorks'
  


                title: 'imooc', 
        }; 
    }, 
    components:{ 
        
        ScopedSlotDemo 
    } 

}; 
</script> 

<style scoped lang="css"> 

</style>

 

Subassembly

<template> 
    <a :href="url"> 
        <slot :slotData="website1" > 
            { 
  
  {website1.subTitle}} <!-- The default value displays subTitle, that is, when the parent component does not pass content --> 
        </slot > 
    </a> 
</template> 

<script> 
export default {    props: ['url'], 
    data() { 
        return { website1: { 
                url: 'http://wangEditor.com/', 
                title: 'wangEditor' , 
                subTitle: 'Lightweight Rich Text Editor' 
            } 
        } 
    } 
} 
</script>
 
            


 

 

 


 

 

Guess you like

Origin blog.csdn.net/admin12345671/article/details/127840095