vue3:vue2中protoType更改为config.globalProperties问题

目录
  • protoType替换为config.globalProperties
  • Vue3 vs Vue2
    • Vue3 的新组件
    • 文件对比
    • 全局 API

protoType替换为config.globalProperties

原文地址

在main.js中:

vue2

Vue.prototype.$verson = '1.0.0'

使用

this.$verson

vue3

Vue.config.globalProperties.$verson = '1.0.0'

使用

<script setup lang="ts">
import {getCurrentInstance} from 'vue'
console.log(getCurrentInstance().appContext.config.globalProperties.$verson)
</script>

Vue3 vs Vue2

Vue3 的新组件

Fragment

Vue2 中:组件必须有一个根标签

Vue3 中:可以没有根标签,内部会添加根标签 <fragment> </fragment>

好处:减少标签层级,减少内存消耗

<template>
    <h1>App</h1>
    <p>superman</p>
</template>
<script>
export default { name: "App" };
</script>

Teleport

用于将组件的 HTML 结构移动到指定位置

用法:

① 用 Teleport 标签将需要移动的 HTML 结构包裹住

② 设置 to 属性,属性值为 选择器,以指定移动到的位置

默认情况下,子组件的 HTML 结构会显示到父组件的 HTML 结构里面;

使用 Teleport 标签包裹子组件的 HTML 标签,则能将该 HTML 结构显示到指定的位置

<template>
    <div class="box">
        <h1>App</h1>
        <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>
<template>
    <!-- 默认情况下,显示到 .box 里面 -->
    <h2>Son</h2>
    <!-- 通过 Teleport 标签,将 HTML 结构显示到 body 里面 -->
    <Teleport to="body">
        <h2>Teleport Son</h2>
    </Teleport>
</template>
<script>
export default { name: "Son" };
</script>

Suspense

等待异步组件时,渲染一些额外的内容,提升用户体验感

用法:

① 在父组件中,异步引入组件:defineAsyncComponent + 懒加载

② 在子组件中,配置 Suspense 标签

③ 在 Suspense 标签内,用 template 标签设置具名插槽

default 插槽的内容:为异步引入的组件

fallback 插槽的内容:为加载时显示的内容

此时,异步引入的组件中 setup 可以是 async 函数

<template>
    <div class="box">
        <h1>App</h1>
        <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>
<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>

文件对比

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')

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') // 链式调用

store 文件

Vue2

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
    state: {},
    mutations: {},
    actions: {},
    modules: {}
})

Vue3

import { createStore } from 'vuex' // 引入 createStore 方法
export default createStore({
    state: {},
    mutations: {},
    actions: {},
    modules: {}
})

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: {}
})

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 name</button> |
    <button @click="diModify">diModify name</button>
</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>

但是,通过该方法获取的数据不是响应式的

响应式数据设置如下:需要配合 computed 方法使用

let name = computed(() => store.state.name);
let arr = computed(() => store.state.arr);
let getArr = computed(() => store.getters.getArr);

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

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

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

Vue3 中需要通过 useRoute 方法使用 vue-router

<template>
    <router-link to="/">Home</router-link> |
    <router-link to="/about">About</router-link>
    <router-view />
</template>
<script>
export default {
    name: "App",
};
</script>
<template>
    <h1>About</h1>
</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>
<template>
    <h1>Home</h1>
</template>
<script>
export default { name: "Home" };
</script>

全局 API

在 Vue3 中,全局和内部 API 都经过了重构

全局 API 现在只能作为 ES 模块构建的命名导出进行访问

import { nextTick } from 'vue'
nextTick(() => {
    // 一些和DOM有关的东西
})

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')

也可以使用简写(回调函数执行完后,DOM 才会插入到页面中):

Vue.directive("focus", (el, msg) => {
    console.log(el, msg); // el:挂载的元素;val:挂载的信息
    console.log(msg.value); // 获取指令的属性值
});

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')

