【Vue】v-model进阶 && ref && nextTick

文章目录

  • [Ⅰ. 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 除了用在表单元素上,还可以用在组件上,实现数据的双向绑定。下面以实现父组件和子组件数据的双向绑定为例:

  1. 父组件使用子组件时候绑定 v-model="数据"
  2. 子组件通过一个宏 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元素 或 获取组件实例。

步骤:

  1. 在要获取的原生DOM元素,或者组件实例标签中声明并绑定 ref 属性
  2. 需要使用时,通过 ref.value 获取

一、获取原生DOM

ECharts引入项目

这里以绘制图表为例:

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 的时候是异步操作。

下面举个例子,代码需求:

  1. 点击编辑,显示编辑框
  2. 让编辑框,立刻获取焦点
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>
相关推荐
eidnxndrdkdns10 小时前
PE 自校验的三个坑:恒失败、基址变化、以及被漏在外面的检测器
前端
90后的晨仔10 小时前
解决 Android 构建报错:Unable to delete file .../file-map.txt
android·前端
Yuhano11 小时前
W4. RAG 让 Agent 拥有"外部记忆"
前端·aigc
用户308169987648511 小时前
gzip 和 br 压同一份 JSON:7.6MB 压到 175KB,差 3.8 倍
前端
掘金者阿豪11 小时前
电商视觉要被 Agent 重做了:一个平台跑通主图、详情页、实拍、复刻和视频
前端
爱勇宝11 小时前
《道德经》第 13 章:别让评价系统控制你的心
前端·后端·产品
掘金者阿豪11 小时前
集中式与分布式数据库怎么选?从架构原理到电科金仓的实践思考
前端·后端
codeejun11 小时前
每日一Go·MySQL-11、覆盖索引 & 回表原理
javascript·数据库·mysql
墨林陌11 小时前
AI 热点日报(2026-11-06):乌镇峰会闭幕发布全球开源AI倡议,腾讯混元Hy4发布即开源
前端
用户2986985301412 小时前
React 前端将 Excel 工作表导出为图片的技术实践
javascript·react.js·excel