第一步:从vue解构你想要的内容
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
//创建根实例
let {createApp} = Vue;
//数据响应式
let {ref,shallowRef,reactive} = Vue;
//主动触发视图渲染
let {,triggerRef} = Vue;
//将ref对象(对象数据),返回只读代理
let {readonly} = Vue;
//监听相关
let {watch,watchEffect } = Vue;
创建vue根实例
let app = createApp({
//这里写内容
})
app.mount("#app")
让数据成为响应式
//ref
let count = ref(10); // {value:10}
let addCount = ()=>{
console.log("addCount执行了",count.value);
count.value ++;
}
// reactive() 创建一个对'对象'数据的引用 返回一个对象的响应式代理。(只能获取修改代理对象的子属性)
// Vue响应式检测reactive()创建的响应式代理数据时是深层的(可以检测根对象及其子对象的属性改变)
let zhang = reactive({name:"张三",age:18,info:{height:177,weight:70}});
console.log("zhang",zhang);
console.log("zhang",zhang.name);
console.log("zhang",zhang.age);
console.log("zhang",zhang.info);
console.log("zhang",zhang.info.height);
console.log("zhang",zhang.info.weight);
ref和shallowref的区别
在vue3中,想讲数据转变为响应式,可以用到ref和shallowref这两个api,目的是使数据的变化可以触发视图的重新渲染。
但是这两个是存在区别的,修改ref响应数据的深层内容,视图会相应改变。而修改shallowref响应数据的深层内容,数据会改变,但是视图没变化,可以使用triggerRef主动去更新视图。
特别地,如果你先点击shallowref响应数据,视图不变,但是如果之后你再去改变ref相应数据改变视图的同时,前面未改变的shallow响应数据视图也会一起更新。
这里的原理就是虚拟dom,一处更新的时候,会整体渲染出虚拟dom,所以顺带把其他地方的数据也同步修改了。
为什么要强制视图更新?
因为shallowRef是浅层的响应式,深层的数据变化无法及时更新到视图
第二种方法 this.$forceUpdate();
let {createApp,getCurrentInstance} = Vue;
// 获取当前Vue实例
let app = getCurrentInstance();
console.log("当前Vue实例",app);
app.config.globalProperties.$a =1;
app.config.globalProperties.$b =2;
let {$a,$b} = app.appContext.config.globalProperties; // 获取全局属性
let ctx = app.ctx; // 获取当前Vue实例的代理对象
ctx.$forceUpdate();//此处的ctx就是我们苦苦寻找的this
简单总结就是三个步骤:用getCurrentInstance获取当前实例,再用ctx获取代理对象,最后执行$forceUpdate
组合式写法
将定义的数据,方法以及计算属性都写在setup(props)里面,最后用return返回暴露即可。、
let { createApp } = Vue;
let { ref, reactive, readonly, computed } = Vue;
let app = createApp({
setup(props) {
var count = ref(10); // {value:10}
console.log("count", count);
var zhang = reactive({ name: "张三", age: 18, info: { height: 177, weight: 70 } });
console.log("zhang", zhang);
// 通过count得到的计算属性
// computed
// 1. 接受一个 getter 函数,返回一个只读的响应式 ref 对象, 此写法默认只有取值没有赋值(只读)
// 2. 也可以接受一个带有 get 和 set 函数的对象来创建一个可写的 ref 对象。
// 返回一个只读的响应式 ref 对象
// let doubleCount = computed(()=>{
// return count.value * 2;
// })
let doubleCount = computed({
get: () => {
return count.value * 2;
},
set: (val) => {
count.value = val / 2;
}
})
console.log("doubleCount", doubleCount);
// 该 ref 通过 .value 取值
console.log("doubleCount", doubleCount.value);
let addCount = () => {
console.log("addCount执行了", count.value);
count.value++;
}
let changeName = () => {
zhang.name = "李四"
}
let changeAge = () => {
zhang.age++
}
let changeHeight = () => {
zhang.info.height++
}
return {
count,
doubleCount,
addCount,
zhang,
changeName,
changeAge,
changeHeight,
}
},
mounted() {
console.log("代理对象,this", this);
/* new Proxy({},{
get(){
// 判断是否是ref对象 => ref.value
},
set(){
// 判断是否是ref对象 => ref.value = xxx
}
}) */
},
})
app.mount("#app");
丧失响应性
起因是我们嫌弃写起来太麻烦,想要将对应变量解构出来
//直接对代理对象解构, 会丧失响应性
//因为后续对name,age赋值已经无法触发源数据的赋值拦截
let { name, age, info: { height, weight } } = zhang;
解决办法一:手搓计算属性形成依赖
let name = computed({
get: () => {
return zhang.name;
},
set: (val) => {
zhang.name = val;
}
});
let age = computed({
get: () => {
return zhang.age;
},
set: (val) => {
zhang.age = val;
}
});
let height = computed({
get: () => {
return zhang.info.height;
},
set: (val) => {
zhang.info.height = val;
}
});
解决办法二:
let {toRef,toRefs } = Vue;
let {name,age} = toRefs(zhang); // {name:ref(),age:ref(),info:ref}
let {height,weight} = toRefs(zhang.info); // {height:ref(),weight:ref()