Vue.js 2.0 学习笔记(四)动态组件&插槽&自定义指令

Vue.js 2.0 学习笔记(四)动态组件&插槽&自定义指令

一、动态组件

动态组件指动态切换组件的显示与隐藏

1.1 实现动态组件的渲染

       vue 提供了一个内置的 <component> 组件,专门用来实现动态组件的渲染,可以认为<component> 就是专门用来给组件占位的占位符

代码如下:

<!-- APP.vue -->
data() {
    //1.当前要渲染的组件名称
    return {
        comName: 'Left'
    }
}

<!-- 2.通过 is 属性,动态指定要渲染的组件的名称 -->
<component :is="comName"></component>

<!-- 3.点击按钮,动态切换组件的名称 -->
<button @click="comName = 'Left'">展示 Left</button>
<button @click="comName = 'Right'">展示 Right</button>

重点:

  1. is 属性的值,表示要渲染的组件的名字,是组件在 components 节点下的注册名称
  2. component 标签是 vue 内置的,作用:组件的占位符

       

1.2 keep-alive的使用

       默认情况下,切换动态组件时无法保持组件的状态。此时可以使用 vue 内置的 <keep-alive> 组件保持动态组件的状态:

<!-- APP.vue -->
<keep-alive>
    <component :is="comName"></component>
</keep-alive>

重点:

  1. keep-alive 会把内部的组件进行缓存,而不是销毁组件

       

1.2.1 keep-alive 对应的生命周期函数

当使用了标签keep-alive时:

  • 当组件被缓存时,会自动触发组件的 deactivated 生命周期函数。
  • 当组件被激活时,会自动触发组件的 activated 生命周期函数。
<!-- APP.vue -->
export default {
    
    
    created() {
    
    
        console.log('Left 组件被创建了!');
    },
    destroyed() {
    
    
        console.log('Left 组件被销毁了~~~');
    },
    activated() {
    
    
        console.log('组件被激活了,activated');
    },
    deactivated() {
    
    
        console.log('组件被缓存了,deactivated');
    }
}

重点:

  1. 当组件第一次被创建的时候,既会执行 created 生命周期,也会执行 activated 生命周期,切换展示其他组件时,会执行 deactivated 生命周期
  2. 但是,当组件被激活的时候,只会触发 activated 生命周期,不再触发 created。因为组件没有被重新创建

       

1.2.2 keep-alive的 include 和 exclude 属性

<!-- APP.vue -->
<keep-alive include="Right,Left">
    <component :is="comName"></component>
</keep-alive>
<!-- APP.vue -->
<keep-alive exclude="Right">
    <component :is="comName"></component>
</keep-alive>

重点:

  1. 在使用 keep-alive 的时候,可以通过 include 指定哪些组件需要被缓存
  2. 或者通过 exclude 属性指定哪些组件不需要被缓存;但是:不要同时使用 include 和 exclude 这两个属性

       

1.3 组件注册名称和组件声明时name的区别

<!-- APP.vue -->
export default {
    
    
  components: {
    
    
    // 如果在“声明组件”的时候,没有为组件指定 name 名称,则组件的名称默认就是“注册时候的名称”
    Left, //注册名称
    Right
  }
}
<!-- Left.vue -->
export default {
    
    
  name: 'MyLeft' // 当提供了 name 属性之后,组件的名称,就是 name 属性的值
}

重点:

  1. 组件的 “注册名称” 的主要应用场景是:以标签的形式,把注册好的组件,渲染和使用到页面结构之中
  2. 组件声明时候的 “name” 名称的主要应用场景:结合 <keep-alive> 标签实现组件缓存功能;以及在调试工具中看到组件的 name 名称

       

二、插槽slot

1.1 slot 的概念

       插槽(Slot)是 vue 为组件的封装者提供的能力。允许开发者在封装组件时,把不确定的、希望由用户指定的部分定义为插槽。 让封装的组件更加具有扩展性。可以把插槽认为是组件封装期间,为用户预留的内容的占位符

       

1.2 插槽使用的例子——移动网站中的导航栏

移动开发中几乎每个页面都有导航栏,我们会将导航栏封装成一个插件,如:nav-bar组件,一旦有了这个组件,我们就可以在多个页面中复用了,但是每个页面的导航栏不是一样的,以京东M站为例:

       

1.3 插槽的基本使用

       在封装组件时,可以通过 <slot> 元素定义插槽,从而为用户预留内容占位符。示例代码如下:

