• 【Vue3】Vue3 vs Vue2


    Vue3 的新组件

    Fragment

    • Vue2 中:组件必须有一个根标签
    • Vue3 中:可以没有根标签,内部会添加根标签
    • 好处:减少标签层级,减少内存消耗
    <template>
        <h1>Apph1>
        <p>supermanp>
    template>
    
    <script>
    export default { name: "App" };
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    Teleport

    • 用于将组件的 HTML 结构移动到指定位置
    • 用法:
      ① 用 Teleport 标签将需要移动的 HTML 结构包裹住
      ② 设置 to 属性,属性值为 选择器,以指定移动到的位置

    默认情况下,子组件的 HTML 结构会显示到父组件的 HTML 结构里面;
    使用 Teleport 标签包裹子组件的 HTML 标签,则能将该 HTML 结构显示到指定的位置

    <template>
        <div class="box">
            <h1>Apph1>
            <button @click="bol = !bol">显示 / 隐藏button>
            <Son v-if="bol" />
        div>
    template>
    
    <script>
    import { ref } from "vue";
    import Son from "./components/Son.vue";
    export default {
        name: "App",
        components: { Son },
        setup() {
            let bol = ref(false);
            return { bol };
        },
    };
    script>
    
    <style>
    .box {
        width: 200px;
        height: 200px;
        background: palevioletred;
        position: relative;
    }
    style>
    
    • 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
    <template>
        
        <h2>Sonh2>
        
        <Teleport to="body">
            <h2>Teleport Sonh2>
        Teleport>
    template>
    
    <script>
    export default { name: "Son" };
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    Suspense

    • 等待异步组件时,渲染一些额外的内容,提升用户体验感
    • 用法:
      ① 在父组件中,异步引入组件:defineAsyncComponent + 懒加载
      ② 在子组件中,配置 Suspense 标签
      ③ 在 Suspense 标签内,用 template 标签设置具名插槽
      default 插槽的内容:为异步引入的组件
      fallback 插槽的内容:为加载时显示的内容
    • 此时,异步引入的组件中 setup 可以是 async 函数
    <template>
        <div class="box">
            <h1>Apph1>
            <Suspense>
                
                <template v-slot:default>
                    <Son>Son>
                template>
                
                <template #fallback>
                    加载中...
                template>
            Suspense>
        div>
    template>
    
    <script>
    // 静态引入
    // import Son from "./components/Son.vue"; 
    
    // 异步引入
    import { defineAsyncComponent } from 'vue';
    const Son = defineAsyncComponent(() => import("./components/Son.vue"));
    
    export default {
        name: "App",
        components: { Son },
    };
    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
    <template>
        <h2>Son: {{ p }}h2>
    template>
    
    <script>
    export default {
        name: "Son",
        // 此时 setup 也可以是 async 函数
        async setup() {
            let p = await new Promise((resolve, reject) => {
                setTimeout(() => {
                    resolve("superman")
                }, 1000);
            });
            return { p };
        }
    };
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    文件对比

    main.js

    Vue2

    import Vue from 'vue'
    import App from './App.vue'
    import router from './router'
    import store from './store'
    
    Vue.config.productionTip = false
    
    new Vue({
        router,
        store,
        render: h => h(App)
    }).$mount('#app')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    Vue3

    • 引入的不再是 Vue 构造函数,而是工厂函数 createApp
      • 构造函数:通过 new 关键字调用,首字母大写
      • 工厂函数:直接调用,首字母小写
    • createApp 返回:应用实例对象 (相当于 Vue2 中的 vm,但比 vm 轻)
    • 可以在 createApp 之后链式调用其它方法
    import { createApp } from 'vue' // 引入 createApp 方法
    import App from './App.vue'
    import router from './router'
    import store from './store'
    
    createApp(App).use(store).use(router).mount('#app') // 链式调用
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    store 文件

    Vue2

    import Vue from 'vue'
    import Vuex from 'vuex'
    Vue.use(Vuex)
    
    export default new Vuex.Store({
        state: {},
        mutations: {},
        actions: {},
        modules: {}
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    Vue3

    import { createStore } from 'vuex' // 引入 createStore 方法
    
    export default createStore({
        state: {},
        mutations: {},
        actions: {},
        modules: {}
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    Vuex 的使用

    • 先配置好 store 文件:
    import { createStore } from 'vuex'
    
    export default createStore({
        state: {
            name: "superman",
            arr: [1, 2, 3]
        },
        mutations: {
            muModify(state, val) {
                console.log("commit muModify", val)
                state.name += val
            }
        },
        actions: {
            acModify(context, val) {
                console.log("dispatch acModify", val)
                context.commit("muModify", val)
            }
        },
        getters: {
            getArr(state) {
                return state.arr.map(item => item * 2)
            }
        },
        modules: {}
    })
    
    • 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
    • Vue3 中需要通过 useStore 方法使用 vuex
    <template>
        <p>普通使用:p>
        <p>$store.state.name: {{ $store.state.name }}p>
        <p>$store.state.arr: {{ $store.state.arr }}p>
        <p>$store.getters.getArr: {{ $store.getters.getArr }}p>
        <hr />
        <p>Vue 3:p>
        <p>name: {{ name }}p>
        <p>arr: {{ arr }}p>
        <p>getArr: {{ getArr }}p>
        <hr />
        <button @click="coModify">coModify namebutton> |
        <button @click="diModify">diModify namebutton>
    template>
    
    <script>
    import { useStore } from "vuex";
    export default {
        name: "App",
        setup() {
            // 通过 useStore 使用 Vuex
            const store = useStore();
            // 获取数据
            let name = store.state.name;
            let arr = store.state.arr;
            let getArr = store.getters.getArr;
            // 调用 dispatch 方法
            function diModify() {
                store.dispatch("acModify", "(Actions)");
            }
            // 调用 commit 方法
            function coModify() {
                store.commit("muModify", "(Mutations)");
            }
            return { name, arr, getArr, coModify, diModify };
        },
    };
    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
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 但是,通过该方法获取的数据不是响应式的
    • 响应式数据设置如下:需要配合 computed 方法使用
    let name = computed(() => store.state.name);
    let arr = computed(() => store.state.arr);
    let getArr = computed(() => store.getters.getArr);
    
    • 1
    • 2
    • 3

    router 文件

    Vue2

    import Vue from 'vue'
    import VueRouter from 'vue-router'
    import Home from '../views/Home.vue'
    
    Vue.use(VueRouter)
    
    const routes = [{
            path: '/',
            name: 'Home',
            component: Home
        },
        {
            path: '/about',
            name: 'About',
            component: () => import('../views/About.vue')
        }
    ]
    
    const router = new VueRouter({
        mode: 'history', // 设置路由模式为 history
        base: process.env.BASE_URL, // 根据 webpack 环境,设置 [根路径]
        routes
    })
    
    export default router
    
    • 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

    Vue3

    import {
        createRouter, // 引入 createRouter 方法
        createWebHistory // 引入 createWebHistory 方法
    } from 'vue-router'
    
    import Home from '../views/Home.vue'
    
    const routes = [{
            path: '/',
            name: 'Home',
            component: Home
        },
        {
            path: '/about',
            name: 'About',
            component: () => import('../views/About.vue')
        }
    ]
    
    const router = createRouter({
        history: createWebHistory(process.env.BASE_URL),
        routes
    })
    
    export default router
    
    • 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

    vue-router 的使用

    • 先配置 router 文件
    import {
        createRouter,
        createWebHistory
    } from 'vue-router'
    
    import Home from '../views/Home.vue'
    
    const routes = [{
            path: '/',
            name: 'Home',
            component: Home
        },
        {
            path: '/about',
            name: 'About',
            component: () => import('../views/About.vue')
        }
    ]
    
    const router = createRouter({
        history: createWebHistory(process.env.BASE_URL),
        routes
    })
    
    export default router
    
    • 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
    • Vue3 中需要通过 useRoute 方法使用 vue-router
    <template>
        <router-link to="/">Homerouter-link> |
        <router-link to="/about">Aboutrouter-link>
        <router-view />
    template>
    
    <script>
    export default {
        name: "App",
    };
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    <template>
        <h1>Abouth1>
    template>
    
    <script>
    import {
        useRoute,
        useRouter,
        onBeforeRouteLeave,
        onBeforeRouteUpdate,
    } from "vue-router";
    export default {
        name: "About",
        setup() {
            // 当前路由对象
            let route = useRoute();
            console.log("route", route);
            // 总路由对象
            let router = useRouter(router);
            console.log("router", router);
            // 路由守卫
            onBeforeRouteLeave(() => {
                console.log("onBeforeRouteLeave:离开路由时触发");
            });
            onBeforeRouteUpdate(() => {
                console.log("onBeforeRouteUpdate:复用路由时触发");
            });
            return {};
        },
    };
    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
    <template>
        <h1>Homeh1>
    template>
    
    <script>
    export default { name: "Home" };
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    全局 API

    • 在 Vue3 中,全局和内部 API 都经过了重构
      全局 API 现在只能作为 ES 模块构建的命名导出进行访问
    import { nextTick } from 'vue'
    nextTick(() => {
        // 一些和DOM有关的东西
    })
    
    • 1
    • 2
    • 3
    • 4
    • Vue.XXXapp.XXX

    在这里插入图片描述

    全局 directive

    Vue2 - Vue.directive("自定义指令名", 配置对象)

    import Vue from 'vue'
    import App from './App.vue'
    
    Vue.config.productionTip = false
    
    Vue.directive("focus", {
        bind() {
            console.log("指令与元素绑定时触发");
        },
        inserted(el) {
            console.log("指令所在元素插入页面时触发");
            el.focus();
        },
        update(el) {
            console.log("模板重新渲染时触发");
            el.focus();
        }
    });
    
    new Vue({ render: h => h(App) }).$mount('#app')
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 也可以使用简写(回调函数执行完后,DOM 才会插入到页面中):
    Vue.directive("focus", (el, msg) => {
        console.log(el, msg); // el:挂载的元素;val:挂载的信息
        console.log(msg.value); // 获取指令的属性值
    });
    
    • 1
    • 2
    • 3
    • 4

    Vue3 - app.directive("自定义指令名", 配置对象)

    import { createApp } from 'vue'
    import App from './App.vue'
    
    const app = createApp(App)
    
    // 自定义指令,指令具有一组生命周期钩子:
    app.directive('myIns', {
        // 在绑定元素的 attribute 或事件监听器被应用之前调用
        created() {},
        // 在绑定元素的父组件挂载之前调用
        beforeMount() {},
        // 在绑定元素的父组件挂载之后调用
        mounted() {},
        // 在包含组件的 VNode 更新之前调用
        beforeUpdate() {},
        // 在包含组件的 VNode 及其子组件的 VNode 更新之后调用
        updated() {},
        // 在绑定元素的父组件卸载之前调用
        beforeUnmount() {},
        // 在绑定元素的父组件卸载之后调用
        unmounted() {}
    });
    
    app.mount('#app')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    钩子函数接收 2 个参数:

    1. el:指令绑定到的元素,可用于直接操作 DOM。eg:el.focus()
    2. binding:配置对象
      1. instance:使用指令的组件实例
      2. value:传递给指令的值
      3. oldValue:先前的值,仅在 beforeUpdateupdated 中可用。无论值是否有更改都可用
      4. arg:传递给指令的参数(如果有的话)
        eg:v-my-directive:foo 中,arg 为 "foo"
      5. modifiers:修饰符对象(如果有的话)
        eg:v-my-directive.foo.bar 中,修饰符对象为 {foo: true,bar: true}
      6. dir:配置对象本身

    全局属性

    • 全局属性:在任何组件中都可以访问
    • 与组件的属性发生命名冲突时,组件的属性优先级更高

    Vue2 - Vue.prototype

    import Vue from 'vue'
    import App from './App.vue'
    
    Vue.config.productionTip = false
    
    Vue.prototype.$myData = "superman" // 设置全局属性
    
    new Vue({ render: h => h(App) }).$mount('#app')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    Vue3 - app.config.globalProperties

    import { createApp } from 'vue'
    import App from './App.vue'
    
    const app = createApp(App)
    
    app.config.globalProperties.$myData = "superman" // 设置全局属性
    
    app.mount('#app')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 相关阅读:
    taobao.top.oaid.decrypt( OAID解密 )淘宝店铺订单解密接口,店铺订单明文接口对接教程
    Vue(四)——使用脚手架(1)
    部署Weblogic10.3.6
    「连载」边缘计算(二十三)02-28:边缘部分源码(源码分析篇)
    项目:数据库表的梳理
    Python接口自动化 —— 发送post请求的接口(详解)
    实验一 图像基本变换
    训练yolov5时出现RuntimeError: CUDA out of memory
    pytest框架如何设置失败重跑,以及运行用例时小技巧
    哪种网站适合物理服务器
  • 原文地址:https://blog.csdn.net/Superman_H/article/details/126294704