共计 2360 个字符,预计需要花费 6 分钟才能阅读完成。
普通的插槽里面的 丽品优系统开发(T:I8O-285I-O282 v 林),而作用域插槽里的数据是在子组件定义的。
有时候作用域插槽很有用,比如使用 Element-ui 表格自定义模板时就用到了作用域插槽,Element-ui 定义了每个单元格数据的显示格式,我们可以通过作用域插槽自定义数据的显示格式,对于二次开发来说具有很强的扩展性。
作用域插槽使用 <template> 来定义模板,可以带两个参数,分别是:
slot-scope ; 模板里的变量,旧版使用 scope 属性
slot ; 该作用域插槽的 name, 指定多个作用域插槽时用到,默认为 default,即默认插槽
例如:
复制代码
<!DOCTYPE html>
<html lang=”en”>
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
</head>
<body>
<div id="app">
<Child>
<template slot="header" slot-scope="props"> <!-- 定义了名为 header 的作用域插槽的模板 -->
<h1>{{props.info.name}}-{{props.info.age}}</h1>
</template>
<template slot-scope="show"> <!-- 定义了默认作用域插槽的模板 -->
<p>{{show.today}}</p>
</template>
</Child>
</div>
<script>
Vue.config.productionTip=false;
Vue.config.devtools=false;
Vue.component('Child',{
template:`<div class="container">
<header><slot name="header" :info="info"></slot></header> //header 插槽
<main><slot today="礼拜一"> 默认内容 </slot></main> // 默认插槽
</div>`,
data(){return { info:{name:'ge',age:25} }
}
})
debugger
new Vue({
el: '#app',
data:{
title:'我是标题',
msg:'我是内容'
}
})
</script>
</body>
</html>
复制代码
我们在子组件定义了两个插槽,如下:
header 插槽内通过 v -bind 绑定了一个名为 info 的特性,值为一个对象,包含一个 name 和 age 属性
另一个是普通插槽,传递了一个 today 特性,值为礼拜一
父组件引用子组件时定义了模板,渲染后结果如下:
对应的 html 代码如下:
其实 Vue 内部把父组件 template 下的子节点编译成了一个函数,在子组件实例化时调用的,所以作用域才是子组件的作用域
源码分析
父组件解析模板将模板转换成 AST 对象时会执行 processSlot()函数,如下:
复制代码
function processSlot (el) {// 第 9767 行 解析 slot 插槽
if (el.tag === ‘slot’) {// 如果是 slot
/* 普通插槽的逻辑 */
} else {
var slotScope;
if (el.tag === 'template') {// 如果标签名为 template(作用域插槽的逻辑)
slotScope = getAndRemoveAttr(el, 'scope'); // 尝试获取 scope
/* istanbul ignore if */
if ("development" !== 'production' && slotScope) { // 在开发环境下报一些信息,因为 scope 属性已淘汰,新版本开始用 slot-scope 属性了
warn$2(
"the \"scope\"attribute for scoped slots have been deprecated and" +
"replaced by \"slot-scope\"since 2.5. The new \"slot-scope\"attribute" +
"can also be used on plain elements in addition to <template> to" +
"denote scoped slots.",
true
);
}
el.slotScope = slotScope || getAndRemoveAttr(el, 'slot-scope'); // 获取 slot-scope 特性,值保存到 AST 对象的 slotScope 属性里
} else if ((slotScope = getAndRemoveAttr(el, 'slot-scope'))) {/* 其它分支 */}
var slotTarget = getBindingAttr(el, 'slot'); // 尝试获取 slot 特性
if (slotTarget) { // 如果获取到了
el.slotTarget = slotTarget === '""'?'"default"' : slotTarget; // 则保存到 el.slotTarget 里面
// preserve slot as an attribute for native shadow DOM compat
// only for non-scoped slots.
if (el.tag !== 'template' && !el.slotScope) {addAttr(el, 'slot', slotTarget);
}
}
}
}
复制代码
执行到这里,对于 <template slot=”header” slot-scope=”props”> 节点来说,添加了一个 slotScope 和 slotTarget 属性
正文完