一、Vue3.x 应用配置
config:包含Vue应用程序全局配置的对象,在挂载应用之前配置相应的属性。
const app = Vue.createApp({}); app.config = {...};
1、devtools(类型:Boolean,默认:true)
概述:配置是否允许开启vue-devtools检查,一般在开发环境中是true,生产环境中为false。
用法:app.config.devtools = true;
2、errorHandler(类型:Function,参数err:错误内容,vm:对应的实例,info:Vue特定的错误信息,如某个生命周期中出现的错误)
概述:为组件在实例化或渲染过程中捕获到的错误进行处理的方法。
用法:app.config.errorHandler = (err, vm, info) => {};
概述:用于添加到应用程序中任何组件都能使用的全局属性,当与组件内部的属性冲突时,将优先使用组件内部的属性值。较Vue2.x:可代替Vue2中的Vue.prototype。
用法:
// Vue 2.x
Vue.prototype.name = '***'; // Vue 3.x
app.config.globalProperties.name = '***';
4、isCustomElement(类型:(tag: string) => boolean)
概述:用于来识别Vue之外的自定义元素(如,三方web组件api),如果组件或元素符合这个条件,则组件不会被实例化,Vue也不会对组件或元素发出警告信息。
用法:app.config.isCustomElement = tag => tag.startsWith('ion');
二、重写的 v-model
在Vue2.x中,我们使用的v-model只能双向绑定一个值,在某些需求面前显的力不从心。但是在Vue3.x中已经可以实现啦!
1、在Vue2.x中,v-model进行数据双向绑定(语法糖)的原理,且不能绑定多个值
<my-components v-model="msg"></my-components>
// 等价于
<my-components :value="msg" @input="value=$event"></my-components>
// myComponents组件中接收绑定数据和触发数据改变
props: { msg: String }; // 获取数据
this.$emit("input", 'newVal'); // 触发事件并传值
2、Vue3.x重写了v-model的实现方式,以适用用绑定多个 v-model —— 单个 / 多个 数据实现数据双向绑定
<my-components v-model:msg="msg" v-model:name="name"></my-components>
// 等价于
<my-components :msg="msg" @update:msg="value=$event" :name="name" @update:name="name=$event"></my-components>
// myComponents组件中接收绑定数据和触发数据改变
props: { msg: String, name: String }; // 获取数据
setup(props, { emit }) { emit('update:msg', 'newValue'); // 触发事件并传值
emit('update:name', 'newValue'); // 触发事件并传值
};
三、emits 选项
2、用途:用于记录当前组件emit的事件,当为对象时,则可以验证传入的值是否有效。
3、如何使用
setup(prop, { emit }) { const changeOne = val => { emit('on-changeOne', val); }; const changeTwo = val => { emit('on-changeTwo', val); }; }
// 用法一:数组用法
export default { emits:['on-changeOne', 'on-changeTwo'], setup() {...} }
// 用法二:对象用法,当emits为对象时,可以验证事件中的参数是否有效
export default { emits:{ click: null, 'on-changeOne': payload => { if(...) { return true; // 验证通过
} console.warn('验证失败!') return false; // 验证失败,控制台打印vue警告及“验证失败!”警告
}, 'on-changeTwo': payload => {...} }, setup() {...} } // 当验证函数中没有返回值return时,默认返回true
4、emits无论是数组或者对象用法最终都会将事件给传递出去,数组或对象的使用只是为了记录实例中的emit事件,或者是验证事件中的参数。
四、getCurrentInstance()获取实例
1、一个很重要的方法,获取当前组件的实例、上下文来操作router和vuex等。由vue提供,按需引入:import { getCurrentInstance} from 'vue';
import { getCurrentInstance } from 'vue'; // 获取当前组件实例
const instance = getCurrentInstance(); // 获取当前组件的上下文,下面两种方式都能获取到组件的上下文。
const { ctx } = getCurrentInstance(); // 方式一,这种方式只能在开发环境下使用,生产环境下的ctx将访问不到
const { proxy } = getCurrentInstance(); // 方式二,此方法在开发环境以及生产环境下都能放到组件上下文对象(推荐) // ctx 中包含了组件中由ref和reactive创建的响应式数据对象,以及以下对象及方法;
proxy.$attrs proxy.$data proxy.$el proxy.$emit proxy.$forceUpdate proxy.$nextTick proxy.$options proxy.$parent proxy.$props proxy.$refs proxy.$root proxy.$slots proxy.$watch
五、mitt 实现全局通讯
1、由于Vue3.x中删除了 on 和 off ,因此不能借助于一个单独的Vue实例来实现全局事件的发布和订阅与取消订阅(也就是跨组件通讯)。
2、mitt 是一个三方库,npm安装:npm install -D mitt,我们以同样使用插件的方式将mitt集成到Vue中。
- all(Map对象):包含了所有订阅的事件名称,及对应的处理方法数组。
- emit(方法):触发事件,参数为(事件名(方法名),携带的参数),当- 前携带的参数只能为一个,不能为多个。
- on(方法):创建事件订阅,参数为(事件名,处理方法)。
- off(方法):取消事件订阅,参数为(事件名,处理方法)。
import _ from 'lodash'; import mitt from 'mitt'; export default { install(Vue, options) { const _emitter = mitt(); // 全局发布(在Vue全局方法中自定义$pub发布方法) // 这里做了$pub方法能够携带多个参数的处理,方便我们再业务中触发事件时带多个参数
Vue.config.globalProperties.$pub = (...args) => { _emitter.emit(_.head(args), args.slice(1)); }; // 全局订阅(在Vue全局方法中自定义$sub订阅方法)
Vue.config.globalProperties.$sub = function (event, callback) { Reflect.apply(_emitter.on, _emitter, _.toArray(arguments)); }; // 取消订阅
Vue.config.globalProperties.$unsub = function (event, callback) { Reflect.apply(_emitter.off, _emitter, _.toArray(arguments)); }; } };
5、组件实例中使用:
// 全局事件发布
<template>
<div class="child">
<button @click="pubHandler">发起事件</button>
</div>
</template>
<script> import { onMounted, getCurrentInstance } from 'vue'; export default { setup(props, context) { const { proxy } = getCurrentInstance(); const pubHandler = () => { proxy.$pub('foo', 1, 2, 3); }; return { pubHandler }; } }; </script>
// 全局事件订阅/取消订阅
<template>
<div class="child">
<button @click="unsubHandler">注销事件</button>
</div>
</template>
<script> import { getCurrentInstance, onMounted } from 'vue'; export default { setup(props, context) { const { proxy } = getCurrentInstance(); const watchHandler = ([a, b, c] = args) => { console.log('组件件监听触发!'); }; onMounted(() => { proxy.$sub('foo', watchHandler); }); const unsubHandler = () => { proxy.$unsub('foo', watchHandler); }; return { unsubHandler }; } }; </script>
六、vue-router 的新特性
2、创建路由
// router.js
import { createRouter, createWebHashHistory, createWebHistory } from "vue-router"; const routes = [...]; const router = createRouter({ // 区别于vue2的mode,vue3中将使用history属性来决定采用哪种路由模式
history: createWebHashHistory(), // 默认为Hash模式,可设置createWebHistory模式 // 区别于vue2的base,vue3中的基础路由路径将作为createWebHashHistory或者createWebHistory的唯一参数配置到路由中。
routes }); export default router;
// main.js
import router from './routes'; const app = createApp(App); // 注册路由
app.use(router);
3、在组件中使用路由,查看路由。
// vue-router库当中暴露了 useRouter 和 useRoute 两个方法供组件使用,还暴露有其他方法。
import { useRouter, useRoute } from 'vue-router'; import { onMounted, getCurrentInstance } from 'vue'; export default { setup() { const { proxy } = getCurrentInstance(); const router = useRouter(); const route = useRoute(); onMounted(() => { console.log(proxy.$router === router) // true
console.log(route) // {path, params, query...}
}); } };