<!-- Left.vue -->
<template>
    <h3>Left 组件</h3>
    <!-- 通过slot标签,为用户预留内容占位符-->
    <!-- 若省略了 slot 的 name 属性,有一个默认名称叫做 default -->
    <slot name='default'></slot>
  </div>
</template>
<!-- APP.vue -->
<Left>
    <!--在使用 Left 组件时,为插槽指定具体的内容-->
    <!-- 默认情况下,在使用组件的时候,提供的内容都会被填充到名字为 default 的插槽之中 -->
    <p>这是在 Left 组件的内容区域,声明的 p 标签</p>
</Left>

要点:vue 官方规定:每一个 slot 插槽,都要有一个 name 名称,如果省略了 slot 的 name 属性,则有一个默认名称叫做 default

       

1.3.1 v-slot 指令

作用:若想显式的告诉 vue 要把组件中的内容放到哪个插槽,就可以使用 v-slot:插槽的名字 来完成。

<!-- APP.vue -->
<Left>
    <!--在使用 Left 组件时,为插槽指定具体的内容-->
    <template v-slot='default'>
    <!--或者<template #default>-->
        <p>这是在 Left 组件的内容区域,声明的 p 标签</p>
    </template>
</Left>

要点:

  1. 如果要把内容填充到指定名称的插槽中,需要使用 v-slot: 这个指令,v-slot: 后面要跟上插槽的名字
  2. v-slot: 指令不能直接用在元素身上,必须用在 template 标签上或一个组件上
  3. template 这个标签是一个虚拟的标签只起到包裹性质的作用,不会被渲染为任何实质性的 html 元素
  4. v-slot: 指令的简写形式是 #

       

1.3.2 插槽的后备内容

       如果渲染的组件中没有提供插槽的内容,那么可以在声明插槽时给插槽指定默认显示的内容(后备内容)

<!-- Left.vue -->
<template>
    <h3>Left 组件</h3>
    <!-- 通过slot标签,为用户预留内容占位符-->
    <slot name='default'>这是 default 插槽的默认内容</slot>
  </div>
</template>

       

1.3.3 具名插槽

       如果在封装组件时需要预留多个插槽节点,则需要为每个 <slot> 插槽指定具体的 name 名称。这种带有具体名称的插槽叫做“具名插槽”。在向具名插槽提供内容的时候,我们可以在一个 <template> 元素上使用 v-slot 指令,并以 v-slot 的参数的形式提供其名称。

示例1:

示例2:

<!-- APP.vue -->
<Article>
    <template #title>
        <h3>一首诗</h3>
    </template>

    <template #content>
        <div>
            <p>啊,大海,全是水。</p>
            <p>啊,蜈蚣,全是腿。</p>
            <p>啊,辣椒,净辣嘴。</p>
        </div>
    </template>

    <template #author>
        <div>作者:彬果锅</div>
    </template>
</Article>
<!--Artical.vue-->
<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>

       

1.3.4 作用域插槽

1. 编译作用域

考虑个问题,my-cpn 组件是否可以渲染出来呢?

要点:

  1. 属性是去 vue 实例的模板里面找,而不是去组件 cpn 里面的data找
  2. 父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子子级作用域里编译
  3. 在使用 my-cpn 组件时,整个组件的使用过程相当于在父组件中出现的,即它的作用域就是父组件,使用的也是父组件的属性

       

2. 作用域插槽的基本使用

       在封装组件的过程中,可以为预留的 <slot> 插槽绑定 props 数据(自定义属性),这种带有 props 数据的 <slot> 叫做“作用域插槽”

<!-- Article.vue -->
<template>
  <!-- 文章的内容 -->
  <div class="content-box">
    <!-- 作用域插槽 -->
    <slot name="content" msg="hello vue.js" :user="userinfo"></slot>
  </div>
</template>
<!-- App.vue  -->
<Article>
    <template #title>
        <h3>一首诗</h3>
    </template>

    <template #content="scope">  //scope 是个形参,取什么名字都可以
        <div>
            <p>啊,大海,全是水。</p>
            <p>啊,蜈蚣,全是腿。</p>
            <p>啊,辣椒,净辣嘴。</p>
            <p>{
   
   { scope.msg }}</p>
        </div>
    </template>

    <template #author>
        <div>作者:彬果锅</div>
    </template>
</Article>

       

3. 作用域插槽的解构赋值

