vue高级特性
1、自定义 v-model
<template>
<div>
<p>vue 高级特性</p>
<hr>
<!-- 自定义 v-model -->
<p>{{name}}</p>
<CustomVModel v-model="name"/>
//也可以这样写,value对应$emit第二个参数
<!-- <CustomVModel :text="name" @change1="value=>name=value"/> -->
</div>
</template>
<script>
import CustomVModel from './CustomVModel'
export default {
components: {
CustomVModel
},
data() {
return {
name: '自定义model',
}
}
}
</script>
<template>
<!-- 例如:vue 颜色选择 -->
<input type="text"
:value="text"
@input="$emit('change1', $event.target.value)"
>
<!--
1. 上面的 input 使用了 :value 而不是 v-model
2. 上面的 change1 和 model.event1 要对应起来
3. text1属性对应起来
-->
</template>
<script>
export default {
model: {
prop: 'text', // 对应 props text
event: 'change1' //对应$emit第一个参数
},
props: {
text: String,
default() {
return ''
}
}
}
</script>
提示
一个组件上的v-mode1默认会利用名为value的prop和名为input的事件,但是像单选框、复选框等类型的输入控件可能会将value attribute用于不同的目的。model选项可以用来避免这样的冲突
拓展
vue2.3.0+ 新增 .sync修饰符一样可以达到同样的效果
子组件:this.$emit('update:visible', visible), 使用update:my-prop-name 的模式触发事件
上面列子可以改为:
父组件:
<CustomVModel :text="name" @update:text="val=>name=val"></components>
//简写
<CustomVModel :text.sync="name"/>
子组件:
<input type="text" :value="text" @input="syncChang" />
methods: {
syncChang(event) {
this.$emit("update:text", event.target.value);
}
}
官方案例
2、$nextTick
说明
Vue是异步渲染,data改变之,DOM不会立刻渲染,$nextTick 会在DOM渲染之后被触发,以获取最新的DMO节点
<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()}`)
const ulElem = this.$refs.ul1
console.log( ulElem.childNodes.length )
}
}
}
</script>
如上展示,会获取不到正确的数组长度length,这个时候就的用$nextTick
addItem() {
this.list.push(`${Date.now()}`)
this.list.push(`${Date.now()}`)
this.list.push(`${Date.now()}`)
this.$nextTick(() => {
// 获取 DOM 元素
const ulElem = this.$refs.ul1
console.log( ulElem.childNodes.length )
})
}
说明
- 异步渲染,$nextTick 待 DOM 渲染完再回调
- 页面渲染时会将 data 的修改做整合,多次 data 修改只会渲染一次(也就是只会调用一个$nextTick)
3、solt插槽
作用
让父组件可以往子组件中插入一段内容(不一定是字符串,可以是其它的组件,只要是符合Vue标准的组件或者标签都可以)
3.1 默认插槽
<template>
<div>
<SlotDemo :url="website.url">
{{website.title}}
</SlotDemo>
</div>
</template>
<script>
import SlotDemo from './CustomVModel'
export default {
components: {
SlotDemo
},
data() {
return {
website: {
url: 'http://imooc.com/',
title: 'imooc',
subTitle: '程序员的梦工厂'
},
}
}
}
</script>
<template>
<a :href="url">
<slot>
默认内容,即父组件没设置内容时,这里显示
</slot>
</a>
</template>
<script>
export default {
props: ['url'],
data() {
return {}
}
}
</script>
3.2 作用域插槽
作用
让父组件可以访问到子组件的数据(算是一种组件通讯的方式)
<template>
<div>
<ScopedSlotDemo :url="website.url">
<template v-slot="slotProps">
{{slotProps.slotData.title}}
</template>
</ScopedSlotDemo>
</div>
</template>
<script>
import ScopedSlotDemo from './CustomVModel'
export default {
components: {
ScopedSlotDemo
},
data() {
return {
website: {
url: 'http://imooc.com/',
title: 'imooc',
subTitle: '程序员的梦工厂'
},
}
}
}
</script>
<template>
<a :href="url">
<slot :slotData="website">
{{website.subTitle}} <!-- 默认值显示 subTitle ,即父组件不传内容时 -->
</slot>
</a>
</template>
<script>
export default {
props: ['url'],
data() {
return {
website: {
url: 'http://wangEditor.com/',
title: 'wangEditor',
subTitle: '轻量级富文本编辑器'
}
}
}
}
</script>
讲解
子组件内部的slot标签上绑定动态数据 soltData='website' (website是 data中的数据)
在父组件调用子组件ScopedSlotDemo中 插入template ,v-slot='slotProps' (slotProps可以自定义名字)
最后就可以通过slotProps.slotData获取到子组件中的website
3.3 具名插槽
4、动态、异步组件
4.1 动态组件
说明
需要根据数据,动态渲染场景(组件类型不确定),使用
<template>
<div>
<div v-for="(val, index) in newsData": key="val.id">
<component :is="val. compnent"/>
</div>
</div>
</template>
<script>
import Text from './Text'
import Image from './Image'
import Video from './Video'
export default {
components: {
Text,
Image,
Video
},
data() {
return {
newsData:[
{
id:1,
compnent:'Text'
},
{
id:1,
compnent:'Image'
},
{
id:1,
compnent:'Video'
}
]
}
}
}
</script>
注意
即使一个组件也不能写成 (会报错)
4.2 异步组件
>作用
只有用到的时候才加载
import Text from './Text'
import Image from './Image'
import Video from './Video'
export default {
components: {
Text,
Image,
Video
},
//这些都是同步加载组件,意思就是进入这个页面不管有没有用到都会加载进来
如上图所示,还没有点击按钮显示Form组件 ,就能在文件中搜索到Form组件中的内容
接下来让我们看看异步组件
components: {
FormDemo: () => import('../BaseUse/FormDemo'),
},
//异步引入
如上图 ,一开始加载页面是搜不到Form组件内容的,只有当我没点击了按钮才加载组件文件进来
5、keep-alive
说明
频繁切换,不需要重复渲染的时候就需要使用keep-alive 缓存组件,下次使用直接拿缓存,页面不需要重新加载组件,这是Vue常见性能优化之一。
<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'"/>
<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>
A、b、c只是三个简单的组件
<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>
6、mixin
作用
多个组件有相同逻辑,就会抽离出来,使用mixn混入
例如:
index.vue
<template>
<div>
<p>{{name}} {{major}} {{city}}</p>
<button @click="showName">显示姓名</button>
</div>
</template>
<script>
import myMixin from './mixin'
export default {
mixins: [myMixin],
data() {
return {
name: '张三',
major: 'web 前端'
}
},
methods: {
},
mounted() {
console.log('component mounted', this.name)
}
}
</script>
mixin.js
export default {
data() {
return {
city: '北京'
}
},
methods: {
showName() {
console.log(this.name)
}
},
mounted() {
console.log('mixin mounted', this.name)
}
}
说明
- 上面代码运,会执行mixin.js中的钩子函数,然后在执行index.vue`中的钩子函数
- mixin.js文件中能获取index.vue中的name属性
- index.vue文件点击能触发mixin.js中的showName事件
注意
- 同个文件可以混入多个mixin,有多个混入的时候,按混入顺序依次执行mixin中的钩子函数,最后在执行文件的钩子函数
- 多个混入还会造成属性覆盖
以上内容纯属个人理解,若有不对,请回复纠正
关注【前端知识小册】,第一时间获取前端优质文章!