生命周期函数
setup
创建实例前
onBeforeMount
挂载DOM前
onMounted
挂载DOM后
onBeforeUpdate
更新组件前
onUpdated
更新组件后
onBeforeUnmount
卸载销毁前
onUnmounted
卸载销毁后
vue3.0发生的变化
去掉了beforeCreate和created汉化,添加了setup函数
同一个生命周期可以触发多次
定义数据
<template>
<div>
<p>{{msg}} {{info}}</p>
<button @click="btnFn">点击</button>
</div>
</template>
<script>
export default {
setup () {
const info = 'world'
const btnFn = () => {
console.log(info)
}
return {
msg: 'hello',
info,
btnFn
}
}
}
</script>
【注】setup触发的时机在beforeCreate之前,此时无法访问this,因为组件实例此时尚未创建
该方法定义的数据不是响应式数据
响应式数据
reactive
<template>
<div>
<p>{{obj.msg}} {{obj.info}}</p>
<button @click="btnFn">点击</button>
</div>
</template>
<script>
import { reactive } from 'vue'
export default {
setup () {
const obj = reactive({
msg: 'hello',
info: 'world'
})
const btnFn = () => {
obj.msg = 'Hi'
}
return {
obj,
btnFn
}
}
}
</script>
【注】reactive方法包裹的对象中的数据都是响应式的
reactive中的对象属性如果重新赋值会失去响应式能力
toRef
<template>
<div>
<p>{{msg}} {{info}}</p>
<button @click="btnFn">点击</button>
</div>
</template>
<script>
import { reactive, toRef } from 'vue'
export default {
setup () {
const obj = reactive({
msg: 'hello',
info: 'world'
})
const msg = toRef(obj, 'msg')
const info = toRef(obj, 'info')
const btnFn = () => {
obj.msg = 'Hi'
}
return {
msg,
info,
btnFn
}
}
}
</script>
【注】toRef方法可以把对象中的单个属性取出并且保证响应式能力
toRefs
<template>
<div>
<p>{{msg}} {{info}}</p>
<button @click="btnFn">点击</button>
</div>
</template>
<script>
import { reactive, toRefs } from 'vue'
export default {
setup () {
const obj = reactive({
msg: 'hello',
info: 'world'
})
const { msg, info } = toRefs(obj)
const btnFn = () => {
obj.msg = 'Hi'
obj.info = 'friends'
}
return {
msg,
info,
btnFn
}
}
}
</script>
【注】toRefs可以批量解构对象中的属性,并保证属性的响应式能力
ref
<template>
<div>
<p>{{count}}</p>
<p>name: {{obj.name}} , age: {{obj.age}}</p>
<button @click="btnFn">点击</button>
</div>
</template>
<script>
import { ref } from 'vue'
export default {
setup () {
const count = ref(0)
const obj = ref({
name: 'zhangsan',
age: 16
})
const btnFn = () => {
count.value++
obj.value.name = 'lisi'
obj.value.age = 28
}
return {
count,
btnFn,
obj
}
}
}
</script>
【注】ref主要(也可以是对象和数组)用于定义基本类型的数据并保证响应式能力
ref定义的数据,在js中操作时需要通过value属性进行
计算属性
基础写法(只读)
<template>
<div>
<p>昨日价格:{{price}}</p>
<p>今日价格:{{dayPrice}}</p>
</div>
</template>
<script>
import { ref,computed } from 'vue'
export default {
setup () {
const price = ref(100)
const dayPrice = computed(() => {
return price.value + 10
})
return {
price,
dayPrice
}
}
}
</script>
【注】该写法中返回的计算属性,只能读,不能改
computed回调函数必须return,结果就是计算的结果
如果计算属性依赖的数据发生变化,那么会重新计算
不要在计算中中进行异步操作
高级写法(可读可写)
<template>
<div>
<p>昨日价格:{{price}}</p>
<p>今日价格:{{dayPrice}}</p>
<button @click="dayPrice = 30">点击</button>
</div>
</template>
<script>
import { ref,computed } from 'vue'
export default {
setup () {
const price = ref(100)
const dayPrice = computed({
get () {
return price.value + 10
},
set (val) {
// val接收新修改的计算属性的值
price.value = val - 10
}
})
return {
price,
dayPrice
}
}
}
</script>
监听器
1.监听ref定义的响应式数据
<template>
<div>
<p>count: {{count}}</p>
<button @click="count++">点击</button>
</div>
</template>
<script>
export default {
setup () {
const count = ref(0)
watch(count, (newValue, oldValue) => {
console.log(newValue, oldValue)
})
return {
count
}
}
}
</script>
【注】只能监听ref定义的普通数据类型
2.监听reactive定义的响应式数据
<template>
<div>
<p>
{{obj.name}},{{obj.age}}
</p>
<button @click="obj.name='ls'">点击</button>
</div>
</template>
<script>
export default {
setup () {
const obj = reactive({
name: 'zs',
age: 18
})
watch(obj, (value) => {
console.log(value) // {name:'ls',age:18}
})
return {
obj
}
}
}
</script>
【注】该方法中,监听的回调函数中的参数,都是修改后的整个对象
3.监听多个响应式数据数据
<template>
<div>
<p>n1: {{n1}} , n2: {{n2}}</p>
<button @click="btnFn">点击</button>
</div>
</template>
<script>
export default {
setup () {
const n1 = ref(1)
const n2 = ref(2)
watch([n1, n2], (newValue, oldValue) => {
console.log(newValue, oldValue) // [3,4] [1,2]
})
const btnFn = () => {
n1.value = 3
n2.value = 4
}
return {
n1, n2, btnFn
}
}
}
</script>
4.监听reactive定义的响应式数据的某一个属性
<template>
<div>
<p>name: {{obj.name}}, age: {{obj.age}}</p>
<button @click="obj.name='ls'">点击</button>
</div>
</template>
<script>
export default {
setup () {
const obj = reactive({
name: 'zs',
age: 16
})
watch(() => obj.name, (newValue, oldValue) => {
console.log(newValue, oldValue) //ls zs
})
return {
obj
}
}
}
</script>
5.选项配置
watch( 表达式1, 表达式2 , {
// 首次渲染组件就触发一次
immediate: true,
// 深度侦听,对象里面的数据如果发生变化,也会被侦听到
deep: true
})
ref属性
<template>
<div>
<div ref="pName">text</div>
<button @click="btnFn">点击</button>
</div>
</template>
<script>
export default {
setup () {
const pName = ref(null)
const btnFn = () => {
console.log(pName.value) // <div>text</div>
console.log(pName.value.innerText) // text
}
return {
pName,
btnFn
}
}
}
</script>
【注】单个Dom元素的获取时,ref不需要动态绑定
遍历获取Dom元素
<template>
<div>
<ul>
<li v-for="item,index in names" :key="index" :ref="liRefs">{{item}}</li>
</ul>
</div>
</template>
<script>
export default {
setup () {
const names = ref(['张三', '李四', '王五', '小红', '小明'])
const liRefs = (el) => {
// 每一个el都是一个dom元素
console.log(el)
console.log(el.innerHTML)
}
return {
names,
liRefs
}
}
}
</script>
【注】遍历获取Dom元素时,ref需要动态绑定
父子通讯
父传子
父组件
<template>
<div>
<h1>主页</h1>
<Son :price="dayPrice"></Son>
</div>
</template>
<script>
import Home from '@/views/Son.vue'
import { ref } from 'vue'
export default {
components: {
Son
},
setup () {
const dayPrice = ref(20)
return {
dayPrice
}
}
}
</script>
子组件
<template>
<div class="son">
<h3>子组件</h3>
<p>从父组件接收的值-----price :{{price}}</p>
</div>
</template>
<script>
export default {
name: 'Son',
props: {
price: {
type: Number
}
}
}
</script>
子传父
子组件
<template>
<div class="home">
<h3>子组件</h3>
<p>从父组件接收的值-----price :{{price}}</p>
<button @click="sendFn">点击</button>
</div>
</template>
<script>
export default {
name: 'Home',
emits: ['sendMoney'],
props: {
price: {
type: Number
}
},
setup (props, context) {
const sendFn = () => {
context.emit('sendMoney', 90)
}
return {
sendFn
}
}
}
</script>
父组件
<template>
<div>
<h1>主页</h1>
<p>父组件----{{dayPrice}}</p>
<Home :price="dayPrice" @sendMoney="rePrice"></Home>
</div>
</template>
<script>
import Home from '@/views/Home.vue'
import { ref } from 'vue'
export default {
components: {
Home
},
setup () {
const dayPrice = ref(20)
const rePrice = (val) => {
dayPrice.value = val
}
return {
dayPrice,
rePrice
}
}
}
</script>
依赖注入
祖先组件传入孙组件
祖先组件
<template>
<div>
<h1>父组件</h1>
<hr>
<Home></Home>
</div>
</template>
<script>
import Home from '@/views/Home.vue'
import { provide } from 'vue'
export default {
components: {
Home
},
setup () {
provide('count', 10)
}
}
</script>
子组件
<template>
<div>
<h3>子组件</h3>
<hr>
<About></About>
</div>
</template>
<script>
import About from './About.vue'
export default {
name: 'Home',
components: {
About
}
}
</script>
孙组件
<template>
<div class="about">
<h5>孙组件</h5>
<p>从祖先组件传过来的值----count: {{num}}</p>
</div>
</template>
<script>
import { inject } from 'vue'
export default {
setup () {
const num = inject('count')
return {
num
}
}
}
</script>
孙组件传值给祖先组件
祖先组件
<template>
<div>
<h1>父组件</h1>
<p>str: {{str}}</p>
<hr>
<Home></Home>
</div>
</template>
<script>
import Home from '@/views/Home.vue'
import { provide, ref } from 'vue'
export default {
components: {
Home
},
setup () {
const str = ref(null)
const sendFn = (val) => {
str.value = val
}
provide('sendVal', sendFn)
return {
str
}
}
}
</script>
子组件
<template>
<div>
<h3>子组件</h3>
<hr>
<About></About>
</div>
</template>
<script>
import About from './About.vue'
export default {
name: 'Home',
components: {
About
}
}
</script>
孙组件
<template>
<div class="about">
<h5>孙组件</h5>
<button @click="sendFn">点击</button>
</div>
</template>
<script>
import { inject } from 'vue'
export default {
setup () {
const valueFn = inject('sendVal')
const sendFn = () => {
valueFn('hello')
}
return {
sendFn
}
}
}
</script>
v-mode
父组件
<template>
<div>
<h1>父组件</h1>
<p>count: {{count}}</p>
<p>dayPrice: {{dayPrice}}</p>
<hr>
<Home v-model="count" v-model:price="dayPrice"></Home>
</div>
</template>
<script>
import Home from '@/views/Home.vue'
import { ref } from 'vue'
export default {
components: {
Home
},
setup () {
const count = ref(10)
const dayPrice = ref(100)
return {
count,
dayPrice
}
}
}
</script>
子组件
<template>
<div>
<h3>子组件</h3>
<p>从父组件接收的值----modelValue: {{modelValue}}</p>
<p>从父组件接收的值----price: {{price}}</p>
<button @click="changeFn">点击</button>
</div>
</template>
<script>
export default {
props: {
modelValue: {
type: Number
},
price: {
type: Number
}
},
setup (props, { emit }) {
const changeFn = () => {
// 子组件将该过的值传输给父组件
emit('update:modelValue', 30)
emit('update:price', 99)
}
return {
changeFn
}
}
}
</script>
【注】v-model 默认绑定的属性是modelValue,默认绑定的事件是@update:modelValue
v-model 在vue3.0中,可以在一个组件中绑定多个
v-model:属性名称='属性值'
【注】$event在事件中的不同意义
-
用到表单元素上:$event表示事件对象
-
用到组件上:$event表示子组件传递的数据