Vue基础:组件--slot、异步组件、递归组件及其他
slot分发内容为了让组件可以组合,我们需要一种方式来混合父组件的内容与子组件自己的模板。这个过程被称为内容分发。Vue中使用特殊的 <slot> 元素作为原始内容的插槽。 问题(编译作用域)message 应该绑定到父组件的数据,还是绑定到子组件的数据?<child-component>{{ message }}</child-component>答案是父组件。父组件模板的内容在父组件作用
slot分发内容
为了让组件可以组合,我们需要一种方式来混合父组件的内容与子组件自己的模板。这个过程被称为内容分发。Vue中使用特殊的 <slot>
元素作为原始内容的插槽。
问题(编译作用域)
message
应该绑定到父组件的数据,还是绑定到子组件的数据?
<child-component>
{{ message }}
</child-component>
答案是父组件。父组件模板的内容在父组件作用域内编译;子组件模板的内容在子组件作用域内编译。
单个slot
除非子组件模板包含至少一个 <slot>
插口,否则父组件的内容将会被丢弃。当子组件模板只有一个没有属性的 slot 时,父组件整个内容片段将插入到 slot 所在的 DOM 位置,并替换掉 slot 标签本身。在 <slot>
标签中的任何内容都被视为备用内容。备用内容在子组件的作用域内编译,并且只有在宿主元素为空,且没有要插入的内容时才显示备用内容。
具名slot
<slot>
元素可以用一个特殊的属性 name
来配置如何分发内容。多个 slot 可以有不同的名字。具名 slot 将匹配内容片段中有对应 slot
特性的元素。仍然可以有一个匿名 slot,它是默认 slot,作为找不到匹配的内容片段的备用插槽。如果没有默认的 slot,这些找不到匹配的内容片段将被抛弃。
<div id="app">
<my-component>
<template>
<p>父组件分发内容</p>
</template>
</my-component>
<my-component2>
<b>内容a</b>
<template slot="title">
父组件分发的title
</template>
<b>内容b</b>
</my-component2>
</div>
<script>
const app = new Vue({
el: '#app',
components: {
'my-component': {
template: `<div><slot><p>备选内容</p></slot></div>`
},
'my-component2': {
template: `<div><slot name="title">备选title</slot><slot><b>备选内容</b></slot></div>`
}
}
});
</script>
渲染结果:
<div>
<p>父组件分发内容</p>
</div>
<div>
父组件分发的title
<b>内容a</b>
<b>内容b</b>
</div>
完整示例参考地址:https://jsfiddle.net/381510688/tugxd14s/
作用域插槽
在子组件插槽中可以通过slot插槽标签的属性将数据传递到父组件要分发的内容当中,父组件要通过<template scope=""></template>
模板来接收子组件插槽传递上来的数据。
<my-component>
<template scope="props">
<p>父组件分发内容</p>
<p>{{props.message}}</p>
</template>
</my-component>
<script>
const app = new Vue({
el: '#app',
components: {
'my-component': {
template: `<div><slot message="哈哈"></slot></div>`
}
}
});
</script>
渲染结果:
<div>
<p>父组件分发内容</p>
<p>哈哈</p>
</div>
具代表性的列表组:
<my-list :list="['a.com', 'b.com']">
<template slot="item" scope="props">
<li class="link"><a>{{props.link}}</a></li>
</template>
</my-list>
<script>
// ...
'my-list': {
props: ['list'],
template: `<ul><slot name="item" v-for="item in list" :link="item"></slot></ul>`
}
</script>
渲染结果:
<ul>
<li class="link"><a>a.com</a></li>
<li class="link"><a>b.com</a></li>
</ul>
完整示例参考地址:https://jsfiddle.net/381510688/j8qkbwbo/
动态组件
动态地绑定到它的 is
特性,让多个组件可以使用同一个挂载点,并动态切换:
<component v-bind:is="currentView">
<!-- 组件在 vm.currentview 变化时改变! -->
</component>
var vm = new Vue({
el: '#example',
data: {
currentView: 'home'
},
components: {
home: { /* ... */ },
posts: { /* ... */ },
archive: { /* ... */ }
}
})
keep-alive可以把切换出去的组件保留在内存中,保留它的状态,避免重新渲染。
<keep-alive>
<component :is="currentView">
<!-- 非活动组件将被缓存! -->
</component>
</keep-alive>
杂项
编写可复用组件
可复用组件应当定义一个清晰的公开接口,同时也不要对其使用的外层数据作出任何假设。
- Prop 允许外部环境传递数据给组件;
- 事件允许从组件内触发外部环境的副作用;
- 插槽允许外部环境将额外的内容组合在组件中。
<my-component
:foo="baz"
:bar="qux"
@event-a="doThis"
@event-b="doThat"
>
<img slot="icon" src="...">
<p slot="main-text">Hello!</p>
</my-component>
子组件引用
尽管有 prop 和事件,但是有时仍然需要在 JavaScript 中直接访问子组件。为此可以使用 ref
为子组件指定一个引用 ID。
<div id="parent">
<user-profile ref="profile"></user-profile>
</div>
var parent = new Vue({ el: '#parent' })
// 访问子组件实例
var child = parent.$refs.profile
注意:$refs
只在组件渲染完成后才填充,并且它是非响应式的。它仅仅是一个直接操作子组件的应急方案——应当避免在模板或计算属性中使用 $refs
。
ref
被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs
对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例,可以通过$el,获取DOM元素。
异步组件
Vue.js 允许将组件定义为一个工厂函数,异步地解析组件的定义。
Vue.component('async-example', function (resolve, reject) {
setTimeout(function () {
// 将组件定义传入 resolve 回调函数
resolve({
template: '<div>I am async!</div>'
})
}, 1000)
})
Vue.component('async-webpack-example', function (resolve) {
// 这个特殊的 require 语法告诉 webpack
// 自动将编译后的代码分割成不同的块,
// 这些块将通过 Ajax 请求自动下载。
require(['./my-async-component'], resolve)
})
webpack 2 + ES2015 的语法时可以这样:
Vue.component(
'async-webpack-example',
() => import('./my-async-component')
)
组件命名约定
当注册组件 (或者 prop) 时,可以使用 kebab-case (短横线分隔命名)、camelCase (驼峰式命名) 或 PascalCase (单词首字母大写命名);在 HTML 模板中,请使用 kebab-case。
components: {
myComponent: { /* ... */ }
}
<my-component/>
递归组件
一定要确保递归调用有终止条件,可以通过v-if进行控制。
递归组件示例:https://jsfiddle.net/381510688/nhhfL1bd/
组件间的循环引用
参考官网地址:https://cn.vuejs.org/v2/guide/components.html#组件间的循环引用
内联模板
如果子组件有 inline-template
特性,组件将把它的内容当作它的模板,而不是把它当作分发内容。这让模板编写起来更灵活。
<my-component inline-template>
<div>
<p>这些将作为组件自身的模板。</p>
<p>而非父组件透传进来的内容。</p>
</div>
</my-component>
但是 inline-template
让模板的作用域难以理解。使用 template
选项在组件内定义模板或者在 .vue
文件中使用 template
元素才是最佳实践。
X-Template
另一种定义模板的方式是在 JavaScript 标签里使用 text/x-template
类型,并且指定一个 id。例如:
<script type="text/x-template" id="hello-world-template">
<p>Hello hello hello</p>
</script>
Vue.component('hello-world', {
template: '#hello-world-template'
})
注意:在有很多大模板的演示应用或者特别小的应用中可能有用,其它场合应该避免使用,因为这将模板和组件的其它定义分离了。
对低开销的静态组件使用v-once
尽管在 Vue 中渲染 HTML 很快,不过当组件中包含大量静态内容时,可以考虑使用 v-once
将渲染结果缓存起来,就像这样:
Vue.component('terms-of-service', {
template: '\
<div v-once>\
<h1>Terms of Service</h1>\
...很多静态内容...\
</div>\
'
})
更多推荐
所有评论(0)