构建vite项目
一、ref
接受一个内部值并返回一个响应式且可变的 ref 对象。ref 对象仅有一个 .value
property,指向该内部值。
改为ref
Ref TS对应的接口
interface Ref<T> {
value: T
}
注意被ref包装之后需要.value 来进行赋值
isRef
判断是不是一个ref对象
import { ref, Ref,isRef } from 'vue'
let message: Ref<string | number> = ref("我是message")
let notRef:number = 123
const changeMsg = () => {
message.value = "change msg"
console.log(isRef(message)); //true
console.log(isRef(notRef)); //false
}
``二、reactive`
用来绑定复杂的数据类型 例如 对象 数组
reactive 源码约束了我们的类型
他是不可以绑定普通的数据类型
这样是不允许 会给我们报错
绑定普通的数据类型 我们可以 使用昨天讲到ref
你如果用ref去绑定对象 或者 数组 等复杂的数据类型 我们看源码里面其实也是 去调用reactive
使用reactive 去修改值无须.value
reactive 基础用法
import { reactive } from 'vue'
let person = reactive({
name:"小满"
})
person.name = "大满"
数组异步赋值问题
这样赋值页面是不会变化的因为会脱离响应式
let person = reactive<number[]>([])
setTimeout(() => {
person = [1, 2, 3]
console.log(person);
},1000)
解决方案1
使用push
import { reactive } from 'vue'
let person = reactive<number[]>([])
setTimeout(() => {
const arr = [1, 2, 3]
person.push(...arr)
console.log(person);
},1000)
方案2
包裹一层对象
type Person = {
list?:Array<number>
}
let person = reactive<Person>({
list:[]
})
setTimeout(() => {
const arr = [1, 2, 3]
person.list = arr;
console.log(person);
},1000)
readonly
拷贝一份proxy对象将其设置为只读
import { reactive ,readonly} from 'vue'
const person = reactive({count:1})
const copy = readonly(person)
//person.count++
copy.count++
shallowReactive
只能对浅层的数据 如果是深层的数据只会改变值 不会改变视图
案例
<template>
<div>
<div>{{ state }}</div>
<button @click="change1">test1</button>
<button @click="change2">test2</button>
</div>
</template>
<script setup lang="ts">
import { shallowReactive } from 'vue'
const obj = {
a: 1,
first: {
b: 2,
second: {
c: 3
}
}
}
const state = shallowReactive(obj)
function change1() {
state.a = 7
}
function change2() {
state.first.b = 8
state.first.second.c = 9
console.log(state);
}
</script>
<style>
</style>
三、**认识to系列全家桶(toRef toRefs toRaw
)
toRef
如果原始对象是非响应式的就不会更新视图 数据是会变的
<template>
<div>
<button @click="change">按钮</button>
{{state}}
</div>
</template>
<script setup lang="ts">
import { reactive, toRef } from 'vue'
const obj = {
foo: 1,
bar: 1
}
const state = toRef(obj, 'bar')
// bar 转化为响应式对象
const change = () => {
state.value++
console.log(obj, state);
}
</script>
如果原始对象是响应式的是会更新视图并且改变数据的
toRefs
可以帮我们批量创建ref对象主要是方便我们解构使用
import { reactive, toRefs } from 'vue'
const obj = reactive({
foo: 1,
bar: 1
})
let { foo, bar } = toRefs(obj)
foo.value++
console.log(foo, bar);
toRaw
将响应式对象转化为普通对象
import { reactive, toRaw } from 'vue'
const obj = reactive({
foo: 1,
bar: 1
})
const state = toRaw(obj)
// 响应式对象转化为普通对象
const change = () => {
console.log(obj, state);
}
四、认识computed计算属性
computed用法
计算属性就是当依赖的属性的值发生变化的时候,才会触发他的更改,如果依赖的值,不发生变化的时候,使用的是缓存中的属性值。
1 函数形式
import { computed, reactive, ref } from 'vue'
let price = ref(0)//$0
let m = computed<string>(()=>{
return `$` + price.value
})
price.value = 500
2 对象形式
<template>
<div>{{ mul }}</div>
<div @click="mul = 100">click</div>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
let price = ref<number | string>(1)//$0
let mul = computed({
get: () => {
return price.value
},
set: (value) => {
price.value = 'set' + value
}
})
</script>
<style>
</style>
computed购物车案例
<template>
<div>
<input placeholder="请输入名称" v-model="keyWord" type="text">
<table style="margin-top:10px;" width="500" cellspacing="0" cellpadding="0" border>
<thead>
<tr>
<th>物品</th>
<th>单价</th>
<th>数量</th>
<th>总价</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in searchData">
<td align="center">{{ item.name }}</td>
<td align="center">{{ item.price }}</td>
<td align="center">
<button @click="item.num > 1 ? item.num-- : null">-</button>
<input v-model="item.num" type="number">
<button @click="item.num < 99 ? item.num++ : null">+</button>
</td>
<td align="center">{{ item.price * item.num }}</td>
<td align="center">
<button @click="del(index)">删除</button>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="5" align="right">
<span>总价:{{ total }}</span>
</td>
</tr>
</tfoot>
</table>
</div>
</template>
<script setup lang='ts'>
import { reactive, ref,computed } from 'vue'
let keyWord = ref<string>('')
interface Data {
name: string,
price: number,
num: number
}
const data = reactive<Data[]>([
{
name: "小满的绿帽子",
price: 100,
num: 1,
},
{
name: "小满的红衣服",
price: 200,
num: 1,
},
{
name: "小满的黑袜子",
price: 300,
num: 1,
}
])
let searchData = computed(()=>{
return data.filter(item => item.name.includes(keyWord.value))
})
let total = computed(() => {
return data.reduce((prev: number, next: Data) => {
return prev + next.num * next.price
}, 0)
})
const del = (index: number) => {
data.splice(index, 1)
}
</script>
<style scoped lang='less'></style>
五、认识watch侦听器
watch 需要侦听特定的数据源,并在单独的回调函数中执行副作用
watch第一个参数监听源
watch第二个参数回调函数cb(newVal,oldVal)
watch第三个参数一个options配置项是一个对象{
immediate:true //是否立即调用一次
deep:true //是否开启深度监听
}
监听Ref 案例
import { ref, watch } from 'vue'
let message = ref({
nav:{
bar:{
name:""
}
}
})
watch(message, (newVal, oldVal) => {
console.log('新的值----', newVal);
console.log('旧的值----', oldVal);
},{
immediate:true,
deep:true
})
监听多个ref 注意变成数组啦
import { ref, watch ,reactive} from 'vue'
let message = ref('')
let message2 = ref('')
watch([message,message2], (newVal, oldVal) => {
console.log('新的值----', newVal);
console.log('旧的值----', oldVal);
})
监听Reactive
使用reactive监听深层对象开启和不开启deep 效果一样
import { ref, watch ,reactive} from 'vue'
let message = reactive({
nav:{
bar:{
name:""
}
}
})
watch(message, (newVal, oldVal) => {
console.log('新的值----', newVal);
console.log('旧的值----', oldVal);
})
案例2 监听reactive 单一值
import { ref, watch ,reactive} from 'vue'
let message = reactive({
name:"",
name2:""
})
watch(()=>message.name, (newVal, oldVal) => {
console.log('新的值----', newVal);
console.log('旧的值----', oldVal);
})