Vue3
1.toRef 方法
掌握toRef 方法的使用 方式及应用场景
一个小案例进行入门开始:
当按钮被点击时模版数据发生更新?
<template>
<p>{{ name }}</p> //数据不改变,
<p>{{ person.name }}</p>
<button @click="onClickHandler">button</button>
</template>
<script>
import { ref } from 'vue';
export default {
name:"App",
setup() {
const person = ref({name:"张三"});
const onClickHandler = () => {
person.value.name = "李四"
}
return {
name:person.value.name,
person,
onClickHandler,
}
}
}
</script>
toRef 方法用于将响应式数据内部的普通数据转换为响应式数据,并且转换后的数据和原始数据存在引用关系,存在引用关系意味着当原始数据发生变化后,toRef转换后的数据也会跟着变化。
<template>
<p>{{ name }}</p>
<p>{{ person.name }}</p>
<button @click="onClickHandler">button</button>
</template>
<script>
import { ref, toRef } from "vue";
export default {
name: "App",
setup() {
const person = ref({ name: "张三" });
const onClickHandler = () => {
person.value.name = "李四";
};
return {
name: toRef(person.value, "name"),
person,
onClickHandler,
};
},
};
</script>
需求:当响应式数据的结构层级比较深时,在模版中使用起来也比较繁琐,能不能在模版中使用时简化结构层级呢?
export default {
setup() {
const person = ref({brand:{name:"宝马"}});
return {
person
}
}
}
<template>
{{person.brand.name}}
</template>
如果能够将模版中的person.brand.name简化成brandName的话不就更加简洁?
import { ref } from "vue";
export default {
name:"App",
setup() {
const person = ref({brand:{name:"宝马"}})
const onClickHandler = () => {
person.value.brand.name = "奔驰"
}
return {
person,
brandName: person.value.brand.name,
onClickHandler
}
}
}
<template>
<p>
{{person}}
</p>
<p>
{{brandName}}
</p>
<button @click="onClickHandler">
button
</button>
</template>
import { ref } from "vue";
export default {
name:"App",
setup() {
const person = ref({brand:{name:"宝马"}})
const onClickHandler = () => {
person.value.brand.name = "奔驰"
}
return {
person,
brandName: toRef(person.value.brand,"name"),
onClickHandler
}
}
}
2.toRefs函数
掌握toRefs 方法批量转换响应式数据的方式。
toRef一次只能转换一次数据,通过toRefs方法可以实现批量数据的转换.
toRefs 方法接收引用数据类型的响应式数据,它可以将数据中的第一层属性全部转换为响应式数据,返回值是一个对象, 对象中存储了所有转换之后的响应式数据.
import {reactive,toRefs} from "vue";
export default {
name:"App",
setup() {
const person = reactive({
name:"张三",
age:20,
brand:{title:"宝马",year:1}
})
return {
...toRefs(person),...toRefs(person.brand)
}
}
}
<template>{{ name }} {{ age }} {{ title }} {{ year }}</template> //结果是依据以上reactive顺序进行输出
3.组件通讯
掌握组合式API中父子组件通信的方式
父组件给子组件传递数据通过子组件用props进行接收,例子如下:
<template>
<div>I am parent component</div>
<hr />
<ChildComp :msg="msg"></ChildComp>
</template>
<script>
import ChildComp from "./components/ChildComp.vue"
import { ref } from "vue"
export default {
components: { ChildComp },
setup() {
const msg = ref("a message from parent")
return { msg }
},
}
</script>
<template>
<div>
{{ childMsg }}
<hr />
{{ msg }}
</div>
</template>
<script>
import { computed } from "vue";
export default {
name: "ChildComponent",
props: ["msg"],
setup(props) {
// 当父组件更新 props 时 setup 函数是不会重新执行的
// 所以在 setup 函数中使用 props 时需要用到 computed 或者 watch 来响应 props 的变化
// 注意: 直接在模板中使用 props 数据是没有这个问题的
const childMsg = computed(() => props.msg + "😀😀");
return { childMsg };
},
};
</script>
子组件给父组件传递数据
<template>
<div>
{{ childMsg }}
<hr />
{{ msg }}
<hr />
<button @click="onMsgChanged">change msg</button>
</div>
</template>
<script>
import { computed } from "vue";
export default {
name: "ChildComponent",
props: ["msg"],
emits:["onMsgChanged"] //如果在模版中时使用代码片段,自定义时间需要被显示的声明在emits选项中
setup(props, { emit }) {
const onMsgChanged = () => {
emit("onMsgChanged", "changed msg from children");
};
return { onMsgChanged };
},
};
</script>
解析:首先给button绑定一个事件,当点击这个按钮的时候通过props第二个参数emits出发父组件事件进行数据传递以及更改。
<template>
<ChildComponent :msg="msg" @onMsgChanged="onMsgChanged" />
</template>
<script>
import { ref } from "vue";
import ChildComponent from "./components/child-component.vue";
export default {
components: { ChildComponent },
name: "App",
setup() {
const msg = ref("i am a message");
const onMsgChanged = (data) => {
msg.value = data;
};
return { msg, onMsgChanged };
},
};
</script>
父组件接收到自定义事件的数据也就是changed msg from children 用一个数据接收并且把msg里面的数据改成传递过来的数据。
4.组件生命周期
掌握组件生命周期函数的使用方式
setup 组件初次挂载前,重新挂载前都会执行
<!-- App组件 父组件 -->
<template>
<button @click="show = !show">toggle</button>
<ChildComponent v-if="show"></ChildComponent>
</template>
<script>
import { ref } from "vue";
import ChildComponent from "./components/child-component.vue";
export default {
components: { ChildComponent },
name: "App",
setup() {
const show = ref(true);
return { show };
},
};
</script>
<!-- ChildComponent 组件 子组件 -->
<template>child component</template>
<script>
export default {
name: "ChildComponent",
setup() {
// setup 函数会在组件每次重新渲染时执行
console.log("setup"); ->>>>>>>>>> 记住这里
},
};
</script>
解析一下,就是setup是挂载前和重新挂载后都会执行一次setup函数
<!-- child-component -->
<template>{{ count }} <button @click="onClickHandler">button</button></template>
<script>
import { onMounted, onUnmounted, onUpdated, ref } from "vue";
export default {
name: "ChildComponent",
setup() {
console.log("setup");
let timer = null;
// 组件挂载完成之后开启定时器
onMounted(() => {
timer = setInterval(() => {
console.log("timer...");
}, 1000);
});
// 组件卸载完成之后清除定时器
onUnmounted(() => {
clearInterval(timer);
});
const count = ref(0);
const onClickHandler = () => {
count.value = count.value + 1;
};
// 组件更新之后在控制台中输出 onUpdated
onUpdated(() => {
console.log("onUpdated");
});
return { count, onClickHandler };
},
};
</script>
结果走向:第一 ,从之前我们知道,只要组件一挂载起来setup第一个执行,onMouted是组件挂载完成后执行输出以上代码的定时器,如果数据已更新后onUpdated就回执行,再者就是onUnmounted是组件卸载后执行。
5.与服务端通信
掌握组合式API实现与服务器通讯的方式
向服务器端发送请求获取略表数据渲染列表数据,没有数据显示暂无数据,如果请求报错则展示错误信息,加载过程显示loading
import {ref} from "vue";
import axios from "axios";
export default {
//用于存储列表的数据
const data = ref(null);
//用于标示加载状态
const loading = ref(false);
//用于存储错误信息
const error = ref(null);
//用于发送请求的方法
async function getPosts() {
// 更新加载状态
loading.value = true;
try {
//发送请求
let response = await axios.get("https://jsonplaceholder.typicode.com/posts")
//存储列表数据
data.value = response.data;
} catch(err) {
err.value = err.message;
}
//更新加载状态
loading.value = false
}
//调用方放,发送请求
getPosts()
return {
data,loading.error
}
}
<template>
<div v-if="loading">加载中...</div>
<div v-else-if="error">{{ error }}</div>
<div v-else-if="data && data.length > 0">
<ul>
<li v-for="item in data">{{ item.title }}</li>
</ul>
</div>
<div v-else>暂无数据</div>
</template>
代码进行抽离修改成为如下代码:
6.获取DOM对象
掌握组合式API获取DOM对象方式
1.获取单个DOM对象
import {ref,onMounted} from "vue";
export default {
setup() {
const divRef = ref(null)
onMounted(()=> {
console.log(divRef.value)
})
return {divRef}
}
}
<template>
<div ref="divRef">
我是被获取的dom对象
</div>
</template>
2.获取多个dom对象
import {ref,onMounted,onUpdated} from "vue";
export default {
setup() {
const list = ref(['a','b','c'])
const list1 = ref([])
const onClickHandler = () => {
list.value.push('d')
}
onMounted(()=> console.log(list1.value))
onUpdated(()=> console.log(list1.value))
return {list,list1,onClickHandler}
}
}
<template>
<ul>
<li v-for="(item, index) in list" :key="index" :ref="(el) => (list1[index] = el)">
{{ item }}
</li>
</ul>
<button @click="onClickHandler">button</button>
</template>
7.provide,inject函数
掌握夸组件层级传递数据的方式
通过provide和inject配合使用可以实现夸组件传递数据(组件与组件是存在嵌套关系)
<!-- 父组件 App -->
<template>
<ChildComponent />
</template>
<script>
import { ref, provide } from "vue";
import ChildComponent from "./components/ChildComponent.vue";
export default {
components: { ChildComponent },
name: "App",
setup() {
const person = ref({ name: "张三" });
const changePerson = () => {
person.value.name = "李四";
};
provide("person", person);
provide("changePerson", changePerson);
},
};
</script>
<!-- 子组件 -->
<template>
<LastComponent />
</template>
<script>
import LastComponent from "./LastComponent.vue";
export default {
components: { LastComponent },
name: "ChildComponent",
};
</script>
<!-- 孙组件 -->
<template>
{{ person.name }}
<button @click="changePerson">button</button>
</template>
<script>
import { inject } from "vue";
export default {
name: "LastComponent",
setup() {
const person = inject("person");
const changePerson = inject("changePerson");
return { person, changePerson };
},
};
</script>
\