VUE3 手册

setup

setup函数,是在beforeCreate之前执行(创建实例前$el)。由于在执行setup 时尚未创建组件实例,因此在 setup 选项中没有 this。

setup 参数
使用setup时,它接受两个参数:

  1. props: 组件传入的属性
  2. context:包含3个属性

props是响应式的, 当传入新的props 时,会及时被更新。由于是响应式的, 所以不可以使用ES6解构,解构会消除它的响应式。这段代码会让props不再支持响应式:

import { defineComponent } from 'vue'
export default defineComponent ({
	props: { name: '冷冬' },
    setup(props, context) {
        let name = props.name
        console.log(name);
        return { name }
    },
})

context提供了最常用的三个属性:attrsslotemit,分别对应Vue2中的 a t t r 属 性 、 s l o t 插 槽 和 attr属性、slot插槽 和 attr属性、slot插槽和emit发射事件。

	context.attrs:传入组件中但是未被props接收的对象。
	context.emit:用于触发当前组件实例上的传值事件。
	context.slots:用来访问被插槽分发的内容(一般用于使用渲染函数来书写一个组件时)

数据定义

  1. ref:创建响应式的数据变量。传入的为基本数据类型,例如字符串、数字、boolean 等,返回值是一个响应式的对象,这个对象上只包含一个 value 属性
  2. isRef:判断生成的响应式数据是否是通过 ref 方法生成的(是true、否false)
import { ref } from 'vue'
setup() {
	//定义
    const msg = ref('你好') 
    //修改
    const changeMsg =()=>{
      msg.value ='msg被改了'
    }
    console.log("isRef:",isRef(msg));    // isRef:true
    //导出
    return { 
     msg,
     changeMsg
    }
  }
  1. reactive:创建响应式的数据对象。传入的为引用类型,例如数组、对象等,但不能代理基本类型值,返回一个响应式的数据对象。
  2. isReactive: 判断生成的响应式数据是否是通过 isReactive 方法生成的,还能判断readonly代理的对象是否是由reactive创建(是true、否false)
  3. toRefs:将一个 reactive 对象转化为属性全部为 ref 对象的普通对象
  4. JSON.parse(JSON.stringify(Array)):阻止数据响应式的发生。
<div>{{ msg }}</div>

import { reactive } from 'vue'
setup() {
        //定义
        const state = reactive({
            msg: '你好'
        })
        //修改
        const changeMsg = () => {
            state.msg = 'msg被改了'
        }
        console.log("state:",isReactive(state));   // state:true
        //导出
        return {
            ...toRefs(state),
            changeMsg
        }
    }
  1. readonly:创建一个只读代理,对变量创建只读。
  2. isReadonly:检查代理是否由readonly创建(是true,否false)。
import { readonly } from 'vue';
export default {
    setup() {
        const user = { name: 'ul', age: 20 };
        const copy = readonly(user);
        
		const users = reactive({ name: 'li', age: 30 });
        const copys = readonly(users);
        
		function getClick(){
			user.age++;		// 21
			copy.age++;     // warning! target is readonly.
			users.age++;	// 31
			copys.age++;    // warning! target is readonly.
		}
        return { copy,copys,getClick  };
    }
}
  1. isProxy:对象是否由reactive创建或者是readonly创建的代理(是true,否false)。
	// ref创建
	const refVal = ref(123);
	isProxy(refVal) // false
	
	// reactive创建
	const reactiveVal = reactive({ age: 20 });
	isProxy(reactiveVal) // true
  1. toRaw:返回reactive或者是readonly代理的原始对象。
	import { toRaw, reactive, readonly, isProxy } from 'vue';
	const user = { name:'立冬' };
	const reactiveUser = reactive(user);
	const readonlyUser = readonly(reactiveUser);
	
	console.log(toRaw(reactiveUser) === user) // true
	console.log(toRaw(readonlyUser) === user) // true
	console.log(isProxy(toRaw(reactiveUser))) // false
	console.log(isProxy(toRaw(readonlyUser))) // false
  1. markRaw: 标记一个对象,被标记后,该对象永远不会被转换为代理。
