插槽
当组件的部分内容不确定,可以使用插槽作为占位,而让组件的使用者调用插槽
基本插槽
声明插槽
当组件的标签也不确定的时候,可以使用 slot 作为插槽占位
<slot> 这就是一个简单的插槽 </slot>
使用插槽
直接在使用的组件标签内部写入内容
<panel>
插槽内容填在这里
<p>
我是一个最简单的插槽
</p>
</panel>
填入的内容会将 slot 标签覆盖掉
插槽默认内容
如果 slot 默认为空的时候,页面上不会有任何关于插槽内容的显示,所以这个时候就需要使用插槽的——默认内容
<slot> 默认的内容写在这里 </slot>
如果其他的组件调用了组件,那么将会用新的内容去对 slot 标签进行覆盖
具名插槽
如果一个组件内存在有多个插槽,为了区分插槽的调用,这时候可以通过给插槽命名来区分插槽
<slot name="插槽名"></slot>
调用
具名插槽的调用只能写道 template 标签上
<tempalte v-slot:插槽名>
插槽内容
</tempalte>
插槽名的调用和声明必须一致,否则会因为插槽名不一致而不显示
作用域插槽
插槽无法通过 slot 标签正常访问到组件中的变量,需要插槽组件主动向插槽内传值
<slot :row="需要传入的值"></slot>
插槽需要主动接取数据
<tempalte v-slot="接取变量">
插槽内容
</tempalte>
此时就已经完成了插槽间的传值,传入的值是一个对象,且值为: { row:需要传入的值。。。 }
传入的值是以传值的自定义属性名作为 传入的值对象 的属性名,值就是自定义属性名的值
具名作用域插槽
同上面的,插槽需要通过 slot 标签进行传值
<slot :row="data"></slot>
而插槽也需要主动接取数据
<tempalte v-slot="scope"></tempalte>
但是具名插槽需要在 v-slot 添加名字
<template v-slot:插槽名="scope">
插槽内容
</template>
即可
循环具名插槽的传参
当循环创建组件的过程中,也需要将插槽抽离出来,而配合 v-for 来使用
<slot v-for="item in arr" :key="item.id" :row="data"></slot>
使用
<template #body="{ row: scope }">
<td>{{ scope.id }}</td>
<td>{{ scope.goods_name }}</td>
<td>{{ scope.goods_price }}</td>
<td>
<button
class="btn btn-primary btn-sm"
v-if="!scope.inputVisible"
@click="changeIsShow(scope.id)"
>
+Tag
</button>
<input
type="text"
v-if="scope.inputVisible"
@blur="scope.inputVisible = false"
ref="inp"
style="width: 100px"
v-model="scope.inputValue"
@keydown.enter="add(scope.id)"
/>
<br />
<span
style="margin-right: 5px"
class="badge bg-secondary"
v-for="(item, index) in scope.tags"
:key="index"
>
{{ item }}</span
>
</td>
<td>
<button class="btn btn-danger btn-sm" @click="remove(scope.id)">
删除
</button>
</td>
</template>
自定义指令
概念
当 Vue 内置的指令无法满足需求的时候,就需要使用自定义指定来操作
注册指令
局部注册
App.vue
export default{
//注册指令成员
directive:{
//声明指令
指令名:{
inserted(el) {
inserted 是一个钩子函数,当被添加指令的元素挂载到 DOM 树上调用
el 是 inserted 钩子函数的唯一形参,返回的就是绑定指令的元素的 DOM 对象
}
}
}
}
全局注册
main.js
Vue.directive("指令名",{
inserted(el) {
inserted 是一个钩子函数,当被添加指令的元素挂载到 DOM 树上的时候调用
el 是 inserted 钩子函数的唯一形参,返回的是被绑定元素的 DOM 对象
}
})
使用指令
直接添加前缀 v- 然后绑定到标签元素即可
<template v-自定义指令名></template>
组件进阶 Api
$refs
在 Vue 中是可以直接获取到 原生的 DOM 对象,需要配合 $refs 来使用
绑定 $refs
需要在被获取的 DOM元素 的标签上绑定 ref 属性
<div ref="绑定的属性名">
标签内容
</div>
调用绑定获取DOM
被绑定ref 的标签会被添加进 $refs 对象里面
this.$refs.被绑定的属性名
即可获取到
调用组件方法和属性
因为组件在是使用的时候也是一个标签,所以也可以通过 $refs 来获取组件对象
<panel ref="components"></panel>
获取并调用其组件的方法
this.$refs.components.fn()
console.log(this.$refs.components.data)
$nextTick
因为 在data 更新后,更新 DOM 的操作为异步操作,无法直接获取到修改后的 DOM ,所以需要使用 $nextTick 来获取 DOM 元素
$nextTick 在下一轮DOM 更新后会自动调用
this.$nextTick( ()=>{ 回调函数体 } )
为什么DOM的更新会是异步操作
因为如果 DOM 的更新是同步的操作,那么每当 data 发生更细的时候都会去更新 DOM ,为了避免频繁操作 DOM ,所以 Vue 的设计者 犹大 将DOM 的更新设计成异步操作,为的就是所有同步的data修改完毕后集中操作 DOM ,以提高性能
v-model原理
v-model 实际上就只做了两件事情
1.给标签动态绑定了一个 value 属性
2.给标签绑定了 input 事件
只要 input 事件被触发,那么就会 对 value 的值修改,然后又会把 value 的值返回给自身
这样就形成了双向的数据绑定,单向的动态属性绑定(数据驱动视图),和单向的事件绑定组合在一起形成了双工工作线