Knowledge about dynamic components, slots, and custom instructions of Vue2

1. Dynamic components

1 Introduction

Dynamic components refer to dynamically switching the display and hiding of components.

2. Realize the rendering of dynamic components

Vue provides a built-in component designed to render dynamic components.

3. Dynamic rendering related code

3.1 APP.vue

<template>
  <div id="app">
    <h1>App组件</h1>
    <hr />
    
    <button @click="comName = 'Left'">展示Left</button>
    <button @click="comName = 'Right'">展示Right</button>
    <div class="box">
      <!--渲染Left组件和Right组件-->
      <!--1. component 标签是vue内置的,作用:组件的占位符-->
      <!--2. is属性的值,表示要渲染的组件的名字-->
      <component :is="comName"></component>
    </div>
  </div>
</template>

<script>
import Left from "@/components/Left.vue";
import Right from "@/components/Right.vue";

export default {
  data() {
    return {
      // comName表示要展示的组件的名字
      comName: "Left",
    };
  },
  components: {
    Left,
    Right,
  },
};
</script>

<style lang="less">
</style>

3.2 Left.vue

<template>
  <div class="left-container">
    <h1>Left组件---{
   
   { count }}</h1>
  </div>
</template>

<script>
export default {
  data() {
    return {
      count: 0,
    };
  },
  created() {
    console.log("Left组件被创建了!");
  },
  destroyed() {
    console.log("Left组件被销毁了");
  },

  // 当组件第一次被创建的时候,既会执行created生命周期,也会执行activated生命周期
  // 但是当组件被激活的时候,只会触发activated生命周期,不再触发created。因为组件没有被重新创建。
  activated() {
    console.log("组件被激活了,activated");
  },
  deactivated() {
    console.log("组件被缓存了,deactivated");
  },
};
</script>

<style lang="less" scoped>
.left-container {
  width: 100%;
  min-height: 250px;
  background-color: orange;
  text-align: center;
}
</style>

3.3 Right.vue

<template>
    <div class="right-container">
        <h1>Right组件---{
   
   {  }}</h1>
    </div>
</template>

<script>
export default {

}
</script>

<style lang="less" scoped>
.right-container{
    width: 100%;
    min-height: 250px;
    background-color: rgb(0, 162, 255);
    text-align: center;
}
</style>

4, keep-alive maintain state

4.1 Introduction

Vue can use keep-alive to keep the state when the component is switched, that is, when the switch is switched, the component will not be destroyed, but will be in an inactive state and keep the original state until it is reactivated.

4.2 Lifecycle functions

When the component is cached, the component's deactivated lifecycle function is automatically triggered.
When the component is activated, the activated lifecycle function of the component is automatically triggered

4.3 Related codes

4.3.1 Templates

<!-- keep-alive可以把内部的组件进行缓存,而不是销毁组件-->
<keep-alive>
   <component :is="comName"></component>
</keep-alive>

4.3.2 APP.view

<template>
  <div id="app">
    <h1>App组件</h1>
    <hr />
    
    <button @click="comName = 'Left'">展示Left</button>
    <button @click="comName = 'Right'">展示Right</button>
    <div class="box">
      <!--渲染Left组件和Right组件-->
      <!--1. component 标签是vue内置的,作用:组件的占位符-->
      <!--2. is属性的值,表示要渲染的组件的名字-->
      <!--3. is属性的值,应该是组件在components节点下的注册名称-->

      <!-- keep-alive可以把内部的组件进行缓存,而不是销毁组件-->
      <keep-alive>
        <component :is="comName"></component>
      </keep-alive>
    </div>
  </div>
</template>

<script>
import Left from "@/components/Left.vue";
import Right from "@/components/Right.vue";

export default {
  data() {
    return {
      // comName表示要展示的组件的名字
      comName: "Left",
    };
  },
  components: {
    Left,
    Right,
  },
};
</script>

<style lang="less">
</style>

4.4 include attribute and exclude attribute

(1) The include attribute is used to specify: only components with matching names will be cached. Multiple component names are separated by English commas.
(2) The exclude attribute is used to exclude: specify which components do not need to be cached through the exclude attribute.
Note: It is not necessary to use the two attributes include and exclude at the same time

<keep-alive include="Left,Right">
    <component :is="comName"></component>
</keep-alive>

5. When registering names and component declarations, the usage of name

5.1 Introduction

When the name attribute is provided, the name of the component is the value of the name attribute.
(1) The main application scenario of the "registered name" of the component is to render and use the registered component in the page structure in the form of a label.
(2) The main application scenario of the "name" name when the component is declared: combining the label to realize the caching function of the component; and seeing the name of the component in the debugging tool.

5.2 Related codes

5.2.1 Right.vue

<template>
  <div class="right-container">
    <h1>Right组件---{
   
   {}}</h1>
  </div>
</template>

<script>
export default {
  // 当提供了name属性之后,组件的名称,就是name属性的值
  // 对比:
  // 1.组件的“注册1名称”的主要应用场景是:以标签的形式,把注册好的组件,渲染和使用到页面结构中。
  // 2.组件声明时候的“name”名称的主要应用场景:结合<keep-alive>标签实现组件的缓存功能;以及在调试工具中看到组件的name名称。
  name: "MyRight",
};
</script>

