文章目录
- 1. computed计算属性
- 2. watch侦听器属性
- 2.1 watchEffect
- 2.2 watch
1. computed计算属性
简写写法(只实现了 get ):
<template>
<div>
<ul>
<li v-for="item of carts" :key="item.id">
{{ item.name }}
</li>
</ul>
<hr />
<h3>合计:{{ totalPrice }}</h3>
</div>
</template>
<script>
import { computed, reactive, toRefs } from 'vue'
export default {
setup() {
let state = reactive({
carts: [
{ id: 1, name: '小米', price: 1, num: 1 },
{ id: 2, name: '大米', price: 1, num: 1 }
],
total: 0
})
// 计算属性 -- get
let totalPrice = computed(() => {
return state.carts.reduce((p, { price, num }) => {
p += price * num
return p
}, 0)
})
// let totalPrice = computed({
// get() {
// return state.carts.reduce((p, { price, num }) => {
// p += price * num
// return p
// }, 0)
// }
// })
return { ...toRefs(state), totalPrice }
}
}
</script>
<style lang="scss" scoped>
</style>
标准写法(可以实现 get 和 set 方法):
<template>
<div>
<ul>
<li v-for="item of carts" :key="item.id">
{{ item.name }}
</li>
</ul>
<hr />
<h3>合计:{{ totalPrice }}</h3>
</div>
</template>
<script>
import { computed, reactive, toRefs } from 'vue'
export default {
setup() {
let state = reactive({
carts: [
{ id: 1, name: '小米', price: 1, num: 1 },
{ id: 2, name: '大米', price: 1, num: 1 }
],
total: 0
})
let totalPrice = computed({
get() {
return state.carts.reduce((p, { price, num }) => {
p += price * num
return p
}, 0)
},
// 了解一下
set(v) {
console.log('set', v)
}
})
// 如果你给计算属性赋值,则一定要写标准方式,set方法一定要写
totalPrice.value = 'abc'
return { ...toRefs(state), totalPrice }
}
}
</script>
<style lang="scss" scoped>
</style>
完整的购物车案例:
<template>
<div>
<h3>{{ total }}</h3>
<ul>
<li v-for="(item, index) of carts" :key="item.id">
<span>{{ item.name }}</span>
<span>
<button @click="setNum(index, 1)">+</button>
<button @click="totalPrice = { index, n: 1 }">另一种实现求和的方式</button>
<span>{{ item.num }}</span>
<button @click="setNum(index, -1)">-</button>
</span>
</li>
</ul>
<hr />
<h3>合计:{{ totalPrice }}</h3>
</div>
</template>
<script>
import { computed, reactive, toRefs } from 'vue'
export default {
setup() {
let state = reactive({
carts: [
{ id: 1, name: '小米', price: 1, num: 1 },
{ id: 2, name: '大米', price: 1, num: 1 }
],
total: 0
})
let totalPrice = computed({
get() {
return state.carts.reduce((p, { price, num }) => {
p += price * num
return p
}, 0)
},
// 求和方式2:
set(v) {
if (v.n) {
state.carts[v.index].num += v.n
}
}
})
// 求和方式1:
const setNum = (index, n) => {
state.carts[index].num += n
if (state.carts[index].num <= 1) state.carts[index].num = 1
if (state.carts[index].num >= 10) state.carts[index].num = 10
}
return { ...toRefs(state), totalPrice, setNum }
}
}
</script>
<style lang="scss" scoped></style>
2. watch侦听器属性
- watchEffect 是自动去根据方法中的调用来确定依赖项。
- watch 是手动指定依赖项 – 用它可能会多一些。
2.1 watchEffect
<template>
<div>
<h3>{{ num }}</h3>
<!-- 输入的内容发生变化时,控制台不会打印,因为 name 不是侦听器的依赖项 -->
<input type="text" v-model="name" />
<button @click="num++">+++</button>
<!-- <button @click="stop">停止侦听</button> -->
</div>
</template>
<script>
// watchEffect 自动去根据方法中的调用来确定依赖项
// watch 手动指定依赖项 -- 用它可能会多一些
import { ref, watch, watchEffect } from 'vue'
export default {
setup() {
const num = ref(100)
const name = ref('')
// 侦听,它必须要有依赖项
// 它在初始化时,会主动执行1次,如果没有依赖项,则不会再次执行
// watchEffect(() => {
// // 这里只会在初始时打印一次222
// console.log(222)
// })
watchEffect(() => {
// 此时它的依赖项为 num变量,如果它有改变,则回调函数会自动触发
// 它的依赖项可以是1到N个
console.log(222, num.value)
})
return { num,name }
}
}
</script>
<style lang="scss" scoped>
</style>
watchEffect 的返回值:
<template>
<div>
<h3>{{ num }}</h3>
<button @click="num++">+++</button>
<button @click="stop">停止侦听</button>
</div>
</template>
<script>
// watchEffect 自动去根据方法中的调用来确定依赖项
// watch 手动指定依赖项 -- 用它可能会多一些
import { ref, watch, watchEffect } from 'vue'
export default {
setup() {
const num = ref(100)
const stopHandle = watchEffect(() => {
console.log(222, num.value)
})
const stop = () => stopHandle()
return { num, stop }
}
}
</script>
<style lang="scss" scoped>
</style>
watchEffect 的 onCleanup 回调参数:
watchEffect 还有一个回调参数,此参数它也是一个函数,作用是清理副作用。
<template>
<div>
<h3>{{ num }}</h3>
<button @click="num++">+++</button>
<button @click="stop">停止侦听</button>
</div>
</template>
<script>
// watchEffect 自动去根据方法中的调用来确定依赖项
// watch 手动指定依赖项 -- 用它可能会多一些
import { ref, watch, watchEffect } from 'vue'
export default {
setup() {
const num = ref(100)
let timer
// 此方法它还有一个回调参数,此参数它也是一个函数,作用,清理副作用
const stopHandle = watchEffect(
onCleanup => {
console.log(num.value)
// console.log(222, num.value, name.value)
onCleanup(() => {
console.log('清理上一次的处理')
timer && clearTimeout(timer)
})
timer = setTimeout(() => {
console.log('输出的')
}, 1000)
},
{
// flush?: 'pre' | 'post' | 'sync';
// pre 模板渲染之前触发
// post 模板渲染之后触发
// sync 和模板渲染同步来触发
// 默认为 pres
flush: 'pre'
}
)
const stop = () => stopHandle()
return { num, stop }
}
}
</script>
<style lang="scss" scoped>
</style>
2.2 watch
监听一个变量值的变化:
<template>
<div>
<div>{{ num }} <button @click="num++">+++</button></div>
<input type="text" v-model="name" />
</div>
</template>
<script>
import { ref, watch } from 'vue'
export default {
setup() {
const num = ref(100)
const name = ref('')
// 监听num变量它的变化,如果有变化,则触发
watch(
num,
(newValue, oldValue) => {
console.log(newValue)
},
{
// 初始化执行1次,默认为false
immediate: false
}
)
return { num, name }
}
}
</script>
<style lang="scss" scoped>
</style>
监听多个变量值的变化:
<template>
<div>
<div>{{ num }} <button @click="num++">+++</button></div>
<input type="text" v-model="name" />
</div>
</template>
<script>
import { ref, watch } from 'vue'
export default {
setup() {
const num = ref(100)
const name = ref('')
// 以数组的方式来写,它可以监听多个变量的值的变化,回调参数为一个数组
watch([num, name], (nArr, oArr) => {
console.log(nArr)
})
// 在工作中,通常只关心新的值,所以只会写一个参数,就像下面这样
// watch([num, name], ([numValue, nameValue]) => {
// console.log(numValue, nameValue)
// })
return { num, name }
}
}
</script>
<style lang="scss" scoped>
</style>
监听对象中具体的值:
<template>
<div>
<input type="text" v-model="user.name" />
</div>
</template>
<script>
import { ref, watch } from 'vue'
export default {
setup() {
const user = ref({ id: 1, name: '张三' })
// 目前对于ref定义的引用类型,默认无法监听
// watch(user, (n, o) => {
// console.log(n)
// })
// 但是可以指定监听对象中具体的值
watch(
// 'obj.name'(n,o){}
() => user.value.name,
(n, o) => {
console.log(n)
}
)
return { user }
}
}
</script>
<style lang="scss" scoped>
</style>
监听ref的引用对象(添加参数3):
<template>
<div>
<input type="text" v-model="user.name" />
</div>
</template>
<script>
import { ref, watch } from 'vue'
export default {
setup() {
const user = ref({ id: 1, name: '张三' })
// 监听ref的引用对象 添加参数3
watch(user, (n, o) => {
console.log(n)
},{
deep:true
})
return { user }
}
}
</script>
<style lang="scss" scoped>
</style>
监听 reactive 定义的响应变量:
<template>
<div>
<input type="text" v-model="user.name" />
</div>
</template>
<script>
import { reactive, watch } from 'vue'
export default {
setup() {
const user = reactive({ id: 1, name: '张三' })
// 监听的是一个reactive定义的响应变量,它默认就可以进行深层监听
// 所以在工作中,如果你定义的值它是一个引用类型,建议使用reactive,基本类型用ref
const stop = watch(user, (n, o) => {
console.log(n)
})
return { user, stop }
}
}
</script>
<style lang="scss" scoped>
</style>