vue_之组件进阶

121 阅读5分钟

1、组件进阶之props

  • props的校验

    • 普通格式:props['propA','propB'],没有数据类型的检测,不易发现错误
    • props:{
          // 基础的类型检测(`null` 和 `undefined`会通过任何类型的验证 )
          propA:Number,
          // 多个可能的类型
          propB:[String,Number],
          //必填的字符串
          propC:{
              type:String,
               props: {
          // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
          propA: Number,
          // 多个可能的类型
          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 ['success', 'warning', 'danger'].indexOf(value) !== -1
            }
          }
        }// 必须要填的
                  required:true          
              }
      }
      

2、组件进阶-动态组件

多个组件使用同一个挂载点,并可以动态切换,这个就是动态组件

格式

<component :is="comName"></component>

注意点:

  • is只能是动态属性 => :is="组件注册后的标签名字符串或打他变量"
  • 不能直接拿组件名赋值使用
  • vue内置的component组件,配合js属性,设置要显示的组件标签名字

3、组件进阶-keep-alive组件

  1. 背景:

    • 组件切换会导致组件被频繁销毁和重新创建,大多数情况下是有自己的意义的,但也可能会导致不必要的性能损耗。
    • 可以先给UserName.vue和UserInfo.vue注册created和destoryed生命周期,观察创建和销毁过程
  2. keep-alive

    • 使用Vue内置的keep-alive组件,可以让包裹的组件保存在内存中不被销毁
  3. 格式

    • 使用keep-alive内置的Vue组件,让动态组件缓存而不是销毁

    • 补充生命周期: 当使用keep-alive组件时,会自动补充以下两个钩子

      • activated-激活
      • deactivated-失去激活状态
<keep-alive>
    <!-- vue内置的组件component, 可以动态显示组件 -->
    <component :is="comName"></component>
</keep-alive>

总结:

keep-alive可以提高组件的性能,内部包裹的标签不会被销毁和重新创建,触发激活和非激活的生命周期方法

4、组件进阶-keep-alive组件-指定缓存

语法:

  • include="组件名1,组件名2..."
  • :include=['组件名1','组件名2']
<keep-alive include="name1,name2">
    <!-- vue内置的组件component, 可以动态显示组件 -->
    <component :is="comName"></component>
</keep-alive>

注意点:

匹配首页检查组件自身的name选项,如果name选项不可用,则匹配它的局部注册名称(父组件components选项的键值)

5、组件进阶-默认插槽

vue中的插槽

  • 组件通过插槽传入自定义结构
  • 用于实现组件的内容分发,通过slot标签,可以接收到写在组件标签内的内容
  • vue提供组件插槽能力,允许开发者在封装组件时,把步确定的部分定义为插槽

格式:

在定义组件时,在template中用slot来占坑

使用时,讲组件之间的内容来填坑

6、组件进阶-具名插槽

当一个组件内有2处上需要外部传入标签的地方

格式

定义:

使用:

  • <template #xxx>;
  • 传入的标签可以分别派发给不同的slot位置
  • v-slot一般跟template标签使用(template是html5新出标签内容模板元素,不会渲染到页面上,一般被vue解析为内容标签)

示例:

<div class="container" v-show="isShow">
    <slot name="one"></slot>
    <slot name="two"></slot>
</div>

简写:

==v-slot可以简化成#使用==

v-bind可以省略成:

v-on: 可以省略成@

v-slot: 可以简化成#

写法1:

<Pannel2>
    <template v-slot:one>
        <img src="../assets/mm.gif" alt="" />
    </template>
    <template v-slot:two>
        <span>我是文字哦</span>
    </template>
</Pannel2>

写法2:

<Pannel2>
    <!-- 简化写法 -->
    <template #one>
        <div>
            <p>寒雨连江夜入吴,</p>
            <p>平明送客楚山孤。</p>
            <p>洛阳亲友如相问,</p>
            <p>一片冰心在玉壶。</p>
        </div>
    </template>
    <template #two>
        <img src="../assets/mm.gif" alt="" />
    </template>
</Pannel2>

小结:

  • slot有可以设置多个
  • 定义组件时,slot的name属性起插槽名
  • 使用组件时,template配合#插槽名传入具体html标签或组件

7、组件进阶-作用域插槽(难点)

详细步骤:

  • 创建子组件,准备slot,在slot上绑定属性和子组件值
  • 使用子组件,传入自定义标签,用template和v-slot="自定义变量名"
  • 自定义变量名会自动绑定slot上所有属性,就可以使用子组件内值,并替换slot位置

示例

具名插槽,给slot绑定属性和值

1.子组件

<template>
  <div style="border:1px solid #ccc; margin:5px;padding:5px">
    <h2>子组件</h2>
    <!-- 给slot上补充自定义的属性 -->
    <slot name="content" :a="1" :b="2">
      默认内容
    </slot>
  </div>
</template><script>
export default {
}
</script>

2.父组件

<template>
  <div style="border:1px solid #ccc; margin:5px;padding:5px">
    <h1>45-插槽-作用域插槽</h1>
