• 技术文章 >web前端 >Vue.js

    浅析Ref操作Dom在Vue2.x和Vue3.x的不同

    青灯夜游青灯夜游2023-01-27 05:30:01转载78

    Ref操作Dom为何既易用又高效?下面本篇文章带大家聊聊Ref操作,介绍一下Ref获取Dom的本质、其在Vue2.x和Vue3.x的不同等,希望对大家有所帮助!

    在开发一个项目之前,我们往往都是先做下需求分析,针对前端而言,就是可以调研或者选择一个基础组件库,来提高我们的工作效率。毕竟,对比较计较时间成本的公司来说,不会给你拿看电视剧玩游戏的时间去专门开发一个类似日历的组件。但在市面上的组件库,并不能都能满足我们的需求。这个时候,我们就需要自己手写组件,来应用到项目中。

    而这就是我想说的: 如何设计组件,让其既能易于应用(或者说减少代码量),又能提高扩展性,方便需求变更和后续维护?

    可以有很多种方式,而利用Ref操作Dom的特性随是其中之一,但这个方式却让我们在维护和操作Modal、Popup以及频繁操作Dom显示和隐藏交互的组件的时候,却发挥得很大优势。【相关推荐:vuejs视频教程web前端开发

    就对Ref操作Dom的相关知识点以及应用实例分几个方面来做下剖析

    详说

    Ref获取Dom的本质

    Vue2.x中Vue的对象属性$refs,其实就是所有注册过的ref的一个集合,而ref对应着template模版中,不同组件或普通Dom元素上关联的ref="xx"; 源码中ref的实际获取方式也是通过原生方式getElementById而得到的Dom节点;可以说ref是document.getElementById的语法糖。vue3的ref延续了vue2的用法,还增加了一个作用就是创建响应式数据

    也许有人会问了,既然ref和getElementById都能获取到Dom,那么在项目开发中,我选择哪种方式都没什么区别呢?

    关于这个问题,经过数据表明,$refs相对document.getElementById的方法,会减少获取dom节点的消耗;而具体原因,等下一篇文章再详细探讨。

    Ref操作Dom在Vue2.x和Vue3.x的不同

    Vue2.x

    我们只需要在相应的Dom元素或者组件加上ref="xx"属性,然后在Vue对象中使用this.$refs.xx,就可以直接获取到该Dom并操作其方法属性,

    <user-and-dep-tree-select-modal
      ref="avaUserTreeSelect"
      title="選擇可見範圍"
      :project-id="currentProjectId"
      :visible.sync="avaUserModalVisible"
      @ok="editAvailableUser"
    />
    或者
    <div class="user" ref="user">dd</div>
    // $refs
    showManagerModal () {
      this.$refs.avaUserTreeSelect.showModal(this.form.managers)
      console.log(this.$refs.user.text)
    },

    Vue3.2

    在Vue3.2版本使用的方式

    //普通Dom
    <div class="user" ref="user"></div>
    //组件
    <batch-adjust-department-modal ref="batchAdjustDepartmentRef" />
    <script setup>
    import { ref } from 'vue';
    // modal调整部门弹层Dom
    const batchAdjustDepartmentRef = ref(null);
    const user = ref(null);
    </script>

    也许这里有人疑问,为什么声明了一个和template的ref中同名的常量变量就绑定了对应的dom? 在这里再补充说明一下:

    <script>
    import { defineComponent, ref } from 'vue'
    
    export default defineComponent({
      name: 'HelloWorld',
      setup(props, ctx) {
        const count = ref(0)
        function add() {
          count.value++
        }
        // 使用return {} 把变量、方法暴露给模板
        return {
          count,
          add,
        }
      },
    })
    </script>

    所以在<script setup>中声明的变量会自动被加到该Vue对象的本身this中,如

    <script setup><script>
    const user = ref(null);this.$ref.user

    Ref操作组件Dom和父子组件单向传递

    props父传子,子通过emits传父,这样单方向传递,在控制弹层组件的显示和隐藏方面也可以实现,但是如此一来,我们就会像下面一样 父组件

    <template>
      <exchange-valid-modal-vue v-model:visible="visibleExchange" />
    </template>
    <script setup>
    // 转让管理员组件
    import ExchangeValidModalVue from './modal/ExchangeValidModal.vue';
    // modal弹层
    const visibleExchange = ref(false); // 转让管理员可视化
    const onExchangeAdmin = () => {
      visibleExchange.value = true;
    };
    </script>

    子组件ExchangeValidModalVue.vue

    <template>
        <t-dialog
          v-model:visible="visibleExchange"
          header="转让主管理员"
          attach="body"
          width="384px"
          :confirm-on-enter="true"
          :on-close="onCloseExchange"
        />
    </template>
    <script setup>
    const visibleExchange = ref(false);
    const props = defineProps({
      data: {
        type: Object,
        default: () => {},
      },
      visible: {
        type: Boolean,
        default: false,
      },
    });
    watch(
      () => props.visible,
      (cur, pre) => {
        visibleExchange.value = cur;
        if (cur) {
          firstTag.value = 1;
        }
      },
    );
    watch(
      () => visibleExchange.value,
      (cur, pre) => {
        emits('update:visible', cur);
      },
    );
    </script>

    从代码里面我们就可以发现通过用父子组件单向传递的方式去实现一个组件的显示和隐藏功能,我们需要如此费劲地声明多个变量,还要做两次监听,万一后面不止一个这样的参数进行传递,那么代码量可想而知,而且也不易维护。

    其实显示和隐藏的功能可以直接在内部中进行值的响应即可,并不需要在父级别中操作,如下将上面代码改变一下:

    子组件ExchangeValidModalVue.vue

    <template>
        <t-dialog
          v-model:visible="visible"
          header="转让主管理员"
          attach="body"
          width="384px"
          :confirm-on-enter="true"
          :on-close="onCloseExchange"
        />
    </template>
    <script setup>
    import { ref } from 'vue';
    const visible = ref(false);
    const emits = defineEmits(['call']);
    const onEmitSelectSuperiod = () => { // 省略
      emits('call');
    };
    const onOpen = () => {
      visible.value = true;
    };
    const onClose = () => {
      visible.value = false;
    };
    
    defineExpose({
      onOpen,
      onClose,
    });
    </script>

    那么在父组件中,我们只需要通过ref得到该组件Dom,然后操作Dom内部的方法即可;

    如:父组件改写

    <template>
      <exchange-valid-modal-vue ref="exchangeRef" />
    </template>
    <script setup>
    // 转让管理员组件
    import ExchangeValidModalVue from './modal/ExchangeValidModal.vue';
    // modal弹层
    const exchangeRef = ref(null); // 转让管理员可视化
    const onExchangeOpen = () => {
       exchangeRef.onOpen() // 直接操作dom里defineExpose暴露出来的方法
    };
    </script>

    如此,是不是比父子单向数据传递的方式更加高效易用?当然上面所说的只是我举的一个例子,当后续需要在组件内扩展功能也可按类似的方法代替单向数据流的方式扩展

    但,请注意;这种操作dom方式,并不是什么场景下都是最佳的选择;我们可以分情况选择,比如当一些数据只需要在子组件的范畴中实现,而不需要父组件外加干涉的情况下,选择ref操作dom更为高效;

    补充知识点:

    defineExpose

    在 Vue3.2 中,默认不会暴露任何在 <script setup> 中声明的绑定,即不能通过模板 ref 获取到组件实例声明的绑定。

    Vue3.2 提供了 defineExpose 编译器宏,可以显式地暴露需要暴露的组件中声明的变量和方法

    (学习视频分享:vuejs入门教程编程基础视频

    以上就是浅析Ref操作Dom在Vue2.x和Vue3.x的不同的详细内容,更多请关注php中文网其它相关文章!

    声明:本文转载于:掘金社区,如有侵犯,请联系admin@php.cn删除
    专题推荐:前端 Vue.js
    上一篇:图文详解Vue3实现全局搜索框步骤(附代码) 下一篇:自己动手写 PHP MVC 框架(40节精讲/巨细/新人进阶必看)

    相关文章推荐

    • 解析Vue2实现composition API的原理• .vue格式文件用什么软件打开• vue的内置指令有哪些构成• vue路由有哪几种模式有什么区别• 图文详解Vue3实现全局搜索框步骤(附代码)• 在命令行执行命令什么表示初始化vue项目
    1/1

    PHP中文网