一、响应式数据
1.ref
ref可以定义 基本类型的响应式数据, 也可以定义对象类型响应式数据
<template>
<h1>{{ name }}</h1>
<button @click="test">修改姓名</button>
</template>
<script setup lang="ts">
import { ref } from 'vue'
let name = ref('zhansan')
function test(){
name.value = "张三"
}
</script>
注意:
1.响应式数据必须使用ref进行修饰
2.在template引入响应式数据时,直接引入变量名即可
3.修改ref修饰的响应数据的值时,必须使用 "变量.value"才能修改
2.reactive
reactive是定义对象类型的响应式数据
<template>
<h1>{{ obj.name }}</h1>
<button @click="test">修改姓名</button>
</template>
<script setup lang="ts">
import { reactive } from 'vue'
let obj = reactive({name: "zhangsan"})
function test(){
obj.name = "张三"
}
</script>
注意:reactive 如果重新进行赋值,那么原来的对象就会失去响应式
reactive修改值的内容不需要使用 .value
3.选择原则
如果数据式对象类型,层级不深,两个都可以。如果层级深,推荐使用reactive
4.toRefs
先看实例,此时发现name的值变化了,但是模板中的值没有改变。
这是因为obj在解构后,name就不是响应式的数据了。
<template>
<h1>{{ name }}</h1>
<button @click="test">修改姓名</button>
</template>
<script setup lang="ts">
import { reactive, toRef } from 'vue'
let obj = reactive({name:"zhangsan"})
let { name } = obj
function test(){
name = "张三"
alert(name)
}
</script>
修改后,成功了,包括obj的数据也变化了
<template>
<h1>{{ name }}</h1>
<h1>{{ obj.name }}</h1>
<button @click="test">修改姓名</button>
</template>
<script setup lang="ts">
import { reactive, toRefs } from 'vue'
let obj = reactive({name:"zhangsan"})
let { name } = toRefs(obj)
function test(){
name.value = "张三"
}
</script>
二、基础指令
v-xxx的指令有很多,这里只介绍一些常用的指令
1.v-if
v-if是条件渲染指令,它根据表达式的true和false来删除和插入元素,它的基本语法如下:v-if=“表达式”
<template>
<h1 v-if="data1">1</h1>
<h1 v-if="data2">2</h1>
<h1 v-if="data3 > 18">成年人</h1>
</template>
<script setup lang="ts">
let data1 = true
let data2 = false
let data3 = 20
</script>
2.v-show
v-show也是条件渲染指令,和v-if指令不同的是,v-show不会删除html元素,而是将它得属性设置为style=“display: none;”
<template>
<h1 v-show="data1">1</h1>
<h1 v-show="data2">2</h1>
<h1 v-show="data3 > 18">成年人</h1>
</template>
<script setup lang="ts">
let data1 = true
let data2 = false
let data3 = 20
</script>
3.v-else
v-else就是v-if得继续。
注意:v-else元素必须立即跟在v-if元素的后面——否则它不能被识别。
<template>
<h1 v-if="data1">data1:true</h1>
<h1 v-else>data1:false</h1>
<h1 v-if="data2">data2: true</h1>
<h1 v-else>data2: false</h1>
</template>
<script setup lang="ts">
let data1 = true
let data2 = false
</script>
4.v-for
4.1 遍历数组
注意: :key=“index” 尽量带上。主要目的是为了识别每个节点得唯一标识.有了标识就能够更高效,准确得更新虚拟DOM
<template>
<h3 v-for="(item,index) in arr" :key="index">{{ item }},{{ index }}</h3>
</template>
<script setup lang="ts">
let arr = ["zhangsan","lisi","wangwu"]
</script>
4.2 遍历对象
<template>
<ul>
<li v-for="(value,key,index) in object" :key="index">{{ value }},{{key}}{{index}}</li>
</ul>
</template>
<script setup lang="ts">
let object = {name: "zhangsan",age:20,gender: "boy"}
</script>
4.3 遍历对象数组
<template>
<ul>
<li v-for="(value,index) in object" :key="index">{{ value.name }}{{index}}</li>
</ul>
</template>
<script setup lang="ts">
let object = [
{name: "zhangsan",age:20,gender: "boy"},
{name: "lisi",age:21,gender: "boy"},
{name: "wangwu",age:22,gender: "boy"},
]
</script>
5.v-bind
1.v-bind得简写是 “冒号”
2.v-bind 其实就是让标签得属性 绑定一个 变量 而不是 字符串
先看一个实例,a标签绑定得herf属性被识别成了字符串,而不是一个变量
<template>
<a href="baidu">百度一下</a>
</template>
<script setup lang="ts">
const baidu = "http://www.baidu.com"
</script>
此时就需要使用v-bind进行变量绑定。
<template>
<a :href="baidu">百度一下</a>
</template>
<script setup lang="ts">
const baidu = "http://www.baidu.com"
</script>
6.v-on
v-on指令用于监听事件,简写为 @
6.1 鼠标点击事件
<template>
<el-button type="success" v-on:click="send">完整写法</el-button>
<el-button type="success" @click="send">简写</el-button>
</template>
<script setup lang="ts">
import { ElMessage } from 'element-plus';
function send(){
ElMessage({
type: "success",
message: "hello"
})
}
</script>
6.2 传值得点击事件
<template>
<h1>{{ sum }}</h1>
<el-button type="success" @click="sum1">+1</el-button>
<el-button type="success" @click="sum10(10)">+10</el-button>
</template>
<script setup lang="ts">
import { ref } from 'vue'
let sum = ref(0)
function sum1() {
sum.value++
console.log(sum.value)
}
function sum10(num:number) {
sum.value+=num
console.log(sum.value)
}
</script>
7.v-model
数据双向绑定,在Vue.js中可以使用v-model指令在表单元素上创建双向数据绑定。
v-model只收集表单的数据,别的标签不起作用。
完整写法:v-model:value=“text”
简写: v-model=text
这里可以看出v-model是针对input 的value属性进行处理
<template>
<h1>{{ text }}</h1>
<input type="text" v-model="text" style="position: absolute;top:100px;">
</template>
<script setup lang="ts">
import {ref} from 'vue'
let text = ref()
</script>
三、计算属性computed
computed的好处就是,被计算的数据发生变化,结果也会发生变化
<template>
<h1>{{ x }}</h1>
<button @click="x++">加1</button>
<h1>{{ y }}</h1>
<button @click="y++">加1</button>
<h1>{{ sum }}</h1>
</template>
<script setup lang="ts">
import {computed, ref,toRef} from 'vue'
let x = ref(1)
let y = ref(2)
# 这里使用computed 方法进行数据的计算
let sum = computed(() => {
return x.value + y.value
})
</script>
四、watch
1.作用
监视数据的变化
2.特点
vue3中的watch只监控以下四种数据
1 ref定义的数据
2.reactive定义的数据
3.函数返回一个值
4.一个包含上述内容的数组
3.watch-ref数据
注意点:
1.监视的数据(sum)不用写.value
2.回调函数有两个参数,第一个是变化的新值,第二个是变化之前的旧值
3.在回调函数中,可以直接调用watch的返回值来停止watch的监视
<template>
<h1>sum的和是: {{ sum }}</h1>
<button @click="changeSum">sum加1</button>
</template>
<script setup lang="ts">
import { ref,watch } from 'vue'
let sum = ref(0)
function changeSum(){
sum.value += 1
}
let stopWatch = watch(sum,(newVlue,oldValue) => {
console.log(newVlue)
if (newVlue > 10) {
stopWatch()
}
})
</script>
4.watch-reactive数据
注意:
1.修改了对象的人一一个值,都可以触发watch
2.newValue,oldValue值是一样的,都是显示修改后的值。
<template>
<h1>姓名: {{ obj.name }}</h1>
<button @click="changename">点我修改姓名</button>
<h1>年龄:{{ obj.age }}</h1>
<button @click="changeage">点我修改年龄</button>
</template>
<script setup lang="ts">
import { reactive,watch } from 'vue'
let obj = reactive({name: "zhangsan",age: 20})
function changename(){
obj.name = "张三"
}
function changeage(){
obj.age++
}
watch(obj,(newValue,oldValue)=>{
console.log('变化了')
console.log(newValue,oldValue)
})
</script>
所以监视器可以简写为:回调函数的形参只写一个就可以了
let stop = watch(obj,(newValue)=>{
if (newValue.age == 30){
stop()
console.log('停止监视')
}
})
5.监视对象某个属性
在4中,监视的是整个对象,如果对象中属性特别多,需要只监控某一个属性。
方法如下:将监控对象的参数 以函数的形式编写。
实例如下:
5.1 监控普通属性
<template>
<h1>姓名:{{ persion.name }}</h1>
<button @click="changeName">修改姓名</button>
<h1>汽车: {{ persion.car.c1 }},{{ persion.car.c2 }} </h1>
<button @click="changeC1">修改汽车1</button>
<button @click="changeC2">修改汽车2</button>
<button @click="changeAll">修改所有汽车</button>
</template>
<script setup lang="ts">
import { reactive, watch } from 'vue'
let persion = reactive({
name: "zhangsan",
car:{
c1: "长城",
c2: "大众"
}
})
function changeName(){
persion.name += "~"
}
function changeC1(){
persion.car.c1 = '奔驰'
}
function changeC2(){
persion.car.c2 = '奥迪'
}
function changeAll(){
persion.car = {c1:"宝马",c2:"丰田"}
}
// 监视普通类型属性
watch(
()=> { return persion.name },
(newValue,oldValue)=>{
console.log(newValue,oldValue)
})
</script>
5.2 监视对象属性
<template>
<h1>姓名:{{ persion.name }}</h1>
<button @click="changeName">修改姓名</button>
<h1>汽车: {{ persion.car.c1 }},{{ persion.car.c2 }} </h1>
<button @click="changeC1">修改汽车1</button>
<button @click="changeC2">修改汽车2</button>
<button @click="changeAll">修改所有汽车</button>
</template>
<script setup lang="ts">
import { reactive, watch } from 'vue'
let persion = reactive({
name: "zhangsan",
car:{
c1: "长城",
c2: "大众"
}
})
function changeName(){
persion.name += "~"
}
function changeC1(){
persion.car.c1 = '奔驰'
}
function changeC2(){
persion.car.c2 = '奥迪'
}
function changeAll(){
persion.car = {c1:"宝马",c2:"丰田"}
}
// 监视对象类型属性,并且开启深度监视。深度监视的含义就是监视car对象中的每个属性。
// 如果不开启深度监视,只能是car整个对象变化的的时候才能监视到
watch(
()=>{return persion.car},
(newValue,oldValue)=>{
console.log(newValue,oldValue)
},
{deep:true}
)
</script>
6.监听多个属性
监听多个属性,要写成箭头函数数组的形式
<template>
<h1>姓名:{{ persion.name }}</h1>
<button @click="changeName">修改姓名</button>
<h1>汽车: {{ persion.car.c1 }},{{ persion.car.c2 }} </h1>
<button @click="changeC1">修改汽车1</button>
<button @click="changeC2">修改汽车2</button>
<button @click="changeAll">修改所有汽车</button>
</template>
<script setup lang="ts">
import { reactive, watch } from 'vue'
let persion = reactive({
name: "zhangsan",
car:{
c1: "长城",
c2: "大众"
}
})
function changeName(){
persion.name += "~"
}
function changeC1(){
persion.car.c1 = '奔驰'
}
function changeC2(){
persion.car.c2 = '奥迪'
}
function changeAll(){
persion.car = {c1:"宝马",c2:"丰田"}
}
watch(
// 监听多个属性,要写成箭头函数数组的形式
[ ()=> persion.name,()=>persion.car.c1 ],
(newValue,oldValue)=>{
console.log(newValue,oldValue)
},
{deep:true}
)
</script>
五、watchEffect
watcheffect的好处就是,不用指定监视对象,直接编写处理逻辑就可以了,非常的方便
<template>
<h1>sum的和: {{sum}}</h1>
<button @click="sum++">sum加1</button>
</template>
<script setup lang="ts">
import { ref,watchEffect } from 'vue'
let sum = ref(0)
watchEffect(()=>{
if(sum.value > 10 ){
console.log("sum是一个大于10的数字")
}
})
</script>
六、标签的ref属性
ref属性是能够定位html元素的属性,相当于id或者class定位的作用
<template>
<h1>张三</h1>
<h1 ref="t1">李四</h1>
<button @click="show">查看</button>
</template>
<script setup lang="ts">
import {ref} from 'vue'
let t1 = ref()
function show(){
console.log(t1.value)
}
</script>
七、组件生命周期
vue3和vue2生命周期略有不同
生命周期函数 | 作用 |
---|---|
onBeforeMount() | 组件挂载到节点上之前执行 |
onMounted() | 组件挂载完成后执行 |
onBeforeUpdate() | 组件更新之前执行 |
onUpdated() | 组件更新完成后执行 |
onBeforeUnmount() | 组件卸载之前执行 |
onUnmounted() | 组件卸载完成后执行 |
1.创建test子组件
这里测试onBeforeMount函数
<template>
<h1>我是test组件</h1>
</template>
<script setup>
import { onBeforeMount,onMounted } from 'vue'
onBeforeMount(()=>{
console.log("挂载前")
// 这是开启debug模式,程序到这里就不会在继续运行了
debugger
})
</script>
2.引入test子组件
在app.vue中引入组件
<template>
<h1>我是app.vue</h1>
// 引入test子组件
<test></test>
</template>
<script setup>
import test from './components/test.vue'
</script>
3.验证结果
发现子组件的的结果没有在app.vue中显示,但是onBeforeMount函数中的输出已经控制台输出了
八、Pinia集中式状态管理库
1.安装
pnpm install pinia
2.引入pinia
在main.ts中引入pinia
import { createPinia } from 'pinia'
const store = createPinia()
app.use(store)
3.创建数据仓库
在src下创建store/“数据文件.ts”。这里用于测试的文件是userInfo.ts
3.1 定义数据
在userinfo.ts文件中定义数据。
definStore,有两个参数,第一个参数式一个key,尽量和文件名保持一致。第二个参数就定义的数据
import { defineStore } from 'pinia'
export const userInfoStore = defineStore('userInfo',{
state(){
return {
sum: 0
}
}
})
3.2 引用数据
在app.vue中引用sum
<template>
// 应用sum
<h1> {{ use_userInfoStore.sum }} </h1>
</template>
<script setup>
import { userInfoStore } from './store/userInfo'
const use_userInfoStore = userInfoStore()
</script>
4.修改数据
4.1 方法1
如果只修改一个值。可以使用这个办法。比较简单
<template>
<h1> {{ use_userInfoStore.sum }} </h1>
<button @click="changSum">加1</button>
</template>
<script setup>
import { userInfoStore } from './store/userInfo'
const use_userInfoStore = userInfoStore()
function changSum(){
use_userInfoStore.sum++
}
</script>
4.2 方法2:$patch
如果数据有多个,可以使用以下$patch 方法
<template>
<h1> {{ use_userInfoStore.sum }} {{ use_userInfoStore.name }} {{ use_userInfoStore.age }}</h1>
<button @click="changSum">加1</button>
</template>
<script setup>
import { userInfoStore } from './store/userInfo'
const use_userInfoStore = userInfoStore()
function changSum(){
use_userInfoStore.$patch({
sum:20,
age: 30,
name: "张三",
})
}
</script>
当然使用上边的方法也可以,如下
function changSum(){
use_userInfoStore.sum++
use_userInfoStore.age = 30
use_userInfoStore.name = "张三"
}
5.组合式写法
以上都是选项式写法,组合式写法,在语法上相对来说比较简洁
5.1 定义数据
这里和选项式定义就有了区别,
1.没有了stat和action关键字,直接写逻辑。
2.在函数中不用使用this了
import { defineStore } from 'pinia'
import {ref} from 'vue'
export const userInfoStore = defineStore('userInfo',()=>{
const sum = ref(0)
function changeSum(value){
if (value > 10){
alert('数字太大了')
}else{
sum.value += value
}
}
return {sum,changeSum}
})
5.2 修改数据
<template>
<h1>sum = {{ use_userInfoStore.sum }}</h1>
<button @click="add1">方式1</button>
<button @click="add2">方式2</button>
</template>
<script setup lang="ts">
import { userInfoStore } from './store/userInfo'
const use_userInfoStore = userInfoStore()
// 方式1:直接修改
function add1(){
use_userInfoStore.sum += 1
}
// 方式2: 调用pinia中的函数进行修改,对于传入的数据可以进行限制
function add2(){
use_userInfoStore.changeSum(5)
}
</script>
九、组件通信
1.props
props可以实现 父组件传数据给子组件,也可以子组件给父组件传数据
1.1 父传子
定义子组件
注意: 接收的key 一定要和 父组件传递的key一致。否则接收不到
<template>
<h1>我是test.vue</h1>
<!-- 使用接收的数据 -->
<h1>{{ username }}</h1>
</template>
<script lang="ts">
export default {
name:"test"
}
</script>
<script setup lang="ts">
import { defineProps } from 'vue'
// 这里定义prop_res 是为了打印,如果不接收 打印不了 接收的数据
const prop_res = defineProps(['username'])
// 打印接收的数据
console.log(prop_res.username)
</script>
定义父组件app.vue
注意点:
:username 是一个自定义的key值,并不是一个属性。v-bind决定了传递过去的是一个变量
“username” 是传递过去的变量
<template>
<h1>我是app.vue</h1>
// z这里是给test组件传值。将username变量传给test组件
<test :username="username"></test>
</template>
<script setup lang="ts">
import {ref} from 'vue'
import test from './components/test.vue'
let username = ref("admin")
</script>
1.2 子传父
子传父的原理 其实还是 在父组件中定义一个函数,然后传递给子组件,子组件调用这个函数 将数据通过这个函数传递给父组件
定义子组件:
<template>
<h1>我是app.vue</h1>
<h1>字组数据为: {{ Fdata }}</h1>
<!-- 将定义好的函数发送给子组件 -->
<test :send_data="send_data"></test>
</template>
<script setup lang="ts">
import test from './components/test.vue'
import {ref} from 'vue'
let Fdata = ref()
// 定义好一个函数,让子组件使用,然后利用这个函数将数据发送给父组件
function send_data(value:string){
Fdata.value = value
}
</script>
定义子组件
<template>
<h1>我是test.vue</h1>
<!-- 使用按钮将子组件的数据发送给父组件 -->
<button @click="send_data(data)">发送数据给父组件</button>
</template>
<script lang="ts">
export default {
name:"test"
}
</script>
<script setup lang="ts">
import { ref,defineProps } from 'vue'
const data = ref('测试数据122211')
// 接收父组件传过来的函数,用于发送数据
defineProps(['send_data'])
</script>
2.provide和inject
这两个是一个组合,专门实现父组件向下 给1一级后多级子组件传递数据
设置父组件
<template>
<h1>我是app.vue</h1>
<hr>
<test></test>
</template>
<script setup lang="ts">
import {ref,provide} from 'vue'
import test from './components/test.vue'
let Fdata = ref(100)
// 将Fdata变量 设置一个自定义key 提供给所有的后代组件使用
provide('d1',Fdata)
</script>
设置子组件
<template>
<h1>我是test.vue</h1>
<h1>父组件的数据为:{{ x }}</h1>
</template>
<script lang="ts">
export default {
name:"test"
}
</script>
<script setup lang="ts">
import { inject } from 'vue'
// 引入父组件提供的变量。然后在模板中使用
let x = inject('d1')
</script>