文章目录
- [Ⅰ. v-model的进阶使用](#Ⅰ. v-model的进阶使用)
-
- [一、v-model 的原理](#一、v-model 的原理)
- [二、v-model 用在组件上](#二、v-model 用在组件上)
- [Ⅱ. ref 属性](#Ⅱ. ref 属性)
-
- 一、获取原生DOM
- [二、调用组件实例的方法 -- `defineExpose()`](#二、调用组件实例的方法 --
defineExpose())
- [Ⅲ. nextTick()](#Ⅲ. nextTick())

Ⅰ. v-model的进阶使用
一、v-model 的原理
v-model 实际上是个语法糖,当作用在 原生输入框时,本质是 :value + @input 的组合。
javascript
<input v-model="msg"/>
<!-- 等同于 -->
<input type="text" :value="msg" @input="msg = $event.target.value">
其中 $event 是 事件对象的引用,可以用它拿到点击的元素、坐标、键盘键值等等。
二、v-model 用在组件上
v-model 除了用在表单元素上,还可以用在组件上,实现数据的双向绑定。下面以实现父组件和子组件数据的双向绑定为例:
- 父组件使用子组件时候绑定
v-model="数据" - 子组件通过一个宏
defineModel()接收数据 (注意返回值是ref,使用时候要用.value访问),子组件可以直接操作接收的数据,即可实现数据双向绑定
App.vue文件:
javascript
<script setup>
import { ref } from 'vue'
import MySelect from './components/MySelect.vue'
const activeId = ref('222')
</script>
<template>
<MySelect v-model="activeId"/>
</template>
MySelect.vue文件:
javascript
<script setup>
const model = defineModel()
</script>
<template>
<select v-model="model">
<option value="111">北京</option>
<option value="222">上海</option>
<option value="333">深圳</option>
<option value="444">杭州</option>
<option value="555">苏州</option>
</select>
</template>
defineModel本身是一个便利宏。编译器将其展开为以下内容:
- 一个名为
modelValue的属性,本地 ref 的值与其同步;- 一个名为
update:modelValue的事件,当本地 ref 的值发生变更时触发。
Ⅱ. ref 属性
ref 属性可以用于 获取原生DOM元素 或 获取组件实例。
步骤:
- 在要获取的原生DOM元素,或者组件实例标签中声明并绑定
ref属性 - 需要使用时,通过
ref.value获取
一、获取原生DOM
这里以绘制图表为例:
App.vue文件:
javascript
<template>
<MyChart />
</template>
<script setup>
import MyChart from './components2/MyChart.vue';
</script>
MyChart.vue文件:
javascript
<template>
<div class="chart-box" ref="box_ref"></div>
</template>
<script setup>
import * as echarts from 'echarts';
import { onMounted, ref } from 'vue';
const box_ref = ref(null)
onMounted(() => {
// 基于准备好的dom,初始化echarts实例
const myChart = echarts.init(box_ref.value);
// 绘制图表
myChart.setOption({
title: {
text: 'ECharts 入门示例'
},
tooltip: {},
xAxis: {
data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
},
yAxis: {},
series: [
{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}
]
});
})
</script>
<style scoped>
.chart-box {
width: 400px;
height: 300px;
margin: 100px auto;
border: 3px solid #322929;
}
</style>
二、调用组件实例的方法 -- defineExpose()
组件要想让自己的方法被外部组件拿到并且使用的话,需要调用 defineExpose() 将要暴露出去的方法进行注册 ,外部组件才能通过 ref.value 来拿到该注册的方法。
components/MyForm.vue文件:
javascript
<script setup>
// 表单校验
const validate = () => {
return Math.random() > 0.5 ? true : false
}
// 需要暴露给组件, 目的是父组件可以通过 ref 可以拿到子组件的方法
defineExpose({
validate
})
</script>
<template>
<div class="login-box">
账户:<input type="text" /><br /><br />
密码:<input type="password" /><br /><br />
</div>
</template>
App.vue文件:
javascript
<template>
<MyForm ref="form_ref"/>
<button @click="loginUp">登录</button>
</template>
<script setup>
import { ref } from 'vue';
import MyForm from './components3/MyForm.vue';
const form_ref = ref(null)
const loginUp = () => {
if(form_ref.value.validate() === true) {
console.log("登录成功");
} else {
console.log("登录失败");
}
}
</script>
Ⅲ. nextTick()
作用:等 DOM 更新后,才会触发执行此方法里的函数体,此时不会出现拿到空的 DOM 的情况。
因为 vue 为了提高效率,在更新 DOM 的时候是异步操作。
下面举个例子,代码需求:
- 点击编辑,显示编辑框
- 让编辑框,立刻获取焦点

javascript
<template>
<div>
<span>{{ text }}</span>
<button @click="edit">编辑</button>
</div>
<div v-if="isInput">
<input type="text" ref="input_ref" v-model="input_text"></input>
<button @click="text = input_text; isInput = !isInput">确认</button>
</div>
</template>
<script setup>
import { nextTick, ref } from 'vue';
const text = ref('大标题')
const isInput = ref(false) // true表示显示输入框
const input_text = ref('') // 输入框内容
const input_ref = ref(null) // 输入框实例
const edit = () => {
isInput.value = !isInput.value;
if(isInput.value === true) {
// 在nextTick()中完成输入框的聚焦,保证拿到的输入框实例不为null
nextTick(() => {
input_ref.value.focus()
})
}
}
</script>
