【七十二变】数据响应:
ref一般用于定义基本类型数据 也可以安排引用类型
reactive只能定义引用类型数据
示例如下:
<template>
<h1>姓名:{{ bb.name }}</h1>
<h2>{{ bb.c.d.e }}</h2>
<button @click="change">按钮</button>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
import {h} from "vue"
import {ref, reactive} from "vue";
export default {
name: 'App',
components: {
HelloWorld
},
setup() {
// ref一般用于定义基本类型数据 也可以安排引用类型
let name = ref('嘎嘎')
let age = 20;
// reactive只能定义引用类型数据
let bb = ref({
name: "咖喱哥给",
age: 85,
c: {
d: {
e: "是是是"
}
}
});
function change() {
console.log(bb.value.name = "发放")
bb.value.c.d.e = "哼哼"
}
/*返回对象的时候可以把返回的数据可以直接在模板使用*/
return {
name,
age,
change,
bb
}
/*返回一个函数直接渲染页面*/
// return () => h('h3', "笑死我了")
}
}
</script>
vue2数据代理问题:
引用数据改变其内部属性值不会发生响应,可以用this.$set(对象/数组,键,值),
删除同理: this.$delete(对象/数组,键,值)
数组键为下标
数据代理原理:
vue2:
Object.defineProperty(数据,键,{
get(){
读取会执行这个get函数
},
set(改变的数据){
读取会执行这个set函数,在这里更新页面
}
})
vue3:
ref 还是用vue2数据劫持原理,reactive才用代理。
let 源数据 = {
name:"ggg"
}
let pp = new Proxy(源数据,{
get(源数据,读取的键名){
return Reflect.get(源数据,"键")
},
//set 修改和新增都调佣
set(源数据,修改的键名,修改的值){
Reflect.set(源数据,"键","修改的值")
},
deleteProperty(源数据,删除的键名){
return Reflect.deleteProperty(源数据,"键")
}
})
Reflect可以返回执行结果以防止程序裂开便于捕获错误。
Reflect.set(源数据,"键","修改的值") 修改对象数据
Reflect.get(源数据,"键") 读取对象数据
Reflect.deleteProperty(源数据,"键") 删除对象数据
【两件法宝】setup形参:
父级:
<template>
<h1>爸爸</h1>
//引入的子组件 //自定义事件
<hello-world msg="草拟吗" md="妈的" @fuck="fu">
//匿名插槽传结构
<view>爸爸传的匿名插槽插槽曹</view>
//具名插槽传结构
<template v-slot:qwq>
爸爸的qwq插槽
</template>
</hello-world>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
import {h} from "vue"
import {ref, reactive} from "vue";
export default {
name: 'App',
components: {
HelloWorld
},
setup() { //回调参数
function fu(value){
alert("我是你大爹:"+value)
}
return {
fu
}
}
}
</script>
子级:
<template>
<h1 style="width: 100px;height: 100px;background-color: #42b983">{{msg}}</h1>
//接收父级传的结构
<slot></slot>
<button @click="test">儿子按钮</button>
<slot name="qwq"></slot>
</template>
<script>
export default {
name: 'HelloWorld',
//传参名称
props:['msg','md'],
//自定义事件名称
emits:['fuck'],
// props接受的参数 上下文对象:没有接受的参数attrs 插槽内容 父级传的自定义函数等;
setup(props,context){
function test(){
//自定义事件名称,给父级传的参数
context.emit("fuck","骚狐狸")
}
return{
test
}
}
}
</script>
【神机妙算】计算属性:
<template>
<h1>我的信息</h1>
姓:<input type="text" v-model="ren.name1">
<br>
名:<input type="text" v-model="ren.name2">
<h1> 名字: <input type="text" v-model="ren.name"> </h1>
</template>
<script>
import {h} from "vue"
//计算属性需要引入
import {ref, reactive, computed} from "vue";
export default {
name: 'App',
setup() {
let ren = reactive({
name1: "杨",
name2: "键",
})
//偷懒写法
// ren.name = computed(() => {
// return ren.name1 + "~" + ren.name2
// })
// 完整写法
ren.name = computed({
get(){
return ren.name1 + "~" + ren.name2
},
set(value){
// 拿到ren.name 做些操作
console.log(value)
}
})
return {
ren
}
}
}
</script>
【瞅你咋地】监视属性:
reactive定义的当监视数据是函数返回的deep才有用,否则默认强制开启。
reactive定义的当监视数据不是函数返回的就无法获取正确的oldvalue。
//监视ref定义的一个响应数据 不需要.value
watch(被监视数据,(新,旧)=>{},{deep、immediate等等配置项})
//监视ref定义的多个响应数据
watch([被监视数据1,被监视数据2,被监视数据3],([新1,新2],[旧1,旧2])=>{},{deep、immediate等等配置项})
//监视reactive定义的多个响应数据 ref定义的引用数值需要.value也可以加deep解决
// 重大问题:1、此处无法获取正确的oldvalue
// 2、默认强制开启深度监听无法通过配置项关闭
watch(数据,(新,旧)=>{},{immediate等等配置项})
//监视reactive定义的指定单个响应数据 ref定义的引用数值需要.value也可以加deep解决
watch( ()=>数据.键,(新,旧)=>{},{immediate等等配置项})
//监视reactive定义的指定一些响应数据 ref定义的引用数值需要.value也可以加deep解决
watch( [()=>数据.键,()=>数据.键,],(新,旧)=>{},{immediate等等配置项})
//监视reactive定义的指定的引用数据 此时deep有用 ref定义的引用数值需要.value也可以加deep解决
watch( ()=>数据.键,(新,旧)=>{},{deep、immediate等等配置项})
超级无敌智能监视:
watchEffect(()=>{
//在这里面用谁,就监视谁,谁动就执行,可以检测多个数据变化,默认深度监视
})
【花开花落】vue3生命周期
setup()生命周期在beforeCreate之前。
上面八个生命周期可以在setup里写,需要统一在vue引入,前面加统一加on,以函数的方式调用传入要执行的回调函数。如下图所示:
import {ref, reactive, computed,watch,watchEffect,onBeforeMount} from "vue";
export default {
name: 'App',
setup() {
onBeforeMount(()=>{
console.log("的")
})
return {
}
}
}
【厚德载物】hook自定义函数:
可以让vue3组合式api发挥巨大威力,一个完成的功能就是一个hook函数,不像vue2,数据、功能、监视、计算、生命周期拆开。
相当于vue2的混入,你可以把vue的所有api(ref、reactive、on生命周期等)用于写一个功能返回并导出实现代码复用。
【引蛇出洞】toRef、toRefs:
作用:
toRef:创建ref对象可以让你把对象里的属性单独拿去用还不丢失响应式,用对象而不用点运算符取。
toRefs:把对象的一级属性全部暴露取出。
<template>
{{sonName }}
{{ name }}
{{ age }}
</template>
<script>
import {ref, reactive, toRef, toRefs} from "vue";
export default {
name: 'App',
setup() {
let son = reactive({
name: "啊狗",
age: 88
})
let fu = reactive({
name: "大狗",
age: 22
})
let sonName = toRef(son, 'age')
return {
sonName,
...toRefs(fu)
}
}
}
</script>
【三十六变】shallowReactive、shallowRef(vue引入):
shallowReactive():只考虑对象的一级属性的响应。
应用场景:1、数据比较深;2、只要求一级属性响应。
shallowRef():如果传入对象则不考虑对象一级属性的响应。
应用场景:1、不要求对象一级响应要整体替换的时候。
【数据保安】readonly、shallowReadonly:
readonly(): 接收ref、reactive生成的数据让数据所有地方不可改变。
shallowReadonly(): 只让对象的一级属性不可改变。
【返璞归真】toRaw、markRaw:
toRaw():只能把reactive的响应对象变成普通对象;
markRaw():让普通对象终身无法响应,给reactive对象添加的普通数据会自动变成响应对象,如果你没有让新对象响应的需求,那你就安排这个标记函数,提高效率。
【毛坯房】customRef:
customRef可以在响应中读取或者写入修改数据中写入自己个性化的代码。比如在输入框输入数值一秒后再改变,只能处理基本类型。
<template>
<input type="text" v-model="didi">
<h1>{{ didi }}</h1>
</template>
<script>
import {ref, reactive, toRef, toRefs, customRef} from "vue";
export default {
name: 'App',
setup() {
function myRef(value) {
let timer;
return customRef((track, trigger) => {
return {
get() {
track()//追踪value最新的数据变化,如果不调用则返回旧数据
return value
},
set(v) {
clearTimeout(timer)
timer = setTimeout(() => {
value = v
trigger() //让vue重新解析模板
}, 1000)
}
}
})
}
let didi = myRef("哈哈")
return {
didi
}
}
}
</script>
【祖先的恩赐】
祖代传:引入provide,provide(键名,值)
后代收:引入inject,inject(键名)
【验明正身】
isRef:是否为ref对象;
isReactive:是否为reactive创建的响应代理对象;
isReadonly:是否为readonly创建的只读代理对象;
isProxy:是否由reactive或者readonly创建的代理对象;
【新人报道】
Fragment:vue3默认给你包一个根标签就是 Fragment标签,可以减少不必要的标签。
Teleport:可以让你写的结构不在写结构的位置出现,可以在任意位置出现。
<!-- 想传送到哪里的标签名、或者选择器#id-->
<teleport to="html">
<div v-if="show" style="width: 100px;height: 100px;background-color: yellow">
<h1>我说弹窗</h1>
<button @click="show=false">关闭</button>
</div>
</teleport>
Suspense:可以让组件异步出现,需要配合动态引入;
<template>
<div style="background-color: #42b983;padding: 30px">
孙子的{{b}}
<Suspense>
//组件加载完展示真实的组件内容
<template v-slot:default>
<Dialog />
</template>
//组件没加载完展示的虚假内容
<template v-slot:fallback>
等等我
</template>
</Suspense>
</div>
</template>
<script>
import {inject,ref,defineAsyncComponent} from "vue";
//动态引入 页面会先渲染,再渲染组件
let Dialog = defineAsyncComponent(()=> import("@/components/Dialog"))
export default {
name: "sun",
components:{
Dialog
},
setup(){
let show = ref(false)
return {
show
}
}
}
</script>
在以上的基础上,setup函数可以返回一个new Promise 或者给setup写成async函数。.
坑坑洼洼
获取dom对象
首先只有在挂载后才能获取到元素对象,所以获取的属性值要写在挂载声明周期;
机构写法
<div ref="dom"> </div>
js写法
let dom = ref(null);
onMounted(()=>{
console.log(dom.value)
})
return{
dom
}