详解Vue.js分发之功力域槽

详解Vue.js分发之功力域槽

在slot分发中,无论是单分发还是签字分发,都以父组件替换子组件的数据,可能尚未替换,用子组件默许的数目。两个并无法存活。那样他们就从未多少联系了。

9.2.1 注册

前边说过,大家能够用 Vue.extend() 创建二个零部件构造器:

var MyComponent = Vue.extend({
  // 选项...
})

要把那一个组织器用作组件,需求用 Vue.component(tag, constructor) 注册 :

// 全局注册组件,tag 为 my-component
Vue.component('my-component', MyComponent)

对此自定义标签字字,Vue.js 不强制要求根据 W3C
规则(小写,并且包蕴贰个短杠),就算遵从那一个规则比较好。

组件在登记之后,便得以在父实例的模块中以自定义成分 <my-component>
的样式利用。要保管在早先化根实例从前注册了组件

<div id="example">
  <my-component></my-component>
</div>
// 定义
var MyComponent = Vue.extend({
  template: '<div>A custom component!</div>'
})

// 注册
Vue.component('my-component', MyComponent)

// 创建根实例
new Vue({
  el: '#example'
})

渲染为:

<div id="example">
  <div>A custom component!</div>
</div>

留意组件的模版替换了自定义成分,自定义成分的功能只是作为八个挂载点。能够用实例选项
replace 决定是或不是替换。

# 效用域插槽

2.1 新增

功能域插槽是一种奇特类别的插槽,用作使用二个(能够传递数据到)可采用模板替换已渲染元素。

在子组件中,只需将数据传递到插槽,就如您将 prop 传递给组件同样:

    <div class="child">
      <slot text="hello from child"></slot>
    </div>

在父级中,具备卓越属性 scope<template>
成分,表示它是作用域插槽的模板。scope
的值对应叁个如今变量名,此变量接收从子组件中传递的 prop 对象:

    <div class="parent">
      <child>
        <template scope="props">
          hello from parent
          {{ props.text }}
        </template>
      </child>
    </div>

要是我们渲染以上结果,得到的输出会是:

    <div class="parent">
      <div class="child">
        hello from parent
        hello from child
      </div>
    </div>

效率域插槽更具代表性的用例是列表组件,允许组件自定义应该怎么样渲染列表各个:

    <my-awesome-list :items="items">
      <!-- 作用域插槽也可以在这里命名 -->
      <template slot="item" scope="props">
        <li class="my-fancy-item">{{ props.text }}</li>
      </template>
    </my-awesome-list>

列表组件的模版:

    <ul>
      <slot name="item"
        v-for="item in items" :text="item.text">
        <!-- fallback content here -->
      </slot>
    </ul>

注册

怎么获取呢?

9.4.4 子组件索引 ref

就算有 props 和 events,不过偶然依旧需求在 JavaScript
中一向访问子组件。为此能够动用 v-ref 为子组件钦点贰个索引 ID。举个例子:

<div id="parent">
  <user-profile v-ref:profile></user-profile>
</div>

var parent = new Vue({ el: '#parent' })
// 访问子组件
var child = parent.$refs.profile

v-ref 和 v-for 一齐用时,ref 是一个数组或对象,包罗相应的子组件。

# data 务必是函数

动用组件时,大许多选项能够被传出到 Vue 构造器中,有多个两样: data
必须是函数。 实际上,假使您如此做:

    Vue.component('my-component', {
      template: '{{ message }}',
      data: {
        message: 'hello'
      }
    })

那正是说 Vue 会在调节台发出警示,告诉你在组件中 data
必须是二个函数。最棒精晓这种规则的留存意义。

    <div id="example-2">
      <simple-counter></simple-counter>
      <simple-counter></simple-counter>
      <simple-counter></simple-counter>
    </div>

    var data = { counter: 0 }

    Vue.component('simple-counter', {
      template: '<button v-on:click="counter += 1">{{ counter }}</button>',
      // data 是一个函数,因此 Vue 不会警告,
      // 但是我们为每一个组件返回了同一个对象引用
      data: function () {
        return data
      }
    })
    new Vue({
      el: '#example-2'
    })

鉴于这四个零件共享了同一个 data , 因而扩展贰个 counter
会影响全部组件!大家得以因此为各种组件返回新的 data
对象来消除那些标题:

    data: function () {
      return {
        counter: 0
      }
    }

今昔各样 counter 都有它本身之中的动静了.

给组件绑定原惹祸件

突发性,你或者想在某些组件的根成分上监听一个原惹祸件。能够使用 .native
修饰 v-on。举例:

