ref
ref接受一个内部值并返回一个响应式可变的ref对象
在模版中使用一个ref,当ref的值发生改变时,Vue会自动检测值的变化,并根据值更新DOM。
Ref 可以持有任何类型的值,包括深层嵌套的对象、数组或者 JavaScript 内置的数据结构,比如 Map
const count = ref(0)
const Person = ref({name:'张三'})
const arr = ref(['1','2','3'])
ref 也可以获取DOM,需要在DOM渲染之后获取
<script setup lang="ts">
import { isRef, ref } from 'vue';
const count = ref(0)
count.value = 5
console.log(isRef(count))
console.log(count.value)
const Person = ref({name:'张三'})
const arr = ref(['1','2','3'])
const htmlref = ref<HTMLInputElement>()
const outputInfo = ()=>{
console.log(htmlref.value)
}
</script>
<template>
<button @click="count++">{{ count }}</button>
<p>{{ Person.name }}</p>
<ul>
<li v-for="name in arr" :value="name" :key="name">{{ name }}</li>
</ul>
<input ref="htmlref" placeholder="输入数字">
<button @click="outputInfo">输出html</button>
</template>
reactive
reactive 定义一个对象类型的响应式数据,返回一个proxy实例对象,不能使用基础数据类型
ref和reactive都是将我们的变量变成响应式
ref 支持所有的类型,reactive引用类型 Array Object Map Set ref 取值 赋值 都需要加.value,reactive是不需要.value
<script setup lang="ts">
import { reactive } from 'vue';
type P = {
name:string,
age:number
}
const Person = reactive<P>({name:'张三',age: 18})
let list = reactive<string[]>([])
const addItem = ()=>{
// list.push('Hello')
let arr = ['hello','vue3','!']
//如果直接赋值 页面不会发生变化
// list = arr
//可以解构 给list赋值
list.push(...arr)
}
</script>
<template>
<div>
姓名: {{ Person.name }}<br>
年龄: {{ Person.age }}
</div>
<div>
<ul v-for="item in list" :key="item">
<li>{{ item }}</li>
</ul>
</div>
<button @click="addItem">添加</button>
</template>
toRef toRefs toRow
toRef
toRef 的作用是将一个响应式对象中的属性转换成单独的响应式引用
toRefs
toRefs 将一个对象的所有属性变成响应式引用,追踪原对象的引用关系
toRaw
toRaw 将一个响应式对象变成非响应式
<script setup lang="ts">
import { reactive, toRaw, toRef, toRefs } from 'vue';
let person = reactive({name:'张三',age: 18,like:'吃饭'})
let like = toRef(person,'like')
let {name, age} = toRefs(person)
const changeName = ()=>{
like.value = '睡觉'
console.log(person)
}
const changePerson = ()=>{
name.value = '李四'
age.value = 15
}
const toRawPerson = ()=>{
console.log(toRaw(person))
}
</script>
<template>
<div>
{{ person }}
</div>
<button @click="changeName">改变</button>
<button @click="changePerson">改变2</button>
<button @click="toRawPerson">改变3</button>
</template>
计算属性(computed)
computed 基于组件的响应式依赖进行复杂的计算,并返回一个新的响应式引用
<script setup lang="ts">
import { computed, ref } from 'vue';
let count = ref(1)
let count2 = computed(()=>count.value*2)
const changeCount = ()=>{
count.value = 2
}
</script>
<template>
<div>
原始数据{{ count }}<br>
计算后数据 {{ count2 }}<br>
</div>
<button @click="changeCount">改变数据</button>
</template>
应用场景
1.格式化数据
<script setup lang="ts">
import { computed, ref } from 'vue';
let date = ref(20240519)
let dateStr = computed(()=>{
let str = date.value.toString()
return str.substring(0,4)+`-`+str.substring(4,6)+`-`+str.substring(6,8)
})
</script>
<template>
<div>
<!-- 格式化数据---2024-05-19 -->
格式化数据---{{ dateStr }}<br>
</div>
</template>
2.对多个数据计算
<script setup lang="ts">
import { computed, ref } from 'vue';
let num = ref(5)
let price = ref(20)
let totalPrice = computed(()=>{
return num.value*price.value
})
</script>
<template>
<div>
<!-- 总价格---100 -->
总价格---{{ totalPrice }}<br>
</div>
</template>
3.减少模版中的逻辑计算,过滤,排序等操作
<script setup lang="ts">
import { computed, reactive } from 'vue'
type student = {
name:string,
age:number,
score:number,
}
let data = reactive<student[]>([
{name: '张三', age:18, score: 80},
{name: '李四', age:19, score: 60},
{name: '王五', age:20, score: 100 },
{name: '小李', age:18, score: 100 },
{name: '小小', age:16, score: 85}
]);
let dataLength = computed(()=>{
return data.length
})
let bestScore = computed(()=>{
let score = 0
let arr = []
for (const element of data) {
if(element.score>score){
score = element.score
}
}
for (const element of data) {
if(element.score==score){
arr.push(element)
}
}
return arr
})
let printArr = (array:student[])=>{
array.forEach(element => {
console.log('姓名:'+element.name+' 年龄:'+element.age+' 得分:'+element.score+'\n')
});
}
console.log('同学个数:'+dataLength.value);
printArr(bestScore.value)
</script>
<template>
<div>
</div>
</template>
列表渲染
列表渲染主要通过v-for循环数据渲染列表
遍历数组:v-for="(item, index) in items"
遍历对象:v-for="(value, key, index) in object"
绑定数据渲染列表
<script setup lang="ts">
import { ref } from 'vue'
let list = ref([
{text: 'A'},
{text: 'B'},
{text: 'C'}
])
</script>
<template>
<div>
<ul>
<li v-for="item in list">{{ item.text }}</li>
</ul>
</div>
</template>
v-for 还支持一个可选的第二个参数,参数值为当前项的索引:
<div>
<ul>
<li v-for="(item, index) in list">{{ index }}-----{{ item.text }}</li>
</ul>
</div>
v-for遍历对象
let object = reactive({
name:'张三',
age:20,
gendar:'man',
hobby:'睡觉'
})
<li v-for="value in object">{{ value }}</li>
支持第二个可选参数key
<li v-for="(value, key) in object">{{ key }}----{{ value }}</li>
第三个参数index
<li v-for="(value, key, index) in object">{{ index }}-{{ key }}--{{ value }}</li>
key管理状态
使用 v-for 渲染列表时,为每个项提供一个唯一的 key 属性,以便 Vue 能够识别每个项的唯一性,从而进行高效的 DOM 更新。 key应为字符串或数字,不能用对象最为key
<div v-for="item in items" :key="item.id">
<!-- 内容 -->
</div>
侦测数组变化
数组有一系列方法改变数组内容。
使原数组发生改变的方法有:push() pop() shift() unshift() splice() sort() reverse()
不改变原数组生成新数组的有:filter() concat() slice()
const arr = reactive([1,2,3,4,5,6,7])
const evenArr = computed(()=>{
return arr.filter((n)=>n%2===0)
})
<li v-for="(item,index) in evenArr" :key="index">{{ item }}</li>
watch侦听器
watch 的作用是用于监测响应式属性的变化,并在属性发生改变时执行特定的操作
watch 的第一个参数可以是不同形式的“数据源”:它可以是一个 ref (包括计算属性)、一个响应式对象、一个 getter 函数或多个数据源组成的数组:
第二个参数回调函数callback(newVal, oldVal)
第三个参数一个options配置项是一个对象{immediate:true,//是否立即调用一次 deep:true //是否开启深度监听once: true //监听一次}
<script setup lang="ts">
import { ref, watch } from 'vue'
let x = ref(0)
let y = ref(3)
watch(x,(newx)=>{
console.log(`x 的值 ${newx}`)
})
watch([x,y],([newx,newy])=>{
console.log(`x的值${newx}, y的值${newy}`)
})
watch(()=>x.value+y.value,(sum)=>{
console.log(`x+y的值为${sum}`)
})
const changeX = ()=>{
x.value++
}
const changeY = ()=>{
y.value++
}
</script>
<template>
<div>
<button @click="changeX">改变X</button>
<button @click="changeY">改变Y</button>
</div>
</template>
## watchEffect()
watchEffect 是 Vue 3 中提供的一个函数,用于创建即时执行的侦听器。它会立即执行一次传入的函数,同时会追踪函数内部使用到的响应式数据,当这些数据发生变化时,会再次执行该函数。
const num1 = ref(0)
watchEffect(()=>{
console.log(`num1的值发生了改变${num1.value}`)
})
num1.value = 5
打印
num1的值发生了改变0
num1的值发生了改变5
watch vs. watchEffect
watch 和 watchEffect 都能响应式地执行有副作用的回调。它们之间的主要区别是追踪响应式依赖的方式:
watch只追踪明确侦听的数据源。它不会追踪任何在回调中访问到的东西。另外,仅在数据源确实改变时才会触发回调。watch会避免在发生副作用时追踪依赖,因此,我们能更加精确地控制回调函数的触发时机。watchEffect,则会在副作用发生期间追踪依赖。它会在同步执行过程中,自动追踪所有能访问到的响应式属性。这更方便,而且代码往往更简洁,但有时其响应性依赖关系会不那么明确。
存储
Pinia 是 Vue 3 官方推荐的状态管理库,用于管理应用的全局状态。 安装
npm i pinia
npm i pinia-use-persist
在main.ts中引入使用
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import { createPinia } from 'pinia'
import { usePersist } from 'pinia-use-persist'
const pinia = createPinia()
pinia.use(usePersist)
createApp(App).use(pinia).mount('#app')
创建src/store/文件夹下的index.ts
import { defineStore } from "pinia";
export const useLoginStore = defineStore('Login',{
state: ()=>({
logined: false,
name: '张三'
}),
persist: {
enable: true,
encryptionKey: 'letscode',
storage: localStorage,
}
})
在组件中使用
<script setup lang="ts">
import { useLoginStore } from '../store';
const loginstate = useLoginStore();
const add = ()=>{
loginstate.$state.name = '李四'
}
</script>
<template>
<div>
<p>{{ loginstate.name }}</p>
<button @click="add">改变</button>
</div>
</template>