Luo Hao

Vue.js实战读书笔记(3)

Rehoni / 2019-03-08


slot分发内容

props 传递数据、 events 触发事件和 slot 内 容分发就构成了 Vue 组件的 3 个 API 来源,再复杂的组件也是由这 3 部分构成的。

  1. 作用域:slot分发的内容作用域是在父组件上的。

  2. slot用法:

    1. 单个slot:父组件中进入子组件child-component,在child-component的模板内定义一个<slot>元素,并且用一个<p>作为默认的内容,在父组件没有使用 slot 时,会渲染这段默认的文本;如果写入了 slot, 那就会替换整个<slot>。 子组件<slot>内的备用内容,它的作用域是子组件本身
    2. 具名slot:给<slot>元素指定一个 name 后可以分发多个内容,具名 Slot 可以与单个 Slot 共存。其中在<div class=”main与内的<slot> 没有使用 name 特性,它将作为默认 slot 出现,父组件没有使用 slot 特性的元素与内容都将出现在这里。如果没有指定默认的匿名 slot,父组件内多余的内容片段都将被抛弃。
    3. 作用域插槽:在<slot>元素上有一个类似 props 传递数据给组件的写法 msg=”xxx”,将数据传到了插槽。父组件中使用了<template>元素,而且拥有一个 scope=”props”的特性,这里的 props只是一个临时变量,就像 v-for=”item in items,里面的 item 一样。 template 内可以通过临时变量 props访问来自子组件插槽的数据 msg 。如果下例还在其他组件内使用,<Ii>的内容渲染权是由使用者掌握的,而数据却可以通过临时变量(比如 props )从子组件内获取。
    4. 通过$slots 可以访问某个具名 slot, this .$slots.default 包括了所有没有被包含在具名 slot 中的节点。$slots 在业务中几乎用不到 , 在用 render 函数(进阶篇中将介绍)创建组件时会比较有用,但主要还是用于独立组件开发中。
    <div id="app">
      <my-list :books="books"><!--这里用v-bind语法糖,绑定父组件data中的book传入-->
        <!--作用域插槽也可以是具名slot-->
        <template slot=”book” scope=”props >
          <li> {{props.bookName}}</li>
        </template>
      </my-list>
    </div>
    <script>
      Vue.component('my-list',{
        props:{
          books:{
            type:Array,
            default:function(){
              return [];
            }
          }
        },
        template:'\
        <ul>\
          <slot name="book"\
          v-for="book in books"\
          <!--这里的:book-name对应props.bookName,是由驼峰命名法转化位kebab-case命名的-->\
          :book-name="book.name">\
          <!--这里也可以写默认 slot 内容-->\
          </slot>\
        </ul>'
      });
    
      var app = new Vue({
        el:'#app',
        data:{
          books:[
            {name:'book1'},
            {name:'book2'},
            {name:'book3'}
          ]
        }
      })
    </script>
    

组件高级用法

  1. 组件递归 组件在它的模板内可以递归地调用自己 , 只要给组件设置 name 的选项就可以了。设置 name 后,在组件模板内就可以递归使用了,不过需要注意的是,必须给一个条件来限制递归数量,否则会抛出错误 : max stack size exceeded 。组件递归使用可以用来开发一些具有未知层级关系的独立组件,比如级联选择器和树形控件等
<!--父组件中-->
<child-component : count= "1" ></child- component>
<!--子组件中-->
<child-component :count="count + 1"  v-if="count < 3" ></child- component>
  1. 内联模板 组件的模板一般都是在 template 选项内定义的, Vue 提供了一个内联模板的功能,在使用组件时,给组件标签使用 inline- mplate 特性,组件就会把它的内容当作模板,而不是把它当内容分发,这让模板更灵活。 在父组件中声明的数据 message 和子组件中声明的数据 msg , 两个都可以渲染(如果同名,优先使用子组件的数据)。这反而是内联模板的缺点,就是作用域比较难理解,如果不是非常特殊的场景 , 建议不要轻易使用内联模板。

  2. 动态组件 <component :is="currentView"></component>动态改变currentView的值就可以动态挂载组件了,也可以直接绑定在组件对象上。

  3. 异步组件 工厂函数接收一个 resolve 回调,在收到从服务器下载的组件定义时调用。也可以调用reject(reason)指示加载失败。这里 setTimeout 只是为了演示异步,具体的下载逻辑可以自己决定,比如把组件配置写成一个对象配置,通过 Ajax 来请求,然后调用 resolve 传入配置选项。

<div id="app">
    <child-component></child-component>
</div>
<script>
    Vue.component('child-component',
        function (resolve, reject) {
            window.setTimeout(function () {
                resolve({
                    template: '<div>我是异步渲染的</div>'
                });
            }, 2000)
        });
    var app = new Vue({
        el: '#app'
    })
</script>