<my-component v-on:click.native="doTheThing"></my-component>

v-on 监听组件上自定义事件,并不会绑定到其根成分

<div id="app16">
<ul>
  <li class="child-li">苹果</li>
  <li class="child-li">香蕉</li>
  <li class="child-li">橙子</li>
</ul>
</div>

9.3.1 使用 Props 传递数据

组件实例的成效域是孤立的。那象征不能够同期不该在子组件的模版内从来引用父组件的多少。能够运用
props 把多少传给子组件。

“prop” 是组件数据的三个字段,期望从父组件传下来。子组件供给显式地用
props 选项 表明 props:

Vue.component('child', {
  // 声明 props
  props: ['msg'],
  // prop 可以用在模板内
  // 可以用 `this.msg` 设置
  template: '{{ msg }}'
})

然后向它传播叁个常备字符串:

<child msg="hello!"></child>

props的三种写法如下:
简短语法

// 简单语法
Vue.component('props-demo-simple', {
  props: ['size', 'myMessage']
})

指标语法

// 对象语法,指定验证要求
Vue.component('props-demo-advanced', {
  props: {
    // 只检测类型
    size: Number,
    // 检测类型 + 其它验证
    name: {
      type: String,
      required: true,
      // 双向绑定
      twoWay: true
    }
  }
})

# 编译作用域

在深远内容分发 API 以前,大家先明了内容的编写翻译作用域。假定模板为:

<child-component>
  {{ message }}
</child-component>

message
应该绑定到父组件的数额,依旧绑定到子组件的多寡?答案是父组件。组件成效域简单地说是:

父组件模板的内容在父组件成效域内编写翻译;子组件模板的开始和结果在子组件成效域内编写翻译。

贰个科学普及错误是计划在父组件模板内将贰个限令绑定到子组件的性质/方法:

    <!-- 无效 -->
    <child-component v-show="someChildProperty"></child-component>

尽管 ‘someChildProperty
‘是子组件的性质,上例不会如预期这样行事。父组件模板不该知道子组件的状态。

如若要绑定子组件内的吩咐到二个零部件的根节点,应当在它的模板内这么做:

Vue.component('child-component', {
  // 有效,因为是在正确的作用域内
  template: '<div v-show="someChildProperty">Child</div>',
  data: function () {
    return {
      someChildProperty: true
    }
  }
})

恍如地,分发内容是在父组件成效域内编写翻译。

keep-live 缓存组件防止再一次渲染

<!-- 基本 -->
<keep-alive>
  <component :is="view"></component>
</keep-alive>
<!-- 多个条件判断的子组件 -->
<keep-alive>
  <comp-a v-if="a > 1"></comp-a>
  <comp-b v-else></comp-b>
</keep-alive>
<!-- 和 <transition> 一起使用 -->
<transition>
  <keep-alive>
    <component :is="view"></component>
  </keep-alive>
</transition>

<keep-alive>
是用在其一个专门项指标子组件被开关的事态。就算您在里面有 v-if
则不会专门的学业。假如有上述的多少个条件性的子成分,<keep-alive>
要求同一时间唯有三个子成分被渲染。

本条data只为template里的模板服务。一样的,子组件的data只为子组件的模版服务。因为她俩都是独家效率域内的性质。

9.3.3 动态 Props

恍如于用 v-bind 绑定 HTML 性情到二个表达式,也可以用 v-bind 绑定动态
Props 到父组件的数目。每当父组件的数码变化时,也会传导给子组件:

<div>
  <input v-model="parentMsg">
  <br>
  <child v-bind:my-message="parentMsg"></child>
</div>

选择 v-bind 的缩写语法日常更简便:

<child :my-message="parentMsg"></child>

# 具名slot

<slot> 元素能够用贰个特种的属性 name 来配置怎么着分发内容。多少个 slot
能够有两样的名字。签名 slot 将拾壹分内容片段中有对应 slot 个性的要素。

依旧可以有叁个无名 slot ,它是暗许 slot
,作为找不到十三分的剧情片段的备用插槽。假若未有暗中认可的 slot
,那个找不到非凡的剧情片段将被丢掉。

诸如,假定大家有三个 app-layout 组件,它的沙盘为:

    <div class="container">
          <header>
             <slot name="header"></slot>
          </header>
          <main>
             <slot></slot>
          </main>
          <footer>
             <slot name="footer"></slot>
          </footer>
    </div>

父组件模版:

    <app-layout>
      <h1 slot="header">这里可能是一个页面标题</h1>
      <p>主要内容的一个段落。</p>
      <p>另一个主要段落。</p>
      <p slot="footer">这里有一些联系信息</p>
    </app-layout>

