vue-v-model进阶-ref-nextTick
Vue-v-model进阶+ref属性+nextTick
1. v-model进阶
v-model是Vue中实现数据双向绑定的指令。双向数据绑定,数据改变,视图跟着变。反之视图改变,数据也跟着变。
1.1 v-model作用在原生标签中
1.1.1 普通写法
// v-model的普通写法
<script setup>
import { ref } from 'vue';const msg = ref("")
</script><template><div><p>{{ msg }}</p><input type="text" v-model="msg"></div>
</template>
1.1.2 原理写法
v-model本质上是一个语法糖。例如应用在输入框标签中,v-model是value属性和input事件的合写。
-
:value = "响应式数据"
-
@input = "响应式数据 = $event.target.value"
<script setup>
import { ref } from 'vue';const msg = ref("")
</script><template><div><p>{{ msg }}</p><input type="text" :value="msg" @input="msg = $event.target.value"></div>
</template>
1.2 $event
$event
是Vue提供的特殊变量。
-
如果是原生DOM事件,
$event
是原生事件对象,$event.target
是当前事件的真实DOM元素 -
如果是自定义事件(子组件通过
$emit
触发),$event
是子组件传递的参数,此时可能没有.target
属性
1.3 v-model作用在组件中
v-model除了可以用在表单元素中,还可以用在组件中,实现数据的双向绑定。
1.3.1 普通写法
在 Vue 3.4+ 中,子组件可以通过 defineModel()
接收父组件通过 v-model
传递的数据。该函数返回一个 Ref
类型的响应式数据,其初始值由父组件提供的 v-model
值决定。
子组件可以直接将该 Ref
绑定到模板中的 v-model
指令,从而实现双向数据绑定。
// App.vue
<script setup>
import { ref } from 'vue';
import SelectInput from './component/SelectInput.vue';const currentSelect = ref("BJ")
</script><template><select-input v-model="currentSelect"></select-input>
</template>// SelectInput.vue
<script setup>
const currentSelect = defineModel()
</script><template><div class="select-input-wrap"><select v-model="currentSelect"><option value="BJ">北京</option><option value="SH">上海</option><option value="GZ">广州</option><option value="SZ">深圳</option></select></div>
</template>
1.3.2 原理写法
在组件上使用 v-model
指令,其本质是通过 props 传递 modelValue 属性,并通过监听自定义事件 update:modelValue 实现双向数据绑定。
-
:modelValue = "响应式数据"
-
@update:modelValue = "响应式数据 = $event"
// App.vue
<script setup>
import { ref } from 'vue';
import SelectInput from './component/SelectInput.vue';const currentSelect = ref("BJ")
</script><template>// <select-input v-model="currentSelect"></select-input><select-input :modelValue="currentSelect" @update:modelValue="currentSelect = $event"></select-input>
</template>// SelectInput.vue
<script setup>
const props = defineProps({modelValue: String
})const emit = defineEmits(['update:modelValue'])
</script><template><div class="select-input-wrap"><select :value="props.modelValue" @change="emit('update:modelValue', $event.target.value)"><option value="BJ">北京</option><option value="SH">上海</option><option value="GZ">广州</option><option value="SZ">深圳</option></select></div>
</template>
2. ref
ref属性可以用于获取原生DOM元素或组件实例。.value
2.1 获取原生DOM元素
<script setup>
import { ref, onMounted } from 'vue';const pRef = ref(null)onMounted(() => {console.log(`output->pRef`, pRef.value)
})
</script><template><div><p ref="pRef">Hello World</p></div>
</template>
Vue会在模板渲染完成后自动更新ref的值。
2.2 获取组件实例
-
父组件为子组件绑定
ref
属性 -
子组件通过
defineExpose()
暴露给父组件方法/属性,目的是父组件可以通过ref
访问子组件的方法/属性。
// Form.vue
<script setup>const validate = () => {return Math.random() > 0.5 ? true : false
}
// 暴漏给组件, ⽬的是⽗组件可以通过 ref 可以拿到⼦组件的⽅法
defineExpose({validate
})
</script>// App.vue
<script>
import { ref } from 'vue'
import Form from './components/Form.vue' const formRef = ref(null)console.log(formRef.value.validate())
</script><template><form ref="formRef"></form>
</template>
3. nextTick
3.1 nextTick是什么?
nextTick
是Vue 提供的一个异步API,用于在DOM更新完成后执行回调。它的核心作用是确保你的代码在 Vue 完成响应式数据更新并重新渲染DOM之后再执行。
为什么需要 nextTick
?
Vue 的响应式更新是异步批量处理的。当你修改数据时,Vue 不会立即更新DOM,而是先缓存这些变更,然后在下一个事件循环中一次更新。
如果你在修改数据后立即访问DOM,可能会拿到旧的状态,这时就需要 nextTick
来确保DOM已经更新。
<script setup>
import { nextTick, ref } from 'vue'const isEidt = ref(false)
const inputRef = ref(null)
const showEidt = async () => {isEidt.value = trueawait nextTick() // 等待DOM更新inputRef.value.focus() // 操作DOM
}
</script><template><div class="box"><h3>标题</h3><button @click="showEidt">编辑</button></div><div v-if="isEidt"><input type="text" ref="inputRef"></div>
</template>
数据变化后操作DOM
解决 v-if 切换后操作DOM问题
3.2 nextTick与onMounted的区别
方法 | 执行时机 | 用途 |
---|---|---|
onMounted | 组件挂载完成后(仅一次) | 访问初始渲染后的DOM |
nextTick | 当数据改变,下一次DOM更新后(可多次调用) | 确保数据变化后的DOM已经更新 |