<!-- Article.vue -->
<template>
  <!-- 文章的内容 -->
  <div class="content-box">
    <!-- 作用域插槽 -->
    <slot name="content" msg="hello vue.js" :user="userinfo"></slot>
  </div>
</template>

<script>
export default {
      
      
  // 首字母要大写
  name: 'Article',
  data() {
      
      
    return {
      
      
      // 用户的信息对象
      userinfo: {
      
      
        name: 'zs',
        age: 20
      }
    }
  }
}
</script>
<!-- App.vue  -->
<Article>
    <template #title>
        <h3>一首诗</h3>
    </template>

    <template #content="{msg, user}"> //{}作用是结构对象,若只需要解构出msg,可以用{msg}
        <div>
            <p>啊,大海,全是水。</p>
            <p>啊,蜈蚣,全是腿。</p>
            <p>啊,辣椒,净辣嘴。</p>
            <p>{
   
   { msg }}</p>
          	<p>{
   
   { user.name }}</p>
        </div>
    </template>

    <template #author>
        <div>作者:彬果锅</div>
    </template>
</Article>

       

三、自定义指令

3.1 自定义指令的分类

vue 中的自定义指令分为两类,分别是:

  • 私有自定义指令

  • 全局自定义指令

       

3.2 私有自定义指令

在每个 vue 组件中,可以在 directives 节点下声明私有自定义指令。示例代码如下:

<h1 v-color>hhhhh</h1>
<script>
    directives: {
      
      
    color: {
      
      
        // 当指令第一次被绑定到元素上时,会立即触发 bind 函数
        //为绑定到的HTML元素设置红色的文字
        bind(el) {
      
        //固定写法
            // 形参中的 el 表示当前绑定了此指令的、原生DOM对象
            el.style.color = 'red';
        }
    }
}
</script>

要点:

  1. directives 节点下声明私有自定义指令
  2. 属性定义时名字前不用加 v
  3. 使用自定义属性时前面要加 v ,即 v + 自定义属性名

       

3.3 为自定义指令动态绑定参数值

       在 template 结构中使用自定义指令时,可以通过等号(=)的方式,为当前指令动态绑定参数值:

       

3.4 使用binding.value 获取指令绑定的值

       在声明自定义指令时,可以通过形参中的第二个参数,来接收指令的参数值:

<!--App.vue-->
<template>
    <!-- color 是一个变量 -->
    <h1 v-color="color">App 根组件</h1>  
    <!-- red加了单引号,是一个字面量值 -->
    <p v-color="'red'">测试</p> 
</template>

<script>
export default {
      
      
  data() {
      
      
    return {
      
      
      color: 'blue'
    }
  },
  directives: {
      
      
    // 当指令第一次被绑定到元素上的时候,会立即触发 bind 函数
    color: {
      
      
        // 通过 binding 对象的 .value 属性,获取动态的参数值 
        bind(el, binding) {
      
        
        	el.style.color = binding.value;
   	    }
    }
  }
}
</script>

       

3.5 update 函数

       bind 函数只调用 1 次:当指令第一次绑定到元素时调用,当 DOM 更新时 bind 函数不会被触发。 update 函数会在每次 DOM 更新时被调用。示例代码如下:

directives: {
    
    
    // 当指令第一次被绑定到元素上的时候,会立即触发 bind 函数
    color: {
    
    
        // 通过 binding 对象的 .value 属性,获取动态的参数值 
        bind(el, binding) {
    
      
        	el.style.color = binding.value;
   	    }, 
        // 每次 DOM 更新时被调用
        update(el, binding) {
    
    
            el.style.color = binding.value;
        }
    }
}

       

3.6 bind 和 update 函数的简写形式

       如果 bind 和 update 函数中的逻辑完全相同,则对象格式的自定义指令可以简写成函数格式

directives: {
    
    
    color(el, binding) {
    
    
        el.style.color = binding.value;
    }
}

       

3.7 全局自定义指令

       全局共享的自定义指令需要通过 “ Vue.directive() ” 进行声明,示例代码如下:

//main.js
// 参数1:字符串,表示全局自定义指令的名字
// 参数2:对象,用来接收指令的参数值
Vue.directive('color', function(el, binding) {
    
    
    el.style.color = binding.value;
})

注意:全局声明的自定义指令和过滤器等命令都要放在main.js中

猜你喜欢

转载自blog.csdn.net/weixin_45950819/article/details/121160750
今日推荐