渲染结果为:

    div class="container">
      <header>
        <h1>这里可能是一个页面标题</h1>
      </header>
      <main>
        <p>主要内容的一个段落。</p>
        <p>另一个主要段落。</p>
      </main>
      <footer>
        <p>这里有一些联系信息</p>
      </footer>
    </div>

非prop

所谓非 prop 属性,正是它能够直接传入组件,而无需定义相应的 prop。
显明性给组件定义 prop
是传参的推荐介绍方法,但组件的小编并不总能预知到组件被选取的景观。所以,组件还可以大肆传入的性质,这个属性都会被增加到组件的根元素上。

以此自定义属性已经存放在子组件的prop对象里了。等待着被父组件获取。

9.5 非老爹和儿子组件通信

不经常非老爹和儿子关系的零件也急需通讯。在简短的境况下,使用三个空的 Vue
实例作为大旨事件总线:

var bus = new Vue()
// 触发组件 A 中的事件
bus.$emit('id-selected', 1)
// 在组件 B 创建的钩子中监听事件
bus.$on('id-selected', function (id) {
  // ...
})

在越来越多复杂的动静下,你应有思考采用特地的 状态管理方式(VUEX).

# 组件构成

组件意味着协同专门的学业,平日老爹和儿子组件会是如此的涉嫌:组件 A
在它的沙盘中运用了组件 B
。它们之间自然必要互相通讯:父组件要给子组件传递数据,子组件须要将它当中发生的事体告知给父组件。然则,在叁个美好定义的接口中尽量将父子组件解耦是很体贴的。那保险了各类组件能够在相对隔开分离的条件中书写和清楚,也小幅度进步了组件的可维护性和可重用性。

在 Vue.js 中,老爹和儿子组件的关联足以总括为 props down, events up
。父组件通过 props 向下传递数据给子组件,子组件通过 events
给父组件发送信息。

应用Slot分发内容

为了提升组件的可扩张性和烧结组件,大家能够使用Vue提供Slot分发内容来贯彻。
所谓的Slot内容分发就是把自定义元素内嵌的模版插入到子组件模板slot插座中。

图片 1

image.png

实例代码:

const MyChild = Vue.extend({
  template: `<h1>
    <!-- 默认插座,插入内容会替换掉slot,若没父模板中没有内容插入,则该备用内容会显示 -->
    <slot>h1内容</slot>
  </h1>`
})

new Vue({
  el: '#app',
  components: {
    'my-child': MyChild
  },
  template: `
  <div>
    <!-- 插入内容 -->
    <my-child>
      Hello world!
    </my-child>
    <!-- 无内容插入 -->
    <my-child></my-child>
  </div>
  `
})

效果:

图片 2

image.png

只顾分发内容只在父成效域内编写翻译(请看slot编写翻译内容)

首先,供给通晓的是,每一个组件有种种组件自身的成效域。每一个组件都以Vue()的实例,有投机的成效域。

9.3.4 Prop 绑定类型

prop
暗中同意是单向绑定:当父组件的习性变化时,将传输给子组件,但是反过来不会。那是为了防止子组件无意修改了父组件的动静——这会让动用的数据流难以明白。可是,也足以选用.sync 或 .once 绑定修饰符显式地强制双向或单次绑定:

正如语法:

<!-- 默认为单向绑定 -->
<child :msg="parentMsg"></child>

<!-- 双向绑定  在VUE2中已经废弃 -->
<child :msg.sync="parentMsg"></child>

<!-- 单次绑定 -->
<child :msg.once="parentMsg"></child>

双向绑定会把子组件的 msg 属性同步回父组件的 parentMsg
属性。单次绑定在创制未来不会一齐之后的变型。

Vue 2.x相相比Vue
1.x来说,晋级变化除了完结了Virtual-Dom以外,给使用者最大不适便是移除的组件的props的双向绑定功能。以往在Vue1.x中利用props的twoWay.sync绑定修饰符就可以兑现props的双向绑定成效,可是在Vue第22中学通透到底舍弃了此功用,假设急需双向绑定需求本身来促成。

注意假如 prop
是三个目标或数组,是按引用传递。在子组件内修改它会影响父组件的情事,不管是选择哪一类绑定类型。

上述这几句话是不行重大的。比如array、object都属于引用类型的数量,那么单向绑定对其则不起成效,但是为了单向数据流的纯净化,也要尊重单向数据流的见解。尽量制止方向的修改从而影响父组件的扭转。

利用组件


其他

