【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>
相关推荐
IT_陈寒2 分钟前
Vite的HMR怎么突然失效了?原来是我太年轻
前端·人工智能·后端
ZC跨境爬虫7 分钟前
Apple官网复刻第二阶段day_6:(统一页脚模块封装+CSS公共复用体系落地)
前端·css·ui·重构·html
恋猫de小郭10 分钟前
Flutter 凉了没?Flutter 2026 的未来行程和规划,一些有趣的变化
android·前端·flutter
Beginner x_u12 分钟前
前端手动实现大文件分片上传调度层:分片计算、并发上传与断点续传
前端·状态模式·断点续传·大文件分片上传
胖纳特17 分钟前
Nextcloud 文件预览困局与破局:集成 BaseMetas Fileview 实现全格式在线预览
前端·后端
一个心烑17 分钟前
Layui结合springboot读取返回值,前端展示简单示例
前端·spring boot·layui
天天向上102417 分钟前
openlayers 加载Shapefile文件
前端·javascript·html
亿元程序员20 分钟前
手工拼豆有风险?手把手教你开发个电子版的
前端
wuxianda103022 分钟前
苹果App上架4.3a问题3天解决方案汇报总结
开发语言·javascript·uni-app·ecmascript·ios上架·苹果上架
hhhhhh_we24 分钟前
再定义“皮肤人格”:从Baumann 16型分型到预颜美历的AI时序人格
前端·图像处理·人工智能·python·aigc