import { markRaw, reactive, isReactive } from 'vue';
const user = markRaw({});
const reactiveUser = reactive(user);
console.log(isReactive(reactiveUser)) // false

const reactiveUser1 = reactive({ user });
console.log(isProxy(toRaw(reactiveUser1))) // true 
console.log(isProxy(toRaw(reactiveUser1.user))) // false
// 在reactive创建代理时,被markRaw标记的嵌套对象不会被reactive创建代理
  1. shallowReactive:创建一个反应式代理,但是只是浅度创建。
import { isReactive, shallowReactive } from 'vue';
const data = shallowReactive({
    count: 10,
    content: {
        age: 20
    }
})
data.count++ // 11 逻辑层数据已发生变化,视图重新渲染
isReactive(data.content) // false 因为data.content属于深度嵌套,未被代理
data.content.age++ // 21 逻辑层数据已发生变化,但是视图层不会被更新渲染
  1. shallowReadonly:创建一个只读代理,但是只是浅度创建。
import { isReadonly, shallowReadonly } from 'vue';
const data = shallowReadonly({
    count: 10,
    content: {
        age: 20
    }
})
data.count++ // warning! target is readonly.
isReadonly(data.content) // false 因为data.content属于深度嵌套,未被代理
data.content.age++ // 21 深度嵌套未被代理,所以操作成功。

自定义指令:directive

	beforeMount() {},  		// 挂载前
	mounted() {},			// 挂载后
	beforeUpdate() {},		// 新增,更新前
	updated() {},			// 更新后
	beforeUnmount() {}, 	// 新增,卸载前
	unmounted() {}			// 卸载后

创建自定义指令

	//定义文档的标题: <div v-title>编辑框</div>
	const title = {
	   mounted(el:any) {
	       document.title = el.innerText;
	       el.remove();
	   },
	};

main.js 初始化自定义指令

	import * as directives from "./common/directives"   // 批量定义加载全局自定义指令
	Object.keys(directives).forEach((key:any) => {
	    app.directive(key, directives[key]);
	});

依赖注入

  1. provide:父组件创建
	<son-com ref="sonRef" :customForm=custom/>  
	
	setup(){
		// 使用ref给子组件传值
		const sonRef = ref(null);
		function popUpShow(){
			let item = {};
            sonRef.value.mySes = '懂经济';
		}

		// 给子组件传值
		const custom = reactive({
			name: '紫色'
		});
		
		// 使用依赖注入(provide )给子组件传值
		const person = reactive({name: 'bob', age:32});
		provide('person', person);
		
		return {
			sonRef, custom, popUpShow
		}
	}
  1. inject:子组件获取
	<div>{{ customForm.name }}</div>
    export default {
    	props: {
            customForm: Object
        },
	 	setup(props,context) {
	 		// 获取ref给子组件传的值	
			let mySes = ref(null);
			
			// 可以直接在html中使用customForm.name,在setup中使用要props.customForm
			console.log("父组件传的参数:",props.customForm);

			// 在所有子组件中都能获取provide中的数据
			const person = inject('person');
			return {
				mySes,
				loadDate,
				person
			}
		}
	}

监听属性

	watch(count, (val, old) => { 				// 监听字符串
		console.log("count改变了");
	});
	watch(()=>search.status, (val, old) => { 	// 监听对象
		console.log("count改变了");
	});
	// watch监听器:变化前,变化后的值都能获取。一次监听多个数据(对象,字符串)
	watch([()=>search.status, count], ([name, count], [preName, preCount]) => {
		console.log("search.status的数据变化:",name,preName,',count的数据变化:',count,preCount);
	});
	// watchEffect监听器:只能获取变化后的值,初始化时会执行一次回调函数来自动获取依赖(监控所有的响应式数据)
	watchEffect(() => {
		console.log(search.status);
		onInvalidate(() => {});   // 在watchEffect(重新运行/停止的时候)执行
	});

路由