//js
Vue.component('child-component4',{
  template:'<ul>' +
  '<slot name="child-ul" v-for="item in fruit" v-bind:text="item.name">?</slot>' +
  '</ul>',
  data:function(){
   return {
     fruit:[
       {name:'苹果'},
       {name:'香蕉'},
       {name:'橙子'}
     ]
   }
  },
});
Vue.component('father-component4',{
  template:'<child-component4>' +
  '<template scope="props" slot="child-ul">' +
  '<li class="child-li" >{{props.text}}</li>' +
  '</template>' +
  '</child-component4>'
});
var app16 = new Vue({
  el:'#app16'
});
<div id="app16">
  <father-component4></father-component4>
</div>

9.6 使用 Slot 分发内容

在应用组件时,经常要像那样组合它们:

<app>
  <app-header></app-header>
  <app-footer></app-footer>
</app>

瞩目两点:

  1. <app>
    组件不知道它的挂载点会有哪些内容。挂载点的开始和结果是由<app>的父组件决定的。
  2. <app> 组件很只怕有它和睦的模板。

为了让组件能够结合,我们必要一种艺术来混合父组件的从头到尾的经过与子组件本人的模板。这么些进程被叫作
内容分发 (或 “transclusion” 假诺你通晓 Angular)。Vue.js
达成了八个内容分发 API ,参照了现阶段 Web 组件标准草案,使用特殊的
<slot> 成分作为土生土长内容的插槽。
编写翻译成效域

在深刻内容分发 API 以前,大家先明了内容的编写翻译效率域。假定模板为:

<child-component>
  {{ message }}
</child-component>

message
应该绑定到父组件的数额,依然绑定到子组件的多寡?答案是父组件。组件效率域轻松地正是:
父组件模板的内容在父组件效率域内编写翻译;子组件模板的始末在子组件成效域内编写翻译。
三个大面积错误是意欲在父组件模板内将贰个下令绑定到子组件的习性/方法:

<!-- 无效 -->
<child-component v-show="someChildProperty"></child-component>

举个例子 someChildProperty
是子组件的特性,上例不会如预期那样行事。父组件模板不应当知道子组件的处境。
设若要绑定子组件内的命令到四个零部件的根节点,应当在它的模板内这么做:

Vue.component('child-component', {
  // 有效,因为是在正确的作用域内
  template: '<div v-show="someChildProperty">Child</div>',
  data: function () {
    return {
      someChildProperty: true
    }
  }
})

恍如地,分发内容是在父组件成效域内编写翻译。

# 使用自定义事件的表单输入组件

自定义事件也能够用来创设自定义的表单输入组件,使用 v-model
来张开数据双向绑定。牢记:

    <input v-model="something">

单独是叁个语法糖:

    <input v-bind:value="something" v-on:input="something = $event.target.value">

故此在组件中应用时,它一定于上面包车型地铁简写:

    <custom-input v-bind:value="something" v-on:input="something = arguments[0]"></custom-input>

之所以要让组件的 v-model 生效,它必须:

  • 接受贰个 value 属性
  • 在有新的 value 时触发 input 事件

八个特别轻巧的钱币输入:

<currency-input v-model="price"></currency-input>

    Vue.component('currency-input', {
      template: '\
        \
          $\
          <input\
            ref="input"\
            v-bind:value="value"\
            v-on:input="updateValue($event.target.value)"\
          >\
        \
      ',
      props: ['value'],
      methods: {
        // 不是直接更新值,而是使用此方法来对输入值进行格式化和位数限制
        updateValue: function (value) {
          var formattedValue = value
            // 删除两侧的空格符
            .trim()
            // 保留 2 小数位
            .slice(0, value.indexOf('.') + 3)
          // 如果值不统一,手动覆盖以保持一致
          if (formattedValue !== value) {
            this.$refs.input.value = formattedValue
          }
          // 通过 input 事件发出数值
          this.$emit('input', Number(formattedValue))
        }
      }
    })

单向数据流

prop
是单向绑定的:当父组件的属性别变化化时,将传输给子组件,可是不会反过来。那是为着防止子组件无意修改了父组件的境况——这会让使用的数据流难以领悟。

注目的在于 JavaScript 中目的和数组是援引类型,指向同二个内部存款和储蓄器空间,假如prop 是一个指标或数组,在子组件内部更改它会影响父组件的图景。

小编们应当幸免这种状态时有爆发:

  • 概念二个有的变量,并用 prop 的值起初化它:

props: ['initialCounter'],
data: function () {
  return { counter: this.initialCounter }
}
  • 概念贰个测算属性,处理 prop 的值并再次来到。

props: ['size'],
computed: {
  normalizedSize: function () {
    return this.size.trim().toLowerCase()
  }
}

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图