文章目录
响应式
- ref:深层响应性
- reactive:使对象本身具有响应性
<template>
<div> {{ count }}</div>
<div> {{ count1 }}</div>
<div> {{ Obj1 }}</div>
<button @click="increment"> test </button>
</template>
<script setup>
import { ref } from 'vue'
import { reactive } from 'vue'
const count = ref(0)
let count1 = 12
const Obj1 = ref({
name: 'xiaomi', // 没加ref也会响应
age: { age1: 12 }, // 深层响应性,没加ref不会响应
})
const state = reactive( // 使对象本身具有响应性
{ count: 0,
age: { age1: 21 },
}
)
function increment() {
count1.value++ // 响应
count.value++ // 响应
Obj1.value.age.age1 = Obj1.value.age.age1 + 1 // 没加ref不响应
state.age.age1 = state.age.age1 + 1 // 响应
}
</script>
// ref额外解包:state里的变量会被新的ref替代,代替之后不会影响之前的
<script setup>
const count = ref(0) // count.value = 0
const state = reactive({
count
})
console.log(state.count) // 0
state.count = 1
console.log(count.value) // 1
const otherCount = ref(2)
state.count = otherCount //state里的count替换成新的变量
console.log(state.count) // 2
// 原始 ref 现在已经和 state.count 失去联系
console.log(count.value) // 1
</script>
计算属性
<script setup>
import { reactive, computed } from 'vue'
const author = reactive({
name: 'John Doe',
books: [ 'test1', 'test2', 'test3' ]
})
// 一个计算属性 ref
const testMessage = computed(() => {
return author.books.length > 0 ? 'Yes' : 'No'
})
//可计算属性
const name = ref('John')
const age = ref('12')
const perInfo = computed({
get() {
return name.value + ' ' + age.value
},
set(newValue) {
// 注意:我们这里使用的是解构赋值语法
[name.value, age.value] = newValue.split(' ')
}
})
</script>
Class 与 Style 绑定
// class属性绑定在子组件上,会同步到子组件的根节点上
// 如果需要指定哪个根元素接收,通过组件的 $attrs 属性来实现指定
<MyComponent class="baz" />
<p :class="$attrs.class">Hi!</p>
<span>This is a child component</span>
// 除基本外还可以直接绑定样式对象或者样式数组
const styleObject = reactive({
color: 'red',
fontSize: '13px'
})
template
<div :style="styleObject"></div>
<div :style="[styleObject1, styleObject2]"></div>
生命周期
watch
// 可以监听单个ref,getter函数,数组
// 多个来源组成的数组,单个(ref,ref,getter)
watch([x, y, () => y.value], ([newx, newy, newy1]) => {
console.log(`xy is ${newx} ${newy} ${newy1}`)
})
// 不能直接监听响应式对象的属性值
const obj = reactive({ // reactive使对象本身具有响应性
count: 0,
perInfo: { age: 12 },
})
watch(obj.count, (count) => { // 错误,watch() 得到的参数是一个 number
console.log(`count is: ${count}`)
})
// 要写成getter
watch( () => obj.count, (count) => {
console.log(`count is: ${count}`)
})
// 深层监听对象
watch(obj, (newobj) => {
console.log(`newobj: ${newobj}`) // newobj is [object Object]
console.log(`count is ${newobj.count}`) // count is 123
console.log(`ageis ${newobj.perInfo.age}`) // age is 23
})
// watch:只追踪明确侦听的数据源
// watchEffect 初始化时一定会执行一次(收集要监听的数据) watchEffect 会根据其中的属性,自动监听其变化
组件上的ref
需要声明一个匹配模板 ref 属性值的ref
// 单组件 - 声明一个 ref 来存放该元素的引用,必须和模板里的 ref 同名
<input ref="input" />
const input = ref(null)
// v-for 中使用模板引用时,ref 中包含的值是一个数组
<li v-for="item in list" ref="itemRefs"> {{ item }} </li>
const itemRefs = ref([])
// 组件上的 ref
<Child ref="child" />
const child = ref(null)
传递 props
// 子组件 - defineProps 和 defineEmits仅可用于 <script setup> 之中
defineProps(['title']) // 接收
const props = defineProps(['title'])
// prop使用对象形式
defineProps( { title: String, likes: Number } )
// 搭配ts
defineProps<{ title?: String, likes?: Number }>()
console.log(props.title)
defineEmits(['enlarge-text']) // $emit传递
// 传值
defineEmits({
submit(payload: { email: string, password: string }) {}
})
// 搭配ts
defineEmits<{
(e: 'change', id: number): void
(e: 'update', value: string): void
}>()
emit('enlarge-text')
组件上实现双向绑定
// 父组件
<Child v-model="count" />
// 子组件
<div>parent bound v-model is: {{ model }}</div>
const model = defineModel() // 返回的值是一个 ref
function update() { model.value++ }
v-bind=“$ attrs” 和 v-on=“$listeners” 在Vue组件中有特殊的作用
- $ attrs: 包含了父作用域中不被prop所识别 (且获取) 的特性绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind=“$attrs” 传入内部组件。
- $ listeners: 包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on=“$ listeners” 传入内部组件。
简单来说:
v-bind=“$ attrs” 会将父组件中非Props属性绑定到当前组件;
v-on=“$listeners” 会将父组件中的事件监听器绑定到当前组件。
这两个属性通常在创建高级别的组件时非常有用,它们允许您将属性和监听器自动传递到某些内部组件中。
例如: 组件就可以自动获得父组件中的属性和事件了。
<my-component
v-bind="$ attrs"
v-on="$listeners">
</my-component>