文章目录
一、V-model原理
介绍
v-model本质上是一个语法糖。例如应用在输入框上,就是value属性 和 input事件 的合写
<template>
<div id="app" >
<input v-model="msg" type="text">
<input :value="msg" @input="msg = $event.target.value" type="text">
// 等价于 <input v-model="msg" type="text">
</div>
</template>
作用
提供数据的双向绑定,即:
- 数据变,视图跟着变
:value
- 视图变,数据跟着变
@input
二、v-model简化代码
步骤
v-model其实就是 :value
和@input
事件的简写
- 子组件:
props
通过value
接收数据,事件触发input
- 父组件:
v-model
直接绑定数据
示例代码
子组件
<template>
<select :value="value" @change="handleChange">
<slot></slot>
</select>
</template>
<script>
export default {
// 父组件通过props将数据传给子组件
props: {
value: String
},
methods: {
handleChange(e) {
// 子组件通过$emit通知父组件修改更新数据
this.$emit('input', e.target.value);
}
}
};
</script>
父组件
<template>
<div>
// 通过v-model直接绑定数据
<BaseSelect v-model="selectId">
<option value="1">选项一</option>
<option value="2">选项二</option>
<option value="3">选项三</option>
</BaseSelect>
</div>
</template>
<script>
import BaseSelect from '@/components/BaseSelect.vue';
export default {
components: {
BaseSelect
},
data() {
return {
selectId: ''
};
}
};
</script>
三、.sync修饰符
作用
可以实现 子组件 与 父组件数据 的 双向绑定,简化代码,填补了v-model只能在父组件修改更新数据的缺点。
简单理解:子组件可以修改父组件传过来的props值。
场景
封装弹框类的基础组件, visible属性 true显示 false隐藏
本质
.sync
修饰符 就是 :属性名
和@update:属性名
合写
语法
父组件
//.sync写法
<BaseDialog :visible.sync="isShow" />
--------------------------------------
//完整写法
<BaseDialog
:visible="isShow"
@update:visible="isShow = $event"
/>
子组件
props: {
visible: Boolean
},
this.$emit('update:visible', false)
代码示例
父组件
<template>
<div class="app">
<button @click="openDialog">退出按钮</button>
<BaseDialog :isShow.sync="isShow" @confirm="closeTab"></BaseDialog>
</div>
</template>
<script>
import BaseDialog from './components/BaseDialog.vue'
export default {
data() {
return {
isShow: false,
}
},
components: {
BaseDialog,
},
methods: {
openDialog() {
this.isShow = true
},
closeTab() {
window.close()
}
}
}
</script>
<style>
</style>
子组件
<template>
<div class="base-dialog-wrap" v-show="isShow">
<div class="base-dialog">
<div class="title">
<h3>温馨提示:</h3>
<button class="close" @click="$emit('update:isShow', false)">x</button>
</div>
<div class="content">
<p>你确认要退出本系统么?</p>
</div>
<div class="footer">
<button @click="$emit('confirm')">确认</button>
<button @click="$emit('update:isShow', false)">取消</button>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
isShow: Boolean,
}
}
</script>
<style scoped>
.base-dialog-wrap {
width: 300px;
height: 200px;
box-shadow: 2px 2px 2px 2px #ccc;
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
padding: 0 10px;
}
.base-dialog .title {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 2px solid #000;
}
.base-dialog .content {
margin-top: 38px;
}
.base-dialog .title .close {
width: 20px;
height: 20px;
cursor: pointer;
line-height: 10px;
}
.footer {
display: flex;
justify-content: flex-end;
margin-top: 26px;
}
.footer button {
width: 80px;
height: 40px;
}
.footer button:nth-child(1) {
margin-right: 10px;
cursor: pointer;
}
</style>
四、ref和$refs
作用
利用ref
和$refs
可以用于 获取 dom 元素 或 组件实例
特点
查找的范围是当前组件内,所以其更精确稳定。
语法
1.给要获取的盒子添加ref
属性
<div ref="chartRef">我是渲染图表的容器</div>
2.获取时通过 $refs
获取 this.$refs.chartRef
获取
mounted () {
console.log(this.$refs.chartRef)
}
注意
之前只用document.querySelect('.box')
获取的是整个页面中的盒子,这使得查找到的盒子与需要查找的盒子发生冲突。
代码示例
父组件
<template>
<div class="app">
<BaseChart></BaseChart>
</div>
</template>
<script>
import BaseChart from './components/BaseChart.vue'
export default {
components:{
BaseChart
}
}
</script>
<style>
</style>
子组件
<template>
<div class="base-chart-box" ref="baseChartBox"></div>
</template>
<script>
import * as echarts from 'echarts';
export default {
mounted() {
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(this.$refs.baseChartBox);
// 绘制图表
myChart.setOption({
title: {
text: 'ECharts 入门示例',
},
tooltip: {},
xAxis: {
data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子'],
},
yAxis: {},
series: [
{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20],
},
],
});
},
};
</script>
<style scoped>
.base-chart-box {
width: 400px;
height: 300px;
border: 3px solid #000;
border-radius: 6px;
}
</style>
五、异步更新 & $nextTick
需求
当点击编辑标题, 编辑框自动聚焦
- 点击编辑,显示编辑框
- 此时,要求编辑框立刻获取焦点
<template>
<div class="app">
<div v-if="isShowEdit">
<input type="text" v-model="editValue" ref="inp" />
<button>确认</button>
</div>
<div v-else>
<span>{{ title }}</span>
<button @click="editFn">编辑</button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
title: '大标题',
isShowEdit: false,
editValue: '',
}
},
methods: {
editFn() {
// 显示输入框
this.isShowEdit = true
// 获取焦点
this.$refs.inp.focus()
}
},
}
</script>
此时,当输入框显示出来后,立刻获取输入框的焦点是失败的。因为vue是异步更新DOM的,此时,DOM并没有完成更新。
因此,想要实现功能,需要等待DOM更新完成后才能获取焦点。即:
$nextTick
:等 DOM更新后,才会触发执行此方法里的函数体
语法: this.$nextTick(函数体)
将上面代码的this.$refs.inp.focus()
更改为下面的代码即可。
this.$nextTick(() => {
this.$refs.inp.focus()
})
注意:$nextTick
内的函数体 一定是箭头函数,这样才能让函数内部的this指向Vue实例。