• 一个 Java 猿眼中 Vue3 和 Vue2 的差异


    随着 TienChin 项目视频的录制,松哥终于也要静下心来,认真捋一捋 Vue3 中的各种新特性了,然后再和小伙伴们进行分享,其实 Vue3 中还是带来了很多新鲜的玩意,今天我们就不卷 Java 了,来卷卷前端。

    以下内容是一个 Java 猿对 Vue3 的理解,主要是应用层面上,如果有专业的前端小伙伴,请轻拍。

    1. script 写法

    进入到 Vue3 时代,最明显的感受就是在一个 .vue 文件中,script 标签的写法大变样了。以前在 Vue2 中,我们都是这样写的:

    <script>
        export default {
            name: "SysHr",
            data() {
                return {
                    //
                }
            },
            mounted() {
                //
            },
            methods: {
                deleteHr(hr) {
                    //
                },
                doSearch() {
                    //
                }
            }
        }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    不过到了 Vue3 里边,这个写法变了,变成下面这样了:

    <template>
        <div>
            <div>{{a}}</div>
            <div>{{result}}</div>
            <button @click="btnClick">clickMe</button>
        </div>
    </template>
    <script>
    
        import {ref} from 'vue';
        import {onMounted,computed} from 'vue'
    
        export default {
            name: "MyVue01",
            setup() {
                const a = ref(1);
                const btnClick=()=>{
                    a.value++;
                }
                onMounted(() => {
                    a.value++;
                });
                const result = computed(()=>{
                    return Date.now();
                });
                return {a,btnClick,result}
            }
        }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    先从大的方面来看,细节实现咱们后面再细聊。

    大的方面,就是在这个 export default 中,以后就只有两个元素了,name 和 setup,我们以前的各种方法定义、生命周期函数、计算属性等等,都写在 setup 中,并且需要在 setup 中返回,setup 中返回了什么,上面的 template 中就能用什么。

    这种写法稍微有点费事,所以还有一种简化的写法,像下面这样:

    <template>
        <div>
            <div>{{a}}</div>
            <div>{{result}}</div>
            <button @click="btnClick">clickMe</button>
        </div>
    </template>
    
    <script setup>
    
        import {ref} from 'vue';
        import {onMounted, computed} from 'vue'
    
        const a = ref(1);
        const btnClick = () => {
            a.value++;
        }
        onMounted(() => {
            a.value++;
        });
        const result = computed(() => {
            return Date.now();
        });
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    这种写法就是直接在 script 标签中加入 setup,然后在 script 标签中该怎么定义就怎么定义,也不用 return 了。这个场景,又有点 jQuery 的感觉了。

    上面这个实现里有几个细节,我们再来详细说说。

    2. 生命周期

    首先就是生命周期函数的写法。

    以前 Vue2 里的写法有一个专业名词叫做 options API,现在在 Vue3 里也有一个专业名词叫做 composition API。在 Vue3 中,这些对应的生命周期函数都要先从 vue 中导出,然后调用并传入一个回调函数,像我们上一小节那样写。

    下图这张表格展示了 options API 和 composition API 的一一对应关系:

    options APIcomposition API
    beforeCreateNot Needed
    createdNot Needed
    mountedonMounted
    beforeUpdateonBeforeUpdate
    updatedonUpdated
    beforeUnmountonBeforeUnmount
    unmountedonUnmounted
    errorCapturedonErrorCaptured
    renderTrackedonRenderTracked
    renderTriggeredonRenderTriggered
    activatedonActivated
    deactivatedonDeactivated

    想用哪个生命周期函数,就从 vue 中导出这个函数,然后传入回一个回调就可以使用了。例如第一小节中松哥给大家举的 onMounted 的用法。

    3. 计算属性

    除了生命周期函数,计算属性、watch 监听等等,用法也和生命周期函数类似,需要先从 vue 中导出,导出之后,也是传入一个回调函数就可以使用了。上文有例子,我就不再啰嗦了。

    像 watch 的监控,写法如下:

    <script>
    
        import {ref} from 'vue';
        import {onMounted,computed,watch} from 'vue'
    
        export default {
            name: "MyVue01",
            setup() {
                const a = ref(1);
                const btnClick=()=>{
                    a.value++;
                }
                onMounted(() => {
                    a.value++;
                });
                const result = computed(()=>{
                    return Date.now();
                });
                watch(a,(value,oldValue)=>{
                    console.log("value", value);
                    console.log("oldValue", oldValue);
                })
                return {a,btnClick,result}
            }
        }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    导入 watch 之后,然后直接使用即可。

    4. ref 于 reactive

    上面的例子中还有一个 ref,这个玩意也需要跟大家介绍下。

    在 Vue2 里边,如果我们想要定义响应式数据,一般都是写在 data 函数中的,类似下面这样:

    <script>
        export default {
            name: "SysHr",
            data() {
                return {
                    keywords: '',
                    hrs: [],
                    selectedRoles: [],
                    allroles: []
                }
            }
        }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    但是在 Vue3 里边,你已经看不到 data 函数了,那怎么定义响应式数据呢?就是通过 ref 或者 reactive 来定义了。

    在第一小节中,我们就是通过 ref 定义了一个名为 a 的响应式变量。

    这个 a 在 script 中写的时候,有一个 value 属性,不过在 HTML 中引用的时候,是没有 value 的,可千万别写成了 {{a.value}},我们再来回顾下上文的案例:

    <template>
        <div>
            <div>{{a}}</div>
            <button @click="btnClick">clickMe</button>
        </div>
    </template>
    
    <script>
    
        import {ref} from 'vue';
    
        export default {
            name: "MyVue04",
            setup() {
                const a = ref(1);
                const btnClick=()=>{
                    a.value++;
                }
                return {a,btnClick}
            }
        }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    现在就是通过这样的方式来定义响应式对象,修改值的时候,需要用 a.value,但是真正的上面的 template 节点中访问的时候是不需要 value 的(注意,函数也得返回后才能在页面中使用)。

    和 Vue2 相比,这种写法有一个很大的好处就是在方法中引用的时候不用再写 this 了。

    ref 一般用来定义原始数据类型,像 String、Number、BigInt、Boolean、Symbol、Null、Undefined 这些。

    如果你想定义对象,那么可以使用 reactive 来定义,如下:

    <template>
        <div>
            <div>{{a}}</div>
            <button @click="btnClick">clickMe</button>
            <div>{{book.name}}</div>
            <div>{{book.author}}</div>
        </div>
    </template>
    
    <script>
    
        import {ref, reactive} from 'vue';
    
        export default {
            name: "MyVue04",
            setup() {
                const a = ref(1);
                const book = reactive({
                    name: "三国演义",
                    author: "罗贯中"
                });
                const btnClick = () => {
                    a.value++;
                }
                return {a, btnClick,book}
            }
        }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    这里定义了 book 对象,book 对象中包含了 name 和 author 两个属性。

    有的时候,你可能批量把数据定义好了,但是在访问的时候却希望直接访问,那么我们可以使用数据展开,像下面这样:

    <template>
        <div>
            <div>{{a}}</div>
            <button @click="btnClick">clickMe</button>
            <div>{{name}}</div>
            <div>{{author}}</div>
        </div>
    </template>
    
    <script>
    
        import {ref, reactive} from 'vue';
    
        export default {
            name: "MyVue04",
            setup() {
                const a = ref(1);
                const book = reactive({
                    name: "三国演义",
                    author: "罗贯中"
                });
                const btnClick = () => {
                    a.value++;
                }
                return {a, btnClick,...book}
            }
        }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    这样,在上面访问的时候,就可以直接访问 name 和 author 两个属性了,就不用添加 book 前缀了。

    不过!!!

    这种写法其实有一个小坑。

    比如我再添加一个按钮,如下:

    <template>
        <div>
            <div>{{a}}</div>
            <button @click="btnClick">clickMe</button>
            <div>{{name}}</div>
            <div>{{author}}</div>
            <button @click="updateBook">更新图书信息</button>
        </div>
    </template>
    
    <script>
    
        import {ref, reactive} from 'vue';
    
        export default {
            name: "MyVue04",
            setup() {
                const a = ref(1);
                const book = reactive({
                    name: "三国演义",
                    author: "罗贯中"
                });
                const btnClick = () => {
                    a.value++;
                }
                const updateBook=()=>{
                    book.name = '123';
                }
                return {a, btnClick,...book,updateBook}
            }
        }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    这个时候点击更新按钮,你会发现没反应!因为用了数据展开之后,响应式就失效了。所以,对于这种展开的数据,应该再用 toRefs 来处理下,如下:

    <template>
        <div>
            <div>{{a}}</div>
            <button @click="btnClick">clickMe</button>
            <div>{{name}}</div>
            <div>{{author}}</div>
            <button @click="updateBook">更新图书信息</button>
        </div>
    </template>
    
    <script>
    
        import {ref, reactive, toRefs} from 'vue';
    
        export default {
            name: "MyVue04",
            setup() {
                const a = ref(1);
                const book = reactive({
                    name: "三国演义",
                    author: "罗贯中"
                });
                const btnClick = () => {
                    a.value++;
                }
                const updateBook = () => {
                    book.name = '123';
                }
                return {a, btnClick, ...toRefs(book),updateBook}
            }
        }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    当然,如果你将 setup 直接写在了 script 标签中,那么可以直接按照如下方式来展开数据:

    <template>
        <div>
            <div>{{a}}</div>
            <button @click="btnClick">clickMe</button>
            <div>{{name}}</div>
            <div>{{author}}</div>
            <button @click="updateBook">更新图书信息</button>
        </div>
    </template>
    
    <script setup>
    
        import {ref, reactive, toRefs} from 'vue';
    
        const a = ref(1);
        const book = reactive({
            name: "三国演义",
            author: "罗贯中"
        });
        const btnClick = () => {
            a.value++;
        }
        const updateBook = () => {
            book.name = '123';
        }
        const {name, author} = toRefs(book);
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    5. 小结

    好啦,今天就和小伙伴们分享了 Vue3 中几个新鲜的玩法~作为我们 TienChin 项目的基础(Vue 基本用法在 vhr 中都已经讲过了,所以这里就不再赘述了),当然,Vue3 和 Vue2 还有其他一些差异,这些我们都将在 TienChin 项目视频中和小伙伴们再仔细分享。

  • 相关阅读:
    网工内推 | 上市公司,云平台运维,IP认证优先,13薪
    android 5.1 BatteryManager深入分析
    word中设置页眉,首页不设置
    MySQL MHA高可用切换
    MapReduce 排序三种实现方式
    【字符串】重新格式化字符串
    武汉凯迪正大—断路器特性测试仪
    C++:内存管理
    宝玉:Sora 如何改变我们的生活
    第31章_瑞萨MCU零基础入门系列教程之WIFI&蓝牙模块驱动实验
  • 原文地址:https://blog.csdn.net/u012702547/article/details/125848855