路由的useRoute,useRouter 相当于vue2的 this. r o u t e ( ) , t h i s . route(),this. route(),this.router()。

	import { useRoute, useRouter } from 'vue-router'
	export default {
	  setup () {
	    const route = useRoute()
	    const router = useRouter()
	    
 		router.push({ name: 'home' })
	
	    return {}
	  },
	}
  1. useRoute:获取当前的路由信息
	 $route.path      	字符串,对应当前路由的路径,总是解析为绝对路径,如"/foo/bar"。
	 $route.params    	一个 key/value 对象,包含了动态片段和全匹配片段,如果没有路由参数,就是一个空对象。
	 $route.query     	一个 key/value 对象,表示 URL 查询参数。如果没有查询参数,则是个空对象。
	 $route.hash      	当前路由的hash值 (不带#) ,如果没有 hash 值,则为空字符串。
	 $route.fullPath  	完成解析后的 URL,包含查询参数和hash的完整路径。
	 $route.matched   	数组,包含当前匹配的路径中所包含的所有片段所对应的配置参数对象。
	 $route.name		当前路径名字
	 $route.meta  		路由元信息
  1. useRouter:全局路由的实例,是router构造方法的实例。
 	$router.push('/home/index')				// 	/home/index
    $router.push({path:'/home/index'})		// 	/home/index
    $router.push({name:'user', params:{userId:123}})  			//  跳转到路由的名称
    $router.push({path:'/register/index',query:{plan:'123'}})   //  /register/index?plan=123
    
    <router-link :to="{path:`/home/edit/${ props.item.id }`}" tag="a" target="_blank" ></router-link>
    注意:push方法其实和<router-link></router-link>是等同的。
    push方法的跳转会向 history 栈添加一个新的记录,当我们点击浏览器的返回按钮时可以看到之前的页面。

	$router.go(1)   // 前进
	$router.go(-1)  // 后退
	$router.replace('/search');  // 

 	{ path: '/:pathMatch(.*)*' }   // 没有匹配的路由

自定义 Hooks

vue3 的 hook 函数 相当于 vue2 的 mixin, 不同在与 hooks 是函数。

	import { getCurrentInstance,ref } from 'vue'
	import { useRouter } from 'vue-router';
	const right = () => {
		let index = ref('123');
		return {
			index
		}
	}
	export { right }

getCurrentInstance

获取当前组件的实例、上下文。

	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.$root.$route   proxy.$root.$router
	proxy.$slots
	proxy.$watch

修饰符

	.stop		// 阻止冒泡行为,不让当前元素的事件继续往外触发
	.prevent	// 阻止事件本身行为,如阻止超链接的点击跳转,form表单的点击提交
	.capture	// 改变js默认的事件机制,默认是冒泡,capture功能是将冒泡改为倾听模式
	.self		// 只有是自己触发的自己才会执行,如果接受到内部的冒泡事件传递信号触发,会忽略掉这个信号
	.once		// 点击事件将只会触发一次
	.passive	//	滚动事件的默认行为 (即滚动行为) 将会立即触发,而不会等待 onScroll 完成。这个 .passive 修饰符尤其能够提升移动端的性能。
	.keyup		// 按键修饰符
	.exact 		// 修饰符允许你控制由精确的系统修饰符组合触发的事件。

	.passive 和 .prevent 不能一起使用(.prevent 将会被忽略)
	.self 和 .stop 区别:
		self只响应当前元素自身触发的事件,不会响应经过冒泡触发的事件,并不会阻止冒泡继续向外部触发。
		stop是从自身开始不向外部发射冒泡信号
		

全局命令

ref

	<p v-for="(item,index) in renderData" :key="index" ref="nodes"></p>
	console.log(this.$refs.nodes) // vue3 返回所有循环的p元素节点
	console.log(this.$refs.nodes) // vue2 返回循环后最后一个P元素节点

v-if和v-for优先级

	当v-if和v-for同时作用于一个元素上时:
	Vue2.x中v-for的优先级会高于v-if;
	Vue3.x中v-if的优先级会高于v-for;
	使用禁忌:Vue3.x中不能将v-for和v-if放在同一个元素上。只能使用v-for嵌套v-if使用
	使用建议:官方建议使用计算属性来处理,即提高性能,又能兼容Vue3.x。

mount(节点挂载)

	在 main.js 挂载
	import { createApp } from 'vue';
	const app = createApp({});
	app.mount('#my-app');

unmount(取消挂载)

	在main.js 中取消挂载
	import { createApp } from 'vue';
	const app = createApp({})
	// 挂载
	app.mount('#my-app');
	// 取消挂载
	setTimeout(() => app.unmount('#my-app'), 2000);

use(插件)

与Vue 2.x类似,如果参数为对象,则需要提供一个install的方法;如果参数本身就是一个方法,那么这个方法将默认为安装插件的方法;在进行方法的调用时,Vue将作为第一个参数传入方法中。

	注意:同一个插件多次调用use时,该插件也只能被安装一次。
	
	import { createApp } from 'vue';
	const app = createApp({})
	import router from './router/index';
	app.use(router);
	app.mount('#my-app');

config:Vue应用配置

config:包含Vue应用程序全局配置的对象,在挂载应用之前配置相应的属性。

devtools(类型: Boolean,默认: true):配置是否允许开启vue-devtools检查,一般在开发环境中是true,生产环境中为false。

errorHandler(类型:Function,参数err:错误内容,vm:对应的实例,info:Vue特定的错误信息,如某个生命周期中出现的错误):为组件在实例化或渲染过程中捕获到的错误进行处理的方法。

warnHandler(类型:Function, 参数msg:警告内容,vm:对应的实例,trace:组件的层次追踪):为Vue在运行时捕获到的警告进行处理的方法。

globalProperties(类型:any):用于添加到应用程序中任何组件都能使用的全局属性,当与组件内部的属性冲突时,将优先使用组件内部的属性值。可代替Vue2中的Vue.prototype。

isCustomElement(类型:(tag: string) => boolean):用于来识别Vue之外的自定义元素(如,三方web组件api),如果组件或元素符合这个条件,则组件不会被实例化,Vue也不会对组件或元素发出警告信息。

optionMergeStrategies(类型:[key: string] : Function):为Vue自定义选项定义合并策略。

performance(类型:boolean,默认:false):设置此项为true时,将在浏览器的devtool性能/时间线面板中启用组件的初始化,编译,渲染及修补程序跟踪。仅在开发模式和支持performance.mark api的浏览器中工作

生命钩子

VUE3 手册

let {  onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted, one rrorCaptured, onRenderTracked, onRenderTriggered} = Vue;
setup() {
    // vue3.x生命周期写在setup中
    onBeforeMount(() => {      });   	// 挂载开始之前被调用
    onMounted(() => {          });   	// 实例被挂载后调用,不会保证所有的子组件也被挂载完
    onBeforeUpdate(() => {     });   	// 更新渲染DOM前
    onUpdated(() => {          });		// 更新渲染DOM完成,不会保证所有的子组件也都一起被重绘
    onBeforeUnmount(() => {    });		// 销毁组件实例之前,此时实例仍然是完全正常的
    onUnmounted(() => {        });    	// 销毁组件实例完成,组件实例的所有指令被解除绑定、事件侦听器被移除、子组件实例被卸载。
    one rrorCaptured(() => {    });  	// 当捕获一个来自子孙组件的错误时被调用
    
	onRenderTriggered((event) => {    });  // 状态触发(它会跟踪你变化值的信息,并且新值和旧值都会给你明确的展示出来)
	onRenderTracked((event) => {      });  // 状态跟踪(所有我们用return返回去的值,它都会跟踪)
},

如果把 onRenderTracked 比喻成散弹枪,每个值都进行跟踪,那 onRenderTriggered 就是狙击枪,只精确跟踪发生变化的值,进行针对性调试。

	event对象属性的详细介绍:
		- key 那边变量发生了变化
		- newValue 更新后变量的值
		- oldValue 更新前变量的值
		- target 目前页面中的响应变量和函数
上一篇:Reactive(1) 从响应式编程到"好莱坞"


下一篇:Vue3响应式系统api 之 ref reactive