​
​
    <MyCom>
      <!-- 
        v-slot:插槽名="对象" 
      对象会自动接收这个插槽传递回来自定义属性
      -->
      <template v-slot:content="scope">
        <!-- <h1>自定义的内容,填坑, {{scope}}</h1> -->
        <h3>{{scope.a}}</h3>
        <p>{{scope.b}}</p>
      </template>
    </MyCom>
  </div>
</template><script>// 父传子
//  1.传数据。 自定义属性    (父)  props(子)
//  2.传结构。 在组件中写内容(父)  slot (子)import MyCom from './MyCom.vue'
export default {
  components: { MyCom }
}
</script><style scoped>
.content{
background-color: #ccc;
}
</style>

小结

组件内变量绑定在slot上,然后使用组件v-slot:插槽名字="变量",变量上就会绑定slot传递的属性和值

8、组件进阶-作用域插槽使用场景

封装一个表格组件,在表格组件内循环产生单元格

[
          {
            name: "小传同学",
            age: 18,
            headImgUrl:
            "https://www.escook.cn/vuebase/pics/1.png",
          },
          {
            name: "小黑同学",
            age: 25,
            headImgUrl:
            "https://www.escook.cn/vuebase/pics/2.png",
          },
          {
            name: "智慧同学",
            age: 21,
            headImgUrl:
            "https://www.escook.cn/vuebase/pics/3.png",
          }
]

1.封装MyTable.vue

<template>
  <table>
    <tr>
      <th>序号</th>
      <th>名字</th>
      <th>年龄</th>
      <th>头像</th>
    </tr>
    <tr v-for="(item,idx) in list" :key="idx">
      <td>{{idx+1}}</td>
      <td>{{item.name}}</td>
      <td>{{item.age}}</td>
      <td>
        <!-- slot name具名插槽 
        slot有自定义的属性,向slot传递数据,这个数据在父组件使用插槽时,能自动接收
        -->
        <slot name="img" :girl="item" :loveName="item.name" :img="item.headImgUrl">
          <!-- 默认内容 -->
          <img :src="item.headImgUrl"/>
        </slot>
      </td>
    </tr>
  </table>
</template><script>
export default {
  props: {
    list: {
      type: Array,
      required: true
    }
  }
}
</script>

2.UserTable -准备数据,传入给MyTable.vue组件里循环使用

<template>
  <div style="border:1px solid #ccc; margin:5px;padding:5px">
    <h1>46-插槽-作用域插槽-场景</h1>
    <MyTable :list="list">
      <!-- scope是一个变量名,自动接收slot上的自定义属性 -->
      <template v-slot:img="scope">
        <img style="display:block;border-radius:50%" :src="scope.img" />
        <button @click="like(scope)">点赞</button>
        <button>加好友</button>
      </template>
    </MyTable>
  </div>
</template><script>import MyTable from './MyTable.vue'
export default {
  data(){
    return {
      list: [
          {
            name: "小明同学",
            age: 18,
            headImgUrl:
            "https://www.escook.cn/vuebase/pics/1.png",
          },
          {
            name: "小王同学",
            age: 25,
            headImgUrl:
            "https://www.escook.cn/vuebase/pics/2.png",
          },
          {
            name: "小美同学",
            age: 21,
            headImgUrl:
            "https://www.escook.cn/vuebase/pics/3.png",
          }
        ]
    }
  },
  methods: {
    like(obj){
      console.log(obj)
    }
  },
  components: { MyTable }
}
</script>

总结: 插槽可以自定义显示内容,作用域插槽可以把组件内额值取出来自定义显示内容

小结

  • props允许父向子传入数据
  • 插槽允许父传子传入结构
  • 作用域插槽允许父向子传入自定义的数据+结构

9、自定义指令-基本使用

除了核心功能默认内置的指令(v-model 和v-show)等,Vue 也允许注册自定义指令 v-xxx

  • html + css + js的复用的主要形式是组件
  • 你需要对普通DOM 元素进行底层操作,这时候就会用到自定义指令

自定义指令的作用:

扩展标签额外的功能

自定义指令-定义的方式

{
  data(){},
  methods: {},
  directives: {
    focus: { // 自定义指令名
        inserted(el){ // 固定配置项 - 当指令插入到标签自动触发此函数
            el.focus()
        }
    },
  },
}

示例 自动获取焦点

<template>
  <div>
    <input type="text" v-focus />
  </div>
</template><script>
export default {
  // 注册
  directives: {
    focus: { // 自定义指令名
        inserted(el){ // 固定配置项 - 当指令插入到标签自动触发此函数
            el.focus()
        }
    }
  }
}
</script>

自定义指令-传值和更新

定义一个color指令-传入一个颜色,给标签设置文字颜色

directives: {
  "color":{
    inserted(el, binding){ // 插入时触发此函数
      el.style.color = binding.value;
    },
    update(el, binding){ // 更新绑定的变量时触发此函数=》手动更新
      el.style.color = binding.value;
    }
  }
}

Diewct.vue 处修改以下

<p v-color="theColor" @click="changeColor">使用v-color指令控制颜色, 点击变蓝</p><script>
  data() {
    return {
      theColor: "red",
    };
  },
  methods: {
    changeColor() {
      this.theColor = 'blue';
    },
  },
</script>

\