钩子函数接收 2 个参数:

  • el:指令绑定到的元素,可用于直接操作 DOM。eg:el.focus()
  • binding:配置对象
  • instance:使用指令的组件实例
  • value:传递给指令的值
  • oldValue:先前的值,仅在 beforeUpdate 和 updated 中可用。无论值是否有更改都可用
  • arg:传递给指令的参数(如果有的话)
  • eg:v-my-directive:foo 中,arg 为 "foo"。
  • modifiers:修饰符对象(如果有的话)
  • eg:v-my-directive.foo.bar 中,修饰符对象为 {foo: true,bar: true}
  • 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')

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')

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • vue3中如何实现定义全局变量

    目录 vue3定义全局变量 vue3全局变量app.config.globalProperties的使用 globalProperties vue3定义全局变量 在vue2中,我们知道vue2.x是使用Vue.prototype.$xxxx=xxx来定义全局变量,然后通过this.$xxx来获取全局变量. 但是在vue3中,这种方法显然不行了.因为vue3中在setup里面我们是无法获取到this的,因此按照官方文档我们使用下面方法来定义全局变量: 首先在main.js里写一个我们要定义的全局变

  • Vue3 中自定义插件的实现方法

    目录 1. Vue 插件 2. 自定义插件 2.1 基本用法 2.2 加入组件 2.3 加入指令 2.4 provide & inject 3. 小结 最近在录 TienChin 项目,项目涉及到了 Vue 中插件的定义,因此整了这么一篇文章,手把手教大家在 Vue3 中定义插件,这个技能掌握了,就可以看懂 TienChin 前端代码了. 1. Vue 插件 在 Vue 中,一些简单的功能,我们可以直接定义为全局方法,然后挂到 Vue 上就能使用了,例如在 vhr 中,我们将网络请求方法进行封装

  • 关于vue3编写挂载DOM的插件问题

    vue3 跟 vue2 相比,多了一个 app 的概念,vue3 项目的创建也变成了 // main.js import { createApp } from 'vue' import App from './App.vue' import ElementPlus from 'element-plus' const app = createApp(App) app.use(ElementPlus) // 使用饿了么框架 app.mount('#app') 所以 Vue.extend 也没有了.

  • vue3:vue2中protoType更改为config.globalProperties问题

    目录 protoType替换为config.globalProperties Vue3 vs Vue2 Vue3 的新组件 文件对比 全局 API protoType替换为config.globalProperties 原文地址 在main.js中: vue2 Vue.prototype.$verson = '1.0.0' 使用 this.$verson vue3 Vue.config.globalProperties.$verson = '1.0.0' 使用 <script setup lan

  • vue2中如何更改el-dialog出场动画(el-dialog弹窗组件)

    目录 前言 效果 基本思路 代码 前言 el-dialog是一个十分好用的弹窗组件,但是出场动画比较单调,于是决定自定义一个出场动画,本文记叙一下思路. 效果 详见上面动图. 基本思路 将.el-body分为两个部分,一个弹窗真正要展示的内容,一个出现.关闭时动画的图片展示(不一定是图片,本项目刚好是图片而已),在出场动画的过程中,图片逐渐消失,真正的内容发逐渐展现,看起来就像是原本那张图片通过旋转之后,变成了弹窗. 代码 首先,写一个常规的el-dialog,里面el-body分为两个部分,真

  • Vue2.x与Vue3.x中路由钩子的区别详解

    目录 vue2.x 前置概念: 路由钩子分类 路由和组件的概念(方便理解钩子函数) 全局路由钩子 路由配置守卫钩子 组件内的守卫钩子 路由钩子执行顺序 eg: 从A组件跳转到B组件顺序 如果B路有更新, 每次都会执行以下三个钩子: vue3.x 对比变化图 区别补充: vue2.x 前置概念: 路由钩子分类 一共分3类, 7个钩子 路由和组件的概念(方便理解钩子函数) 路由和组件是2个概念, 可以粗犷的认为: 路由是浏览器网址 组件是显示在网页上的不同内容 全局路由钩子 router.befor

  • vue3.0中的双向数据绑定方法及优缺点

    熟悉vue的人都知道在vue2.x之前都是使用object.defineProperty来实现双向数据绑定的 而在vue3.0中这个方法被取代了 1. 为什么要替换Object.defineProperty 替换不是因为不好,是因为有更好的方法使用效率更高 Object.defineProperty的缺点: 1. 在Vue中,Object.defineProperty无法监控到数组下标的变化, 导致直接通过数组的下标给数组设置值,不能实时响应. push() pop() shift() unsh

  • Vue2中无法检测到数组变动的原因及解决

    目录 解决方法 由于JavaScript 的限制,Vue 不能检测以下数组的变动: 当利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue 当修改数组的长度时,例如:vm.items.length = newLength var vm = new Vue({ data: { items: ['a', 'b', 'c'] } }) vm.items[1] = 'x' // 不是响应性的 vm.items.length = 2 // 不是响应性的 解决

  • Vue3.0中Ref与Reactive的区别示例详析

    目录 Ref与Reactive Ref Reactive Ref与Reactive的区别 shallowRef 与shallowReactive toRaw ---只修改数据不渲染页面 markRaw --- 不追踪数据 toRef --- 跟数据源关联 不修改UI toRefs ---设置多个toRef属性值 customRef ---自定义一个ref ref 捆绑页面的标签 总结 Ref与Reactive Ref Ref 用来创建基础类型的响应式数据,模板默认调用value显示数据.方法中修

  • Vue3项目中引用TS语法的实例讲解

    目录 基础语法 vue-router vuex##### elementPlus axios setup script 基础语法 定义data  //script标签上 **lang="ts"** <script lang="ts"> import { defineComponent, reactive, ref, toRefs } from 'vue'; //定义一个类型type或者接口interface来约束data type Todo = {  

  • vue2中基于vue-simple-upload实现文件分片上传组件功能

    本文最主要参考的是这一篇,后端也是用django来完成. 大文件上传(秒传/断点续传)_使用Vue-Simple-Uploader插件 --Vue/Django完整实现 https://www.jb51.net/article/206178.htm 参考的代码地址:https://github.com/ClearlightY/FileUpload vue-simple-upload文档:https://github.com/simple-uploader/Uploader <template>

  • vue3+vue-cli4中使用svg的方式详解(亲测可用)

    目录 前言: 一.安装 svg-sprite-loader 二.在src/components/svgIcon下新建组件index.vue 三.在assets在创建icons文件夹 四.在src同级下创建vue.config.js进行配置 五.在main.js里引入,以及做一些小修改 六.在页面中使用 七.文件目录结构及其效果展示 八.参考链接地址 总结 技术栈:vue3+vue-cli4 前言: 目前大多数是基于vue2引入,所以想基于vue3需要做一些改动(注意该方法是基于vue-cli中使

  • vue2中组件互相调用实例methods中的方法实现详解

    目录 前言: 开始前: 使用 第一步.定义全局mixin 第二步添加代码提示d.ts声明文件 在项目下新建jsconfig.json 添加shims-vue.d.ts声明文件 添加event-keys.d.ts声明文件 第三步编写webpack插件 新建global-dispatch.js 自动生成event-keys.d.ts 添加vue-path-loader.js webpack loader文件 配置vue.config.js 后记 仓库地址 总结 前言: 大家都知道在vue2中相互调用

随机推荐