Vue插槽原理与用法详解


Posted in Javascript onMarch 05, 2019

本文实例讲述了Vue插槽原理与用法。分享给大家供大家参考,具体如下:

1 插槽内容

Vue 实现了一套内容分发的 API,这套 API 基于当前的 Web Components 规范草案,将 <slot> 元素作为承载分发内容的出口。

它允许你像这样合成组件:

<div id="app1">
  <navigation-link url="/profile">
    Your Profile
  </navigation-link>
</div>

然后你在 <navigation-link> 的模板中可能会写为:

Vue.component('navigation-link', {
    template: `
      <a
        v-bind:href="url" rel="external nofollow" 
        class="nav-link"
      >
      <slot></slot>
      </a>
    `
  });

当组件渲染的时候,这个 <slot> 元素将会被替换为“Your Profile”。

Vue插槽原理与用法详解

插槽内可以包含任何模板代码,包括 HTML:

<navigation-link url="/profile">
 <!-- 添加一个 Font Awesome 图标 -->
 <span class="fa fa-user"></span>
 Your Profile
</navigation-link>

甚至其它的组件:

<navigation-link url="/profile">
 <!-- 添加一个图标的组件 -->
 <font-awesome-icon name="user"></font-awesome-icon>
 Your Profile
</navigation-link>

如果 <navigation-link> 没有包含一个 <slot> 元素,则任何传入它的内容都会被抛弃。

2 具名插槽

有些时候我们需要多个插槽。例如,一个假设的 <base-layout> 组件多模板如下:

<div class="container">
 <header>
  <!-- 我们希望把页头放这里 -->
 </header>
 <main>
  <!-- 我们希望把主要内容放这里 -->
 </main>
 <footer>
  <!-- 我们希望把页脚放这里 -->
 </footer>
</div>

对于这样的情况,<slot> 元素有一个特殊的特性:name。这个特性可以用来定义额外的插槽:

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

在向具名插槽提供内容的时候,我们可以在一个父组件的 <template> 元素上使用 slot 特性:

<base-layout>
 <template slot="header">
  <h1>Here might be a page title</h1>
 </template>
 <p>A paragraph for the main content.</p>
 <p>And another one.</p>
 <template slot="footer">
  <p>Here's some contact info</p>
 </template>
</base-layout>

另一种 slot 特性的用法是直接用在一个普通的元素上:

<base-layout>
 <h1 slot="header">Here might be a page title</h1>
 <p>A paragraph for the main content.</p>
 <p>And another one.</p>
 <p slot="footer">Here's some contact info</p>
</base-layout>

我们还是可以保留一个未命名插槽,这个插槽是默认插槽,也就是说它会作为所有未匹配到插槽的内容的统一出口。上述两个示例渲染出来的 HTML 都将会是:

<div class="container">
 <header>
  <h1>Here might be a page title</h1>
 </header>
 <main>
  <p>A paragraph for the main content.</p>
  <p>And another one.</p>
 </main>
 <footer>
  <p>Here's some contact info</p>
 </footer>
</div>

3 默认插槽的内容

有的时候为插槽提供默认的内容是很有用的。例如,一个 <submit-button> 组件可能希望这个按钮的默认内容是“Submit”,但是同时允许用户覆写为“Save”、“Upload”或别的内容。

你可以在 <slot> 标签内部指定默认的内容来做到这一点。

<button type="submit">
 <slot>Submit</slot>
</button>

如果父组件为这个插槽提供了内容,则默认的内容会被替换掉。

4 编译作用域

当你想在插槽内使用数据时,例如:

<navigation-link url="/profile">
 Logged in as {{ user.name }}
</navigation-link>

该插槽可以访问跟这个模板的其它地方相同的实例属性 (也就是说“作用域”是相同的)。但这个插槽不能访问 <navigation-link> 的作用域。例如尝试访问 url 是不会工作的。牢记一条准则:

父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译。

5 作用域插槽

2.1.0+ 新增

有的时候你希望提供的组件带有一个可从子组件获取数据的可复用的插槽。例如一个简单的 <todo-list> 组件的模板可能包含了如下代码:

Vue.component('todo-list',{
    template:`
    <ul>
      <li
        v-for="todo in todos"
        v-bind:key="todo.id">
        {{ todo.text }}
      </li>
    </ul>
    `
  });

但是在我们应用的某些部分,我们希望每个独立的待办项渲染出和 todo.text 不太一样的东西。这也是作用域插槽的用武之地。

为了让这个特性成为可能,你需要做的全部事情就是将待办项内容包裹在一个 <slot> 元素上,然后将所有和其上下文相关的数据传递给这个插槽:在这个例子中,这个数据是 todo 对象:

<ul>
 <li
  v-for="todo in todos"
  v-bind:key="todo.id"
 >
  <!-- 我们为每个 todo 准备了一个插槽,-->
  <!-- 将 `todo` 对象作为一个插槽的 prop 传入。-->
  <slot v-bind:todo="todo">
   <!-- 回退的内容 -->
   {{ todo.text }}
  </slot>
 </li>
</ul>

现在当我们使用 <todo-list> 组件的时候,我们可以选择为待办项定义一个不一样的<template> 作为替代方案,并且可以通过 slot-scope 特性从子组件获取数据:

<todo-list v-bind:todos="todos">
  <!--插槽作用域的名字是 slotProps-->
  <template slot-scope="slotProps">
    <!-- 为指定的待办项定义一个模板-->
    <span v-if="slotProps.todo.isComplete">✓</span>
    {{ slotProps.todo.text }}
  </template>
</todo-list>

在 2.5.0+,slot-scope 不再限制在 <template> 元素上使用,而可以用在插槽内的任何元素或组件上。

解构 slot-scope

如果一个 JavaScript 表达式在一个函数定义的参数位置有效,那么这个表达式实际上就可以被 slot-scope 接受。也就是说你可以在支持的环境下 单文件组件或现代浏览器),在这些表达式中使用 ES2015 解构语法。例如:

<todo-list v-bind:todos="todos">
 <template slot-scope="{ todo }">
  <span v-if="todo.isComplete">✓</span>
  {{ todo.text }}
 </template>
</todo-list>

这会使作用域插槽变得更干净一些。

希望本文所述对大家vue.js程序设计有所帮助。

Javascript 相关文章推荐
让iframe框架网页在任何浏览器下自动伸缩
Aug 18 Javascript
纯JavaScript实现的完美渐变弹出层效果代码
Apr 02 Javascript
js 获取子节点函数 (兼容FF与IE)
Apr 18 Javascript
JavaScript初学者需要了解10个小技巧
Aug 25 Javascript
jQuery中:enabled选择器用法实例
Jan 04 Javascript
html中鼠标滚轮事件onmousewheel的处理方法
Nov 11 Javascript
js通过指定下标或指定元素进行删除数组的实例
Jan 12 Javascript
vue填坑之webpack run build 静态资源找不到的解决方法
Sep 03 Javascript
JavaScript使用类似break机制中断forEach循环的方法
Nov 13 Javascript
mocha的时序规则讲解
Feb 16 Javascript
layui prompt 设置允许空白提交的方法
Sep 24 Javascript
javascript实现商品图片放大镜
Nov 28 Javascript
JavaScript基于遍历操作实现对象深拷贝功能示例
Mar 05 #Javascript
JavaScript函数定义方法实例详解
Mar 05 #Javascript
C#程序员入门学习微信小程序的笔记
Mar 05 #Javascript
JavaScript函数的4种调用方法实例分析
Mar 05 #Javascript
微信小程序保存多张图片的实现方法
Mar 05 #Javascript
JS添加或删除HTML dom元素的方法实例分析
Mar 05 #Javascript
迅速了解一下ES10中Object.fromEntries的用法使用
Mar 05 #Javascript
You might like
初学PHP的朋友 经常问的一些问题。不断更新
2011/08/11 PHP
destoon实现VIP排名一直在前面排序的方法
2014/08/21 PHP
Laravel手动分页实现方法详解
2016/10/09 PHP
用js实现手把手教你月入万刀(转贴)
2007/11/07 Javascript
从零开始学习jQuery (三) 管理jQuery包装集
2011/02/23 Javascript
兼容ie、firefox的图片自动缩放的css跟js代码分享
2012/01/21 Javascript
利用js的Node遍历找到repeater的一个字段实例介绍
2013/04/25 Javascript
设为首页和收藏的Javascript代码(亲测兼容IE,Firefox,chrome等浏览器)
2013/11/18 Javascript
jQuery支持动态参数将函数绑定到事件上的方法
2015/03/17 Javascript
jQuery实现图片文字淡入淡出效果
2015/12/21 Javascript
AngularJS页面访问时出现页面闪烁问题的解决
2016/03/06 Javascript
jquery if条件语句的写法
2016/05/19 Javascript
jQuery解析与处理服务器端返回xml格式数据的方法详解
2016/07/04 Javascript
JS 插件dropload下拉刷新、上拉加载使用小结
2017/04/13 Javascript
Angular2中select用法之设置默认值与事件详解
2017/05/07 Javascript
jQuery中hover方法搭配css的hover选择器,实现选中元素突出显示方法
2017/05/08 jQuery
jquery.picsign图片标注组件实例详解
2018/02/02 jQuery
Vue-cli@3.0 插件系统简析
2018/09/05 Javascript
Javascript 之封装(Package)
2018/09/14 Javascript
JS复杂判断的更优雅写法代码详解
2018/11/07 Javascript
Vue组件内部实现一个双向数据绑定的实例代码
2019/04/04 Javascript
layui 根据后台数据动态创建下拉框并同时默认选中的实例
2019/09/02 Javascript
JavaScript实现点击出现子菜单效果
2021/02/08 Javascript
python多线程threading.Lock锁用法实例
2014/11/01 Python
Python2随机数列生成器简单实例
2017/09/04 Python
python和opencv实现抠图
2018/07/18 Python
python 实现得到当前时间偏移day天后的日期方法
2018/12/31 Python
Python 正则表达式 re.match/re.search/re.sub的使用解析
2019/07/22 Python
地图可视化神器kepler.gl python接口的使用方法
2020/12/22 Python
加拿大建筑和装修专家:Reno-Depot
2017/12/21 全球购物
英国玛莎百货澳大利亚:Marks & Spencer Australia
2019/08/30 全球购物
应聘医学检验人员自荐信
2013/09/27 职场文书
文艺演出策划方案
2014/06/07 职场文书
2015年国税春训心得体会
2015/03/09 职场文书
毕业生就业推荐表自我鉴定
2019/06/20 职场文书
MySQL索引知识的一些小妙招总结
2021/05/10 MySQL