生命周期钩子函数
vue2的生命周期函数
- beforeCreate
- created
- beforeMount
- mounted
- beforeUpdate
- updated
- beforeDestroy
- destroyed
vue3的生命周期函数
- setup 创建实例前
- onBeforeMount 挂载DOM前
- onMounted 挂载DOM后
- onBeforeUpdate 更新组件前
- onUpdated 更新组件后
- onBeforeUnMount 卸载销毁前
- onUnMounted 卸载销毁后
创建vue应用实例基本步骤:
- 在main.js中导入createApp函数
- 定义App.vue组件,导入main.js
- 使用createApp函数基于App.vue组件创建应用实例
- 挂载至index.html的#app容器
import { createApp } from "vue"
import App from "./app.vue"
const app = createApp(App)
app.mount('#app')
选项API和组合API
在vue2.x项目中使用的就是 选项API 写法(Options ApI
)
代码风格:data选项写数据,methods选项写函数…,一个功能逻辑的代码分散。
- 优点:易于学习和使用,写代码的位置已经约定好
- 缺点:代码组织性差,相似的逻辑代码不便于复用,逻辑复杂代码多了不好阅读。
- 补充:虽然提供mixins用来封装逻辑,但是出现数据函数覆盖的概率很大,不好维护。
在vue3.0项目中将会使用 组合API 写法(Compositon API)
代码风格:一个功能逻辑的代码组织在一起(包含数据,函数…)
- 优点:功能逻辑复杂繁多情况下,各个功能逻辑代码组织再一起,便于阅读和维护
- 缺点:需要有良好的代码组织能力和拆分逻辑能力,PS:大家没问题。
- 补充:为了能让大家较好的过渡到vue3.0的版本来,也支持vue2.x选项API写法
setup组件选项函数
- setup是一个新的组件选项,作为组件中使用组合API的起点。
- 从组件生命周期来看,它的执行在组件实例创建之前vue2.x的beforeCreate执行。
- 这就意味着在setup函数中 this 还不是组件实例,this 此时是 undefined
- 在模版中需要使用的数据和函数,需要在 setup 返回。
在这个函数中做的事情有:
1.定义响应式变量
const object= reactive({ test: 'aaa' })
const count = ref(0)
2.定义方法
const count = ref(0)
const countAdd = function(){
count.value++
}
3.执行钩子函数
onMounted(() => {
document.addEventListener("mousemove",move)
})
4. 定义计算属性
const age = ref(18);
const newAge = computed(()=>{
return age.value + 2
})
5.监听数据
const count = ref(0)
const obj = reactive({
name: "小名",
age: '18',
brand:{
id: 1,
name: 'AAAAAA'
}
});
const updateBrandName = function(){
obj.brand.name = "小花qqqq"
}
//监听某个响应式数据
watch(obj,()=>{
console.log("obj数据改变了")
})
//监听多个响应式数据
watch([count,obj],()=>{
console.log("obj数据改变了")
})
//监听对象中的某个属性的变化
watch(()=>obj.brand,()=>{
console.log("obj.brand数据改变了222")
},{
deep: true
})
最后将所有的变量和方法等数据return出去,在模板中使用
响应式函数(reactive、ref、toRef、toRefs)
1.定义复杂响应式数据:reactive
reactive是一个函数,它可以定义一个复杂数据类型,成为响应式数据。
<template>
<div class="container">
<div>{{obj.name}}</div>
<div>{{obj.age}}</div>
<button @click="updateName">修改数据</button>
</div>
</template>
<script>
import { reactive } from 'vue'
export default {
setup () {
//定义响应式数据
const obj = reactive({
name: 'ls',
age: 18
})
// 修改名字
const updateName = () => {
obj.name = 'zs'
}
return { obj ,updateName}
}
}
2.定义简单响应式数据:ref
ref函数,常用于简单数据类型定义为响应式数据
- 在修改值,获取值的时候,需要.value
- 在模板中使用ref申明的响应式数据,可以省略.value
setup () { // 1. name数据 const name = ref('ls') //console.log(name) const updateName = () => { name.value = 'zs' } // 2. age数据 const age = ref(10)
<span class="token comment">// ref常用定义简单数据类型的响应式数据</span> <span class="token comment">// 其实也可以定义复杂数据类型的响应式数据</span> <span class="token comment">// 对于数据未之的情况下 ref 是最适用的</span> <span class="token comment">// const data = ref(null)</span> <span class="token comment">// setTimeout(()=>{<!-- --></span> <span class="token comment">// data.value = res.data</span> <span class="token comment">// },1000)</span> <span class="token keyword">return</span> <span class="token punctuation">{<!-- --></span>name<span class="token punctuation">,</span> age<span class="token punctuation">,</span> updateName<span class="token punctuation">}</span>
使用场景:
- 当你明确知道需要的是一个响应式数据 对象 那么就使用 reactive 即可
- 其他情况使用ref
3.转换响应式对象中某个属性为单独响应式数据:toRef函数
setup () {
// 1. 响应式数据对象
const obj = reactive({
name: 'ls',
age: 10
})
console.log(obj)
// 2. 模板中只需要使用name数据
// 注意:从响应式数据对象中解构出的属性数据,不再是响应式数据
// let { name } = obj 不能直接解构,出来的是一个普通数据
const name = toRef(obj, 'name')
// console.log(name)
const updateName = () => {
console.log('updateName')
// toRef转换响应式数据包装成对象,value存放值的位置
name.value = 'zs'
}
return {name, updateName}
}
4.转换响应式对象中所有属性为单独响应式数据:toRefs函数
setup () {
// 1. 响应式数据对象
const obj = reactive({
name: 'ls',
age: 10
})
// console.log(obj)
// 2. 解构或者展开响应式数据对象
const obj3 = toRefs(obj)
// console.log(obj3)
const updateName = () => {
// obj3.name.value = 'zs'
obj.name = 'zs'
}
return {...obj3, updateName}
}
获取Dom元素ref
-
单个元素:先申明ref响应式数据,返回给模版使用,通过ref绑定数据
-
遍历的元素:先定义一个空数组,定一个函数获取元素,返回给模版使用,通过ref绑定这个函数
<template> <div class="container"> <!-- 单个元素 --> <div ref="dom">我是box</div> <!-- 被遍历的元素 --> <ul> <li v-for="i in 4" :key="i" :ref="setDom">第{{i}}LI</li> </ul> </div> </template> <script> import { onMounted, ref } from 'vue' export default { name: 'App', setup () { // 1. 获取单个元素 // 1.1 先定义一个空的响应式数据ref定义的 // 1.2 setup中返回该数据,你想获取那个dom元素,在该元素上使用ref属性绑定该数据即可。 const dom = ref(null) onMounted(()=>{ console.log(dom.value) }) // 2. 获取v-for遍历的元素 // 2.1 定义一个空数组,接收所有的LI // 2.2 定义一个函数,往空数组push DOM const domList = [] const setDom = (el) => { domList.push(el) } onMounted(()=>{ console.log(domList) }) return {dom, setDom} } } </script>
父子组件通讯
父传子的时候,可以用子组件的setup的第一个参数获取
父组件引入子组件,并绑定数据和方法
<template> <div class="container"> <h1>父组件money={{ money }}</h1> <ChildCom :money="money" @moneyChange="updateMoney"></ChildCom> </div> </template> <script> import { ref, provide } from 'vue' import ChildCom from "./components/ChildCom.vue" export default { name: 'App', components:{ ChildCom }, setup () { const money = ref(100) const updateMoney = (newMoney)=>{ money.value = newMoney } return{ money, updateMoney } } } </script>
子组件接收
<template> <div> <h1>子组件</h1> <div>父组件传过来的数据{{money}}</div> </div> </template> <script> export default { props: { money: { type: Number, default: 0 } }, setup (props) { // 获取父组件数据money const money = props.money return {money} } }
子传父的时候,用到setup的第二个参数
子组件setup中还有一个参数,包含了emit方法,其他思想与vue2一样
- 父传子:在setup种使用props数据 setup(props){ // props就是父组件数据 }
- 子传父:触发自定义事件的时候emit来自 setup(props,{emit}){ // emit 就是触发事件函数 }
//模板中加一个按钮
<button @click="changeMoney">花1元</button>
//js里加一个changeMoney方法
props: {
money: {
type: Number,
default: 0
}
},
setup(props,context){
// 获取父组件的数据
const money = props.money
const changeMoney = ()=>{
context.emit("moneyChange",50)
}
return {money,changeMoney}
}
子组件拿到父组件的值,并且赋值给新的变量用,用ref定义新变量
<template>
<div>
<h1>子组件</h1>
<div>父组件传过来的数据{{newMoney}}</div>
<button @click="changeMoney">花1元</button>
</div>
</template>
props: {
money: {
type: Number,
default: 0
}
},
setup(props,context){
const money = props.money
const newMoney = ref(money)
const changeMoney = ()=>{
newMoney.value--;
context.emit("moneyChange",newMoney)
}
return {newMoney,changeMoney}
}
使用provide函数和inject函数完成后代组件数据通讯
- provide函数提供数据和函数给后代组件使用
- inject函数给当前组件注入provide提供的数据和函数
将数据提供给后代组件 provide
//模板中不需要加数据
<ChildCom @moneyChange="updateMoney"></ChildCom>
setup () {
const money = ref(100)
const updateMoney = (newMoney)=>{
money.value = newMoney
}
// 将数据提供给后代组件 provide
provide(‘money’, money)
// 将函数提供给后代组件 provide 暂时没用到这个方法
// provide(‘updateMoney’, updateMoney )
return {
money }
}
接收祖先组件提供的数据(不需要写props组件选项)
setup () {
// 接收祖先组件提供的数据
const money = inject('money')
return { money }
}
子组件拿到父组件的值,并且赋值给新的变量用,用ref定义新变量
这个money是个响应式变量,定义新变量的时候赋值money.value
setup(props,context){
const money = inject("money")
const newMoney = ref(money.value)
const changeMoney = ()=>{
newMoney.value--;
context.emit("moneyChange",newMoney)
}
return {newMoney,changeMoney}
}