一、响应式数据
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 } = objfunction 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+=numconsole.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 = 30use_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>