Vue 动态组件与插槽
Vue 动态组件
Vue 动态组件基本概念
动态组件的作用: 可以让多个组件使用同一个挂载点,并动态切换。 component 本质上是一个占位符,通过 :is 属性来指定渲染谁。
Vue 动态组件语法
<component :is="vue变量"></component>Vue 动态组件示例
创建两个子组件。
<template>
<div>用户名:<input type="text" /> 密码:<input type="text" /></div>
</template><template>
<div>用户名:<input type="text" /> 密码:<input type="text" /></div>
</template>在 App.vue 中插入动态组件:
<template>
<div>
<h1>动态组件的使用</h1>
<div>
<button @click="change('username')">账号密码</button>
<button @click="change('userinfo')">用户信息</button>
</div>
<component :is="curComp"></component>
</div>
</template>
<script>
import userinfo from './components/userinfo.vue'
import username from './components/username.vue'
export default {
data() {
return {
curComp: 'username',
}
},
methods: {
change(type) {
this.curComp = type
},
},
components: {
username,
userinfo,
},
}
</script>在 data 中设置了子组件的变量名,点击按钮改变子组件从而实现动态组件的效果。
Vue 动态组件缓存
动态组件频繁切换会导致频繁销毁和创建组件,不利于提高性能。因此在组件创建出来之后将其缓存起来不被销毁,需要的时候就能使用。
Vue 动态组件缓存的语法
用 keep-alive 将其包裹即可。
<keep-alive>
<component :is="vue变量名"></component>
</keep-alive>总结
keep-alive可以把内部的组件进行缓存而非销毁,内部包裹的标签不会被销毁和重新创建,因此能够提高组件的性能。
Vue 动态组件缓存的生命周期
组件被缓存起来后钩子函数不会再触发,想要判断某个组件当前是显示还是隐藏状态,需要用到 activated 和 deactivated 这两个钩子。
activated:当前组件显示状态。当组件被激活的时候会自动触发这个生命周期函数。deactivated:当前组件隐藏状态。当组件被缓存的时候会自动触发这个生命周期函数。
被缓存的组件不再创建和销毁,也就意味着钩子函数 created 和销毁函数只会触发一次,为了能得知此时组件是否是显示状态,可以通过新的钩子判断其是否被激活。
总结
当组件第一次被创建的时候,既会触发 created 生命周期,也会触发 activated 生命周期。而组件被激活的时候,只会触发 activated 生命周期,而不触发 created 生命周期。
Vue 动态组件缓存的 include 属性
用来指定:只有名称匹配的组件会被缓存,多个组件名之间使用英文逗号分隔。
相反的,指定 exclude 可用来指定被匹配的组件不会被缓存。
注意
二者只能选其一来使用,不能一起使用。
Vue 动态组件注册与声明的区别
- 组件注册 组件注册指在
a组件中引入b组件时设置的名称,主要应用场景:把注册好的组件渲染到页面上。 - 组件声明 组件声明指创建好了组件后为其设置一个
name属性,主要应用场景:结合keep-alive标签实现组件缓存功能,以及在调试工具中看到组建的name名称。
Vue 动态组件解析 DOM 模板时的注意事项
有些 HTML 元素,诸如 <ul>、<ol>、<table> 和 <select>,对于哪些元素可以出现在其内部是有严格限制的。而有些元素,诸如 <li>、<tr> 和 <option>,只能出现在其它某些特定的元素内部。
这会导致我们使用这些有约束条件的元素时遇到一些问题。例如:
<table>
<blog-post-row></blog-post-row>
</table>这个自定义组件 <blog-post-row> 会被作为无效的内容提升到外部,并导致最终渲染结果出错。幸好这个特殊的 is attribute 给了我们一个变通的办法:
<table>
<tr is="blog-post-row"></tr>
</table>Vue 动态组件插槽
Vue 动态组件插槽的含义
插槽的作用: 用于实现组件的内容分发, 通过 slot 标签, 可以接收到写在组件标签内的内容。
Vue 动态组件插槽的语法
子组件中:使用以下代码,作用是占位
<slot></slot>父组件中:插入以下代码,把动态的标签写入其中即可。
<子组件名称></子组件名称>Vue 动态组件插槽示例
子组件中,生成一个骨架,把会变化的部分用占位符替换。
<template>
<div>
<slot></slot>
</div>
</template>
<script>
export default {}
</script>
<style></style>父组件中,用引入的子组件 Pannel 包裹动态的标签,多个标签还能实现复用。
<template>
<div>
<div>
<h1>插槽的使用</h1>
<pannel>
<p>哈哈哈哈</p>
<p>我是文字</p>
</pannel>
<pannel>
<ul>
<li>刀刀</li>
<li>刀刀</li>
<li>刀刀</li>
<li>刀刀</li>
</ul>
</pannel>
</div>
</div>
</template>
<script>
import pannel from './components/pannel.vue'
export default {
components: {
pannel,
},
}
</script>Vue 动态组件插槽的作用域
如果在插槽中想要使用变量或方法,例如:
<navigation-link url="/profile">
<div @click="click">Logged in as {{ user.name }}</div>
</navigation-link>该插槽跟模板的其它地方一样可以访问相同的实例 property (也就是相同的“作用域”),而不能访问 <navigation-link> 的作用域。
父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。
Vue 动态组件插槽的默认内容
如果调用者不传值, 有默认内容就会显示默认内容,默认内容添加在 slot 标签内。
Vue 动态组件插槽默认内容的语法
<slot>默认内容</slot>Vue 动态组件具名插槽
当一个组件内有 2 处以上需要外部传入标签的插槽,可以为每个插槽添加名字加以区分。
Vue 动态组件具名插槽的语法
<slot name="自定义名字"></slot>默认情况下,在使用组件的时候,提供的内容都会被填充到名字为 default 的插槽中。
- 如果要把内容填充到指定名称的插槽中,需要使用
v-slot这个指令。 v-slot:后面要跟上插槽的名字。v-slot:指令不能直接作用在元素身上,必须用在template标签上。template:这个标签是一个虚拟标签,只起到包裹性质的作用,并不会被实际渲染成 html 元素。
在组件内添加 template 标签,结合 v-slot 或其简写形式 # 进行具名区分。
Vue 动态组件具名插槽示例
子组件中定义两个具名插槽。
<template>
<div>
<slot name="title"></slot>
<slot name="content"></slot>
</div>
</template>
<script>
export default {}
</script>
<style></style>父组件分开使用。
<template>
<div>
<pannel>
<template v-slot:title>
<h1>我一路向北</h1>
</template>
<template #content>
<p>离开有你的季节</p>
</template>
</pannel>
</div>
</template>
<script>
import pannel from './components/pannel.vue'
export default {
components: {
pannel,
},
}
</script>Vue 动态组件作用域插槽
子组件里的值,给插槽赋值,在父组件环境下使用。
Vue 动态组件作用域插槽的语法
<slot :自定义名称="子组件内的值"></slot>Vue 动态组件作用域插槽的使用
父组件中用 template 和 v-slot="自定义变量名" 来使用。变量名会收集 slot 身上属性和值形成对象。
<template v-slot="scope">
<p>{{ scope.自定义名称.子组件内的值 }}</p>
</template>推荐名称使用 scope ,但想起啥都无所谓。
Vue 动态组件作用域插槽示例
子组件内定义一个作用域插槽,把对象传过去。
<template>
<div>
<slot name="title"></slot>
<slot :row="obj" name="content"></slot>
</div>
</template>
<script>
export default {
data() {
return {
obj: {
one: '我是1',
two: '我是0',
},
}
},
}
</script>父组件中接受其值,由于是对象形式的值,想要使用要再点一次。
<template>
<div>
<pannel>
<template #title>
<h1>七里香的滋味</h1>
</template>
<!-- 这里scoped变量只有当前template可以使用 -->
<template #content="chao">
<p>猫和你我都想了解</p>
<p>{{ chao.row.two }}</p>
</template>
</pannel>
</div>
</template>
<script>
import pannel from './components/pannel.vue'
export default {
components: {
pannel,
},
}
</script>注意
作用域插槽只有当前 template 可以使用。
Vue 动态组件自定义指令
除了核心功能默认内置的指令 (v-model 和 v-show), Vue 也允许注册自定义指令。
Vue 动态组件局部自定义
定义一个名为 focus 的指令,指向一个配置对象。
<div v-focus></div>
<script>
export default {
directives: {
focus: {
inserted(el,binding){
// 这里el表示被引用的标签
}
}
}
}
</script>当指令第一次被绑定到元素上时,会立即触发一次 inserted 函数。其余钩子函数如下所示:
bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新。componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。unbind:只调用一次,指令与元素解绑时调用。
形参中的 el 表示当前指令所绑定到的那个 DOM 对象, binding 可以获取指令绑定的值。其余参数如下所示:
el:指令所绑定的元素,可以用来直接操作 DOM 。binding:一个对象,包含以下 property:name:指令名,不包括v-前缀。value:指令的绑定值,例如:v-my-directive="1 + 1"中,绑定值为 2。oldValue:指令绑定的前一个值,仅在update和componentUpdated钩子中可用。无论值是否改变都可用。expression:字符串形式的指令表达式。例如v-my-directive="1 + 1"中,表达式为 "1 + 1"。arg:传给指令的参数,可选。例如v-my-directive:foo中,参数为"foo"。modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar中,修饰符对象为{ foo: true, bar: true }。
vnode:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。oldVnode:上一个虚拟节点,仅在update和componentUpdated钩子中可用。
Vue 动态组件局部自定义指令的传值
用第二个参数 binding 进行接受传递过来的参数。
<p v-color="colorStr">修改文字颜色</p>Vue.directive('color', {
inserted(el, binding) {
el.style.color = binding.value
},
})总结
全局注册自定义指令, 哪里都能用, 局部注册, 只能在当前 vue 文件里用。
Vue 动态组件局部自定义指令的注册
在自定义指令的标签注册后只执行一次 inserted 方法,后续发生改变也不会触发,因此需要新的指令 update 来监听。
Vue.directive('color', {
inserted(el) {},
update(el) {},
})后续 DOM 更新时都会触发 update 函数。
Vue 动态组件局部自定义指令的简写形式
如果 update 和 inserted 方法的代码指令一致,可以直接简写为函数的形式。
foucs(el,binging){
el.style.color = binding.value
}这样写的方式相当于 update 和 inserted 方法执行一样的指令。
Vue 动态组件全局自定义
Vue.directive('自定义名称', {
inserted(el) {
el.focus() // 触发标签的事件方法
},
})Vue 动态组件全局自定义指令的简写形式
Vue.directive("自定义名称", fucntion(el,binding) {
inserted(el) {
el.focus() // 触发标签的事件方法
}
})Vue ESLint 指令
VScode 插件满足 ESlint 规范要求。
插件一:ESlint,作者:微软 插件二:prettier,作者:prettier
打开设置 setting.json 添加配置代码
// ESlint 插件配置
"editor.codeActionsOnSave": {
"source.fixAll": true
},
"eslint.alwaysShowStatus": true,
"prettier.trailingComma": "none",
"prettier.semi": false,
// 每行文字超出限制自动换行
"prettier.singleQuote": true,
"prettier.arrowParens": "avoid",
// 设置vue文件中,html代码的格式化插件
"vetur.format.defaultFormatter.html": "js-beautify-html",
"vetur.ignoreProjectWarning": true,
"vetur.format.defaultFormatterOptions": {
"js-beautify-html": {
"wrap_attributes": false
},
"prettier": {
"trailingComma": "none",
"semi": false,
"singleQuote": true,
"arrowParens": "avoid",
"printWidth": 300
}
},