Vue
刀刀
3/20/2025
0 字
0 分钟
动态组件
动态组件基本概念
作用
可以让多个组件使用同一个挂载点,并动态切换。 component
本质上是一个占位符,通过 :is
属性来指定渲染谁。
语法
<component :is="vue变量"></component>
例子
创建两个子组件。
子组件1:
<template>
<div>
用户名:<input type="text">
密码:<input type="text">
</div>
</template>
复制代码
子组件2:
<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
中设置了子组件的变量名,点击按钮改变子组件从而实现动态组件的效果。
组件缓存
动态组件频繁切换会导致频繁销毁和创建组件,不利于提高性能。因此在组件创建出来之后将其缓存起来不被销毁,需要的时候就能使用。
语法
用 keep-alive
将其包裹即可。
<keep-alive>
<component :is="vue变量名"></component>
</keep-alive>
总结:
keep-alive
可以把内部的组件进行缓存而非销毁,内部包裹的标签不会被销毁和重新创建,因此能够提高组件的性能。
生命周期补充
组件被缓存起来后钩子函数不会再触发,想要判断某个组件当前是显示还是隐藏状态,需要用到 actived
和 deactivated
这两个钩子。
actived
:当前组件显示状态。当组件被激活的时候会自动触发这个生命周期函数。deactived
:当前组件隐藏状态。当组件被缓存的时候会自动触发这个生命周期函数。
被缓存的组件不再创建和销毁,也就意味着钩子函数 created
和销毁函数只会触发一次,为了能得知此时组件是否是显示状态,可以通过新的钩子判断其是否被激活。
总结:
当组件第一次被创建的时候,既会触发
created
生命周期,也会触发actived
生命周期。而组件被激活的时候,只会触发actived
生命周期,而不触发created
生命周期。
include
属性
用来指定:只有名称匹配的组件会被缓存,多个组件名之间使用英文逗号分隔。
相反的,指定 exinclude
可用来指定被匹配的组件不会被缓存。
注意:
二者只能选其一来使用,不能一起使用。
组件注册与组件声明的区别
- 组件注册 组件注册指在a组件中引入b组件时设置的名称,主要应用场景:把注册好的组件渲染到页面上。
- 组件声明 组件声明指创建好了组件后为其设置一个
name
属性,主要应用场景:结合keep-alive
标签实现组件缓存功能,以及在调试工具中看到组建的name
名称。
解析 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>
插槽
含义
作用
用于实现组件的内容分发, 通过 slot
标签, 可以接收到写在组件标签内的内容。
vue中不仅组件可以动态改变,标签也可以动态改变,提供组件插槽能力, 允许开发者在封装组件时,把不确定的部分定义为插槽。
语法
子组件中:使用以下代码,作用是占位
<slot></slot>
父组件中:插入以下代码,把动态的标签写入其中即可。
<子组件名称></子组件名称>
例子
子组件中,生成一个骨架,把会变化的部分用占位符替换。
<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>
作用域
如果在插槽中想要使用变量或方法,例如:
<navigation-link url="/profile">
<div @click="click">Logged in as {{ user.name }}</div>
</navigation-link>
该插槽跟模板的其它地方一样可以访问相同的实例 property (也就是相同的“作用域”),而不能访问 <navigation-link>
的作用域。
父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。
默认内容
如果调用者不传值, 有默认内容就会显示默认内容,默认内容添加在 slot
标签内。
语法
<slot>默认内容</slot>
具名插槽
当一个组件内有2处以上需要外部传入标签的插槽,可以为每个插槽添加名字加以区分。
语法
<slot name="自定义名字"></slot>
默认情况下,在使用组件的时候,提供的内容都会被填充到名字为 default
的插槽中.
- 如果要把内容填充到指定名称的插槽中,需要使用
v-slot
这个指令. v-slot
:后面要跟上插槽的名字.v-slot
:指令不能直接作用在元素身上,必须用在template
标签上.template
:这个标签是一个虚拟标签,只起到包裹性质的作用,并不会被实际渲染成html元素.
在组件内添加 template
标签,结合 v-slot
或其简写形式 #
进行具名区分。
例子
子组件中定义两个具名插槽。
<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>
作用域插槽
子组件里的值,给插槽赋值,在父组件环境下使用。
语法
<slot :自定义名称="子组件内的值"></slot>
使用
父组件中用 template
和 v-slot="自定义变量名"
来使用。变量名会收集slot身上属性和值形成对象。
<template v-slot="scope">
<p>{{ scope.自定义名称.子组件内的值 }}</p>
</template>
推荐名称使用 scope
,但想起啥都无所谓。
例子
子组件内定义一个作用域插槽,把对象传过去。
<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
可以使用。
自定义指令
除了核心功能默认内置的指令 (v-model
和 v-show
),Vue 也允许注册自定义指令。
局部自定义
定义一个名为focus的指令,指向一个配置对象。
<div v-focus></div>
directives: {
focus: {
inserted(el,binding){
// 这里el表示被引用的标签
}
}
}
当指令第一次被绑定到元素上时,会立即触发一次 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
钩子中可用。
传值
用第二个参数 binding
进行接受传递过来的参数。
<p v-color="colorStr">修改文字颜色</p>
Vue.directive('color', {
inserted(el, binding) {
el.style.color = binding.value
},
})
总结: 全局注册自定义指令, 哪里都能用, 局部注册, 只能在当前
vue
文件里用。
注册
在自定义指令的标签注册后只执行一次 inserted
方法,后续发生改变也不会触发,因此需要新的指令 update
来监听。
Vue.directive('color', {
inserted(el) {
},
update(el) {
}
})
后续 dom
更新时都会触发 update
函数。
简写形式
如果 update
和 inserted
方法的代码指令一致,可以直接简写为函数的形式。
foucs(el,binging){
el.style.color = binding.value
}
这样写的方式相当于 update
和 inserted
方法执行一样的指令。
全局自定义
在 main.js
文件中使用。
Vue.directive("自定义名称", {
inserted(el) {
el.focus() // 触发标签的事件方法
}
})
复制代码
简写形式
Vue.directive("自定义名称", fucntion(el,binding) {
inserted(el) {
el.focus() // 触发标签的事件方法
}
})
复制代码
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
}
},