<style lang="less" scoped>
.right-container {
  width: 100%;
  min-height: 250px;
  background-color: rgb(0, 162, 255);
  text-align: center;
}
</style>

2. Slot

1 Introduction

Slot (Slot) is the ability provided by vue to the wrapper of the component. Allows developers to define undefined parts that are expected to be specified by users as slots when packaging components.

2. v-slot (abbreviated as: #)

By default, when using the component, the provided content will be filled into the slot named default.
If you want to fill the content into the slot with the specified name, you need to use the v-slot: command.
v-slot should be followed by the name of the slot. At the same time, the v-slot directive cannot be used directly on the element, but must be used on the template tag. The template tag is a virtual tag that only serves as a wrapper, but will not be rendered as any substantial html element.
The abbreviation for the v-slot directive is#

3. Relevant basic code

3.1 App view

<template>
  <div id="app">
    <h1>App组件</h1>
    <hr />

    <div class="box">
      <Left>
        <!--默认情况下,在使用组件的时候,提供的内容都会被填充到名字为default的插槽之中-->
        <!--1.如果要把内容填充到指定名称的插槽中,需要使用v-slot:这个指令-->
        <!--2.v-slot:后面要跟上插槽的名字-->
        <!--3.v-slot:指令不能直接用在元素身上,必须用在template标签上-->
        <!--4.template这个标签,它是一个虚拟的标签,只起到包裹性质的作用,但是不会渲染为任何实质性的html元素-->
        <!--5.v-slot指令的简写形式是 #-->
        <template v-slot:default>
          <p>这是在Left组件的内容区域,声明的p标签</p>
        </template>
      </Left>
    </div>
  </div>
</template>

<script>
import Left from "@/components/Left.vue";
import Right from "@/components/Right.vue";

export default {
  components: {
    // 如果在"声明组件"的时候,没有为组件指定name名称,则组件的名称默认就是“注册时候的名称”
    Left,
    Right,
  },
};
</script>

<style lang="less">
</style>

3.2 Left.vue

<template>
  <div class="left-container">
    <h1>Left组件</h1>
    <hr/>
    <!--声明一个插槽区域-->
    <!--vue官方规定:每一个slot插槽,都要有一个name名称-->
    <!--如果省略了slot的name属性。则有一个默认名称叫做default-->
    <slot name="default"></slot>
  </div>
</template>

<script>
export default {}
</script>

<style lang="less" scoped>
.left-container {
  width: 100%;
  min-height: 250px;
  background-color: orange;
  text-align: center;
}
</style>

4. Named slots

4.1 Introduction

A slot has a specific name, and if there are multiple slots, a specific name must be given to each slot.

4.2 Related codes

4.2.1 APP.view

<template>
  <div id="app">
    <h1>App组件</h1>
    <hr />
    
    <Article>
      <template v-slot:title>
        <h3>一首诗</h3>
      </template>

      <template #content>
        <div>
          <p>内容区域</p>
        </div>
      </template>

      <template #author>
        <div>
          <p>作者</p>
        </div>
      </template>
    </Article>
    <hr/>
  </div>
</template>

<script>
import Article from "@/components/Article.vue";

export default {
  components: {
    // 如果在"声明组件"的时候,没有为组件指定name名称,则组件的名称默认就是“注册时候的名称
    Article
  },
};
</script>

<style lang="less">
</style>

4.2.2 Article.view

<template>
  <div class="article-container"> 
    <!--文章的标题-->
    <div class="header-box">
        <slot name="title"></slot>
    </div>

    <!--文章的内容-->
    <div class="content-box">
        <slot name="content"></slot>
    </div>

    <!--文章的作者-->
    <div class="footer-box">
        <slot name="author"></slot>
    </div>

  </div>
</template>

<script>
export default {
  // 首字母大写
  name: 'Article'
}
</script>

<style lang="less" scoped>
.article-container{
    > div{
        min-height: 150px;
    }
    .header-box{
        background-color:pink;
    }
    .content-box{
        background-color:lightblue;
    } 
    .footer-box{
        background-color:lightsalmon;
    }
}
</style>

5. Scope slots

5.1 Introduction

When encapsulating a component, provide the value corresponding to the reserved property. This usage is called "scope slot". (scope)

<template #content="scope">
        <div>
          <p>内容区域</p>
          <p>{
   
   { scope.msg }}</p>
        </div>
</template>

5.2 Related codes

5.2.1 APP.view

<template>
  <div id="app">
    <h1>App组件</h1>
    <hr />
    
    <Article>
      <template #content="scope">
        <div>
          <p>内容区域</p>
          <p>{
   
   { scope.msg }}</p>
        </div>
      </template>
    </Article>
    <hr/>
  </div>
</template>

<script>
import Article from "@/components/Article.vue";

export default {
  components: {
    Article
  },
};
</script>

<style lang="less">
</style>

5.2.2 Article.view

<template>
  <div class="article-container"> 
    <div class="content-box">
        <!--在封装组件时,为预留的<slot>提供属性对应的值,这种用法,叫做“作用域插槽”-->
        <slot name="content" msg="hello world"></slot>
    </div>
  </div>
</template>

<script>
export default {
  // 首字母大写
  name: 'Article'
}
</script>

<style lang="less" scoped>
.article-container{
    > div{
        min-height: 150px;
    }
    .content-box{
        background-color:lightblue;
    } 
}
</style>

5.3 Destructuring assignment of scoped slots

5.3.1 Introduction

property values ​​can be dynamically bound

5.3.2 Related code (APP.vue)

<template>
  <div id="app">
    <h1>App组件</h1>
    <hr />
    
    <Article>
      <template #content="scope">
        <div>
          <p>内容区域</p>
          <p>{
   
   { scope.msg }}</p>
          <p>{
   
   { scope.user.name }}</p>
          <p>{
   
   { scope.user.age }}</p>
        </div>
      </template>
    </Article>
    <hr/>
  </div>
</template>

<script>
import Article from "@/components/Article.vue";

export default {
  components: {
    Article
  },
};
</script>

<style lang="less">
</style>

5.3.3 Article.view

<template>
  <div class="article-container"> 
    <div class="content-box">
        <!--在封装组件时,为预留的<slot>提供属性对应的值,这种用法,叫做“作用域插槽”-->
        <slot name="content" msg="hello world" :user="userinfo"></slot>
    </div>
  </div>
</template>

<script>
export default {
  // 首字母大写
  name: 'Article',
  data(){
    return {
        // 用户信息对象
        userinfo:{
            name:'zs',
            age:18
        }
    }
  }
}
</script>

<style lang="less" scoped>
.article-container{
    > div{
        min-height: 150px;
    }
    .content-box{
        background-color:lightblue;
    } 
}
</style>

3. Custom commands

1 Introduction

Vue officially provides common instructions such as v-text, v-for, v-model, v-if. In addition, vue also allows developers to customize instructions.

2. Custom commands

2.1 Private Custom Instructions

In each vue component, private custom directives can be declared under the directives node.

2.1.1 Basic usage of private custom instructions

<template>
  <div id="app">
    <h1 v-color>App组件</h1>
    <p v-color>测试</p>
    <hr />
  </div>
</template>

<script>
export default {
  components: {
  },
  directives: {
    // 定义名为color的指令,指向一个配置对象
    color: {
      // 当指令第一次被绑定到元素上的时候,会立即触发bind函数
      // 形参中的el表示当前指令所绑定到的那个DOM对象
      bind(el) {
        console.log("触发了v-color的bind函数")
        el.style.color = 'red'
      },
    },
  },
};
</script>

<style lang="less">
</style>

result
insert image description here

2.1.2 Use binding.value to get the value bound by the instruction

When a directive is bound to an element for the first time, the bind function is triggered immediately

<template>
  <div id="app">
    <h1 v-color = "color">App组件</h1>
    <p v-color = "'green'">测试</p>
    <hr />
  </div>
</template>

<script>

export default {
  data(){
    return {
      color:'blue'
    }
  },
  components: {
  },
  directives: {
    // 定义名为color的指令,指向一个配置对象
    color: {
      // 当指令第一次被绑定到元素上的时候,会立即触发bind函数
      // 形参中的el表示当前指令所绑定到的那个DOM对象
      bind(el,binding) {
        console.log("触发了v-color的bind函数")
        el.style.color = binding.value
      },
    },
  },
};
</script>

<style lang="less">
</style>

result
insert image description here

2.1.3 Using the update function to call elements

The update function will be called every time the DOM is updated

<template>
  <div id="app">
    <h1 v-color = "color">App组件</h1>
    <p v-color = "'green'">测试</p>
    <button @click="color='green'">改变color的颜色值</button>
    <hr />
  </div>
</template>

<script>
export default {
  data(){
    return {
      color:'blue'
    }
  },
  components: {
  },
  directives: {
    // 定义名为color的指令,指向一个配置对象
    color: {
      // 在DOM更新的时候,会触发update函数
      update(el, binding){
        console.log("触发了v-color的update函数")
        el.style.color = binding.value
      }
    },
  },
};
</script>

<style lang="less">
</style>

result
insert image description here

2.1.4 Function shorthand

<template>
  <div id="app">
    <h1 v-color = "color">App组件</h1>
    <p v-color = "'green'">测试</p>
    <button @click="color='green'">改变color的颜色值</button>
    <hr/>
  </div>
</template>

<script>
export default {
  data(){
    return {
      color:'blue'
    }
  },
  components: {
  },
  directives: {
    // 定义名为color的指令,指向一个配置对象
    color(el, binding){
      el.style.color = binding.value
    }
  },
};
</script>

<style lang="less">
</style>

2.2 Global Custom Instructions

Globally shared custom directives need to be declared via "Vue.directive()"

import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

Vue.directive('color',function(el, binding){
    
    
  el.style.color = binding.value
})

new Vue({
    
    
  render: h => h(App),
}).$mount('#app')

Guess you like

Origin blog.csdn.net/qq_46106857/article/details/129932803