自定义v-model
v-model实际上是语法糖:
<input type="text" v-model="test" />
// 就是相当于:
<input type="text"
:value="test"
@input="test= $event.target.value" />
案例:
<!-- 子组件 -->
<template>
<!-- 例如:vue 颜色选择 -->
<input type="text"
:value="text1"
@input="$emit('change1', $event.target.value)"
>
<!--
1. 上面的 input 使用了 :value 而不是 v-model
2. 上面的 change1 和 model.event1 要对应起来
3. text1 属性对应起来
-->
</template>
<script>
export default {
model: {
prop: 'text1', // 对应 props text1
event: 'change1'
},
props: {
text1: String,
default() {
return ''
}
}
}
</script>
<template>
<div>
<p>{{name}}</p>
<CustomVModel v-model="name"/>
</div>
</template>
<script>
import CustomVModel from './CustomVModel'
export default {
components: {
CustomVModel
},
data() {
return {
name: 'yong',
}
}
}
</script>
$nextTick异步渲染
$nextTick会在DOM渲染之后被触发,以获取最新的DOM节点
案例:
<template>
<div id="app">
<ul ref="ul1">
<li v-for="(item, index) in list" :key="index">
{{item}}
</li>
</ul>
<button @click="addItem">添加一项</button>
</div>
</template>
<script>
export default {
name: 'app',
data() {
return {
list: ['a', 'b', 'c']
}
},
methods: {
addItem() {
this.list.push(`${Date.now()}`)
this.list.push(`${Date.now()}`)
this.list.push(`${Date.now()}`)
// 1. 异步渲染,$nextTick 待 DOM 渲染完再回调
this.$nextTick(() => {
// 获取最新的DOM 元素
const ulElem = this.$refs.ul1
// eslint-disable-next-line
console.log( ulElem.childNodes.length )
})
}
}
}
</script>
slot插槽
默认插槽
<!-- 子组件 -->
<template>
<a :href="url">
<slot>
默认内容,即父组件没设置内容时,这里显示
</slot>
</a>
</template>
<script>
export default {
props: ['url'],
data() {
return {}
}
}
</script>
<!-- 父组件 -->
<SlotDemo :url="website.url">
{{website.title}} // 有值就显示值,没值就显示默认内容
</SlotDemo>
作用域插槽
获取子组件的插槽值
<!-- 子组件 -->
<template>
<a :href="url">
<slot :slotData="website">
{{website.subTitle}} <!-- 默认值显示 subTitle ,即父组件不传内容时 -->
</slot>
</a>
</template>
<script>
export default {
props: ['url'],
data() {
return {
website: {
url: 'http://Editor.com/',
title: 'Editor',
subTitle: '轻量级富文本编辑器'
}
}
}
}
</script>
<!-- 父组件 -->
<ScopedSlotDemo :url="website.url">
<template v-slot="slotProps">
{{slotProps.slotData.title}} // 获取子组件中的插槽数据Editor
</template>
</ScopedSlotDemo>
在element-ui中使用v-slot="scope",可以拿到scope.row当前行的数据
v-slot="scope"只能用于template和组件标签
<el-table-column label="状态">
<!-- 作用域插槽拿到当前行的数据 -->
<template v-slot="scope">
<el-switch
v-model="scope.row.mg_state"
active-color="#13ce66"
inactive-color="#DCDFE6"
@change="userStateChanged(scope.row)"
>
</el-switch>
</template>
</el-table-column>
具名插槽
多个插槽,通过命名来区分
// 子组件
<template>
<div class="slottwo">
<div>slottwo</div>
<slot name="header"></slot>
<slot></slot>
<slot name="footer"></slot>
</div>
</template>
<!-- 父组件 -->
<template>
<div>
<slot-two>
<p>123456</p>
<template slot="header">
<p>我是name为header的slot</p>
</template>
<p slot="footer">我是name为footer的slot</p>
</slot-two>
</div>
</template>
没有对应值的其他内容会被放到子组件中没有添加name属性的slot中,所以123456被加在了中间
异步组件
用的时候再加载,不用不加载,按需加载,异步加载大组件
<template>
<div>
<FormDemo v-if="showFormDemo"/>
<button @click="showFormDemo = true">show form demo</button>
</div>
</template>
<script>
components: {
FormDemo: () => import('../BaseUse/FormDemo')
},
data() {
return {
showFormDemo: false
}
}
</script>
keep-alive组件缓存
<template>
<div>
<button @click="changeState('A')">A</button>
<button @click="changeState('B')">B</button>
<button @click="changeState('C')">C</button>
<keep-alive> <!-- tab 切换 -->
<KeepAliveStageA v-if="state === 'A'"/> <!-- v-show -->
<KeepAliveStageB v-if="state === 'B'"/>
<KeepAliveStageC v-if="state === 'C'"/>
</keep-alive>
</div>
</template>
<script>
import KeepAliveStageA from './KeepAliveStateA'
import KeepAliveStageB from './KeepAliveStateB'
import KeepAliveStageC from './KeepAliveStateC'
export default {
components: {
KeepAliveStageA,
KeepAliveStageB,
KeepAliveStageC
},
data() {
return {
state: 'A'
}
},
methods: {
changeState(state) {
this.state = state
}
}
}
</script>
// 其中一个组件,其他都是一样
<template>
<p>state A</p>
</template>
<script>
export default {
mounted() {
// eslint-disable-next-line
console.log('A mounted')
},
destroyed() {
// eslint-disable-next-line
console.log('A destroyed')
}
}
</script>
如果不加<keep-alive>,则不会缓存,每次切换都有执行加载销毁
用keep-alive包起来实现组件缓存
<keep-alive> <!-- tab 切换 -->
<KeepAliveStageA v-if="state === 'A'"/> <!-- v-show -->
<KeepAliveStageB v-if="state === 'B'"/>
<KeepAliveStageC v-if="state === 'C'"/>
</keep-alive>
如果里面有不需要缓存的:
// 将不需要缓存的名字加上去
<keep-alive exclude="Profile,User">
<router-view/>
</keep-alive>