一.写一个app组件
1.App.vue
<template>
<div class="app">
<h2>你好啊!</h2>
</div>
</template>
<script lang="ts">
//可写JS或ts,但是vue3推荐ts
export default{ //不能和声明一起使用,通常用于导出函数,类或对象
name:'App' //组件名
}
</script>
<style>
.app{
background-color: #ddd;
box-shadow: 0 0 10px;
border-radius: 10px; /*设置四个角的角度*/
padding: 20px;
}
</style>
2.main.ts
//引入creatApp用于创建应用
import { createApp } from "vue";
//引用App根组件
import App from "./App.vue"
createApp(App).mount('#app')
二.一个简单的效果
<template>
<div class="person">
<h2>姓名:{{name}}</h2>
<h2>年龄:{{age}}</h2>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年龄</button>
<button @click="showTel">查看电话</button>
</div>
</template>
<script lang="ts">
export default{ //默认导出
name:'person',
data() {
return{
name:'张三',
age:18,
tel:'13888888888'
}
},
methods:{
changeName(){
this.name='zhang-san'
},
changeAge(){
this.age += 1
},
showTel(){
alert(this.tel)
}
}
}
</script>
<style scoped>
.person{
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button{
margin: 0 5px;
}
</style>
三.setup
1.setup概述
-
setup函数返回的对象中的内容,可直接在模板中使用。 -
setup中访问this是undefined。 -
setup函数会在beforeCreate之前调用,它是“领先”所有钩子执行的。
<template>
<div class="person">
<h2>姓名:{{name}}</h2>
<h2>年龄:{{age}}</h2>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年龄</button>
<button @click="showTel">查看电话</button>
</div>
</template>
<script lang="ts">
export default{ //默认导出
name:'Person',
beforeCreate(){
console.log('beforCreate') //比beforCreate先执行
},
setup() {
console.log(this) //setup中的this是undefined,vue3在弱化this
//数据,原来写在data中的,此时的name,age,tel都不是响应式
let name = '张三'
let age = 18
let tel = '138888888888'
//方法
function changeName(){
name = 'zhang-san' //注意:这里修改name,页面是没变化的
console.log(name) //name确实改了,但name不是响应式
}
function changeAge(){
age += 1 //注意:这里修改age,页面是没变化的
console.log(age) //age确实改了,但age不是响应式
}
function showTel(){
alert(tel)
}
//将数据,方法交出去,模板中才可以使用
return {name,age,tel,changeName,changeAge,showTel}
}
}
</script>
<style scoped>
.person{
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button{
margin: 0 5px;
}
</style>
2.setup返回值
-
若返回一个对象:则对象中的:属性、方法等,在模板中均可以直接使用(重点关注)。
-
若返回一个函数:则可以自定义渲染内容,代码如下:
<template>
<div class="person">
<h2>姓名:{{name}}</h2>
<h2>年龄:{{age}}</h2>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年龄</button>
<button @click="showTel">查看电话</button>
</div>
</template>
<script lang="ts">
export default{ //默认导出
name:'Person',
beforeCreate(){
console.log('beforCreate') //setup比beforCreate先执行
},
setup() {
console.log(this) //setup中的this是undefined,vue3在弱化this
//数据,原来写在data中的,此时的name,age,tel都不是响应式
let name = '张三'
let age = 18
let tel = '138888888888'
//方法
function changeName(){
name = 'zhang-san' //注意:这里修改name,页面是没变化的
console.log(name) //name确实改了,但name不是响应式
}
function changeAge(){
age += 1 //注意:这里修改age,页面是没变化的
console.log(age) //age确实改了,但age不是响应式
}
function showTel(){
alert(tel)
}
//将数据,方法交出去,模板中才可以使用
return {name,age,tel,changeName,changeAge,showTel}
//setup的返回值也可以是一个渲染函数
//return ()=>'哈哈'
}
}
</script>
<style scoped>
.person{
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button{
margin: 0 5px;
}
</style>
3.setup与 Options API 的关系
-
Vue2的配置(data、methos......)中可以访问到setup中的属性、方法。 -
但在
setup中不能访问到Vue2的配置(data、methos......)。 -
如果与
Vue2冲突,则setup优先。
<template>
<div class="person">
<h2>姓名:{{name}}</h2>
<h2>年龄:{{age}}</h2>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年龄</button>
<button @click="showTel">查看电话</button>
<hr>
<h2> {{a}}</h2>
<h2> {{c}}</h2>
<h2> {{d}}</h2>
<button @click="b">测试</button>
</div>
</template>
<script lang="ts">
export default{ //默认导出
name:'Person',
beforeCreate(){
console.log('beforCreate') //setup比beforCreate先执行
},
data() {
return {
a: 6,
c: this.name, //可以读取到setup中的数据
d:900,
age:90
}
},
methods(){
function b(){
console.log('b')
}
},
setup() { //不能读取data中的数据
console.log(this) //setup中的this是undefined,vue3在弱化this
//数据,原来写在data中的,此时的name,age,tel都不是响应式
let name = '张三'
let age = 18
let tel = '138888888888'
//方法
function changeName(){
name = 'zhang-san' //注意:这里修改name,页面是没变化的
console.log(name) //name确实改了,但name不是响应式
}
function changeAge(){
age += 1 //注意:这里修改age,页面是没变化的
console.log(age) //age确实改了,但age不是响应式
}
function showTel(){
alert(tel)
}
//将数据,方法交出去,模板中才可以使用
return {name,age,tel,changeName,changeAge,showTel}
//setup的返回值也可以是一个渲染函数
//return ()=>'哈哈'
}
}
</script>
<style scoped>
.person{
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button{
margin: 0 5px;
}
</style>
4.setup语法糖
<template>
<div class="person">
<h2>姓名:{{name}}</h2>
<h2>年龄:{{age}}</h2>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年龄</button>
<button @click="showTel">查看电话</button>
</div>
</template>
<!--setup函数和name可以直接写到script里-->
<script lang="ts" setup name="Person">
let name = '张三'
let age = 18
let tel = '138888888888'
//方法
function changeName(){
name = 'zhang-san' //注意:这里修改name,页面是没变化的
console.log(name) //name确实改了,但name不是响应式
}
function changeAge(){
age += 1 //注意:这里修改age,页面是没变化的
console.log(age) //age确实改了,但age不是响应式
}
function showTel(){
alert(tel)
}
</script>
<style scoped>
.person{
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button{
margin: 0 5px;
}
</style>
四.ref和reactive
1.ref 创建:基本类型的响应式数据
-
作用:定义响应式变量。
-
语法:
let xxx = ref(初始值)。 -
返回值:一个
RefImpl的实例对象,简称ref对象或ref,ref对象的value属性是响应式的。 -
注意点:
-
JS中操作数据需要:xxx.value,但模板中不需要.value,直接使用即可。 -
对于
let name = ref('张三')来说,name不是响应式的,name.value是响应式的。
-
<template>
<div class="person">
<h2>姓名:{{name}}</h2>
<h2>年龄:{{age}}</h2>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年龄</button>
<button @click="showTel">查看电话</button>
</div>
</template>
<!--setup函数和name可以直接写到script里-->
<script lang="ts" setup name="Person">
import {ref} from 'vue'
//name和age是一个RefImpl的实列对象,简称ref对象,它们的value属性是响应式
let name = ref('张三')
let age = ref(18)
//tel就是一个普通字符串,不是响应式
let tel = '138888888888'
//方法
function changeName(){
//JS中操作ref对象需要.value
name.value = 'zhang-san'
console.log(name.value)
//注意:name不是响应式,name.value是响应式,以下不会引起页面变化
//name = ref('zhang-san')
}
function changeAge(){
age.value += 1
console.log(age.value)
}
function showTel(){
alert(tel)
}
</script>
<style scoped>
.person{
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button{
margin: 0 5px;
}
</style>
2.reactive 创建:对象类型的响应式数据
-
作用:定义一个响应式对象(基本类型不要用它,要用
ref,否则报错) -
语法:
let 响应式对象= reactive(源对象)。 -
返回值:一个
Proxy的实例对象,简称:响应式对象。 -
注意点:
reactive定义的响应式数据是“深层次”的。
<template>
<div class="person">
<h2>姓名:{{name}}</h2>
<h2>年龄:{{age}}</h2>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年龄</button>
<button @click="showTel">查看电话</button>
</div>
</template>
<!--setup函数和name可以直接写到script里-->
<script lang="ts" setup name="Person">
import {ref} from 'vue'
//name和age是一个RefImpl的实列对象,简称ref对象,它们的value属性是响应式
let name = ref('张三')
let age = ref(18)
//tel就是一个普通字符串,不是响应式
let tel = '138888888888'
//方法
function changeName(){
//JS中操作ref对象需要.value
name.value = 'zhang-san'
console.log(name.value)
//注意:name不是响应式,name.value是响应式,以下不会引起页面变化
//name = ref('zhang-san')
}
function changeAge(){
age.value += 1
console.log(age.value)
}
function showTel(){
alert(tel)
}
</script>
<style scoped>
.person{
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button{
margin: 0 5px;
}
</style>
3.ref 创建:对象类型的响应式数据
-
其实
ref接收的数据可以是:基本类型、对象类型。 -
若
ref接收的是对象类型,内部其实也是调用了reactive函数。
<template>
<div class="person">
<h2>姓名:{{name}}</h2>
<h2>年龄:{{age}}</h2>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年龄</button>
<button @click="showTel">查看电话</button>
</div>
</template>
<!--setup函数和name可以直接写到script里-->
<script lang="ts" setup name="Person">
import {ref} from 'vue'
//name和age是一个RefImpl的实列对象,简称ref对象,它们的value属性是响应式
let name = ref('张三')
let age = ref(18)
//tel就是一个普通字符串,不是响应式
let tel = '138888888888'
//方法
function changeName(){
//JS中操作ref对象需要.value
name.value = 'zhang-san'
console.log(name.value)
//注意:name不是响应式,name.value是响应式,以下不会引起页面变化
//name = ref('zhang-san')
}
function changeAge(){
age.value += 1
console.log(age.value)
}
function showTel(){
alert(tel)
}
</script>
<style scoped>
.person{
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button{
margin: 0 5px;
}
</style>
4. ref与reactive对比
宏观角度看:
ref用来定义:基本类型数据、对象类型数据;
reactive用来定义:对象类型数据。
-
区别:
ref创建的变量必须使用.value(可以使用volar插件自动添加.value)。
reactive重新分配一个新对象,会失去响应式(可以使用Object.assign去整体替换)。
-
使用原则:
若需要一个基本类型的响应式数据,必须使用
ref。若需要一个响应式对象,层级不深,
ref、reactive都可以。若需要一个响应式对象,且层级较深,推荐使用
reactive。
<template>
<div class="person">
<h2>姓名:{{name}}</h2>
<h2>年龄:{{age}}</h2>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年龄</button>
<button @click="showTel">查看电话</button>
</div>
</template>
<!--setup函数和name可以直接写到script里-->
<script lang="ts" setup name="Person">
import {ref} from 'vue'
//name和age是一个RefImpl的实列对象,简称ref对象,它们的value属性是响应式
let name = ref('张三')
let age = ref(18)
//tel就是一个普通字符串,不是响应式
let tel = '138888888888'
//方法
function changeName(){
//JS中操作ref对象需要.value
name.value = 'zhang-san'
console.log(name.value)
//注意:name不是响应式,name.value是响应式,以下不会引起页面变化
//name = ref('zhang-san')
}
function changeAge(){
age.value += 1
console.log(age.value)
}
function showTel(){
alert(tel)
}
</script>
<style scoped>
.person{
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button{
margin: 0 5px;
}
</style>
5.toRefs与toRef
-
作用:将一个响应式对象中的每一个属性,转换为
ref对象。 -
备注:
toRefs与toRef功能一致,但toRefs可以批量转换。
<template>
<div class="Person">
<h2>姓名:{{person.name}}</h2>
<h2>年龄:{{person.age}}</h2>
<button @click="changeName">修改姓名</button>
<button @click="changeAge">修改年龄</button>
</div>
</template>
<script lang="ts" setup name="Person">
import {reactive,toRefs,toRef} from 'vue'
let person = reactive({
name:'张三',
age:18
})
//使用使用toRefs从person这个响应式对象中,解构出name、age,且name和age依然是响应式的
// name和age的值是ref类型,其value值指向的是person.name和person.age
let {name,age} = toRefs(person)
let nl = toRef(person,'age')
console.log(nl)
function changeName(){
name.value += '~'
}
function changeAge(){
age.value += 1
}
</script>
<style scoped>
.person{
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button{
margin: 0 5px;
}
</style>
五.computed
<template>
<div class="person">
<!--v-model双向绑定-->
姓:<input type="text" v-model="firstName"><br>
名:<input type="text" v-model="lastName"><br>
<button @click="changeName">将全名改为li-si</button>
<br>
全名:<span>{{ fullName }}</span><br>
</div>
</template>
<script lang="ts" setup name="Person">
import { ref,computed } from 'vue'
let firstName = ref('zhang')
let lastName = ref('san')
//fullName是一个计算属性,且是只读的
/*let fullName = computed(()=>{
return firstName.value.slice(0,1).toUpperCase() + firstName.value.slice(1) + '-' + lastName.value
})*/
//fullName是一个计算属性,可读可写
let fullName = computed({
//当fullName被读取时,get调用
get(){
return firstName.value.slice(0,1).toUpperCase() + firstName.value.slice(1) + '-' + lastName.value
},
//当fullName被修改时,set调用,且会收到修改值
set(val){
const[str1,str2] = val.split('-')
firstName.value = str1
lastName.value = str2
}
})
/* set(val){
firstName.value = val.split('-')[0]
lastName.value = val.split('-')[1]
}}*/
function changeName(){
fullName.value = 'li-si'
}
</script>
<style scoped>
.person{
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button{
margin: 0 5px;
}
</style>
六.watch
1.监视ref定义的基本数据类型
-
作用:监视数据的变化(和
Vue2中的watch作用一致) -
特点:
Vue3中的watch只能监视以下四种数据:
ref定义的数据。
reactive定义的数据。函数返回一个值(
getter函数)。一个包含上述内容的数组。
<template>
<div class="person">
<h1>情况一:监视【ref】定义的【基本类型】数据</h1>
<h2>当前求和{{sum}}</h2>
<button @click="changeSum">点我sum+1</button>
</div>
</template>
<script lang="ts" setup name="app">
import {ref,watch} from 'vue'
//数据
let sum =ref(0)
//方法
function changeSum(){
sum.value +=1
}
//监视,情况一:监视【ref】定义的【基本类型】数据
const stopwatch = watch(sum,(newvalue,oldvalue)=>{
console.log(newvalue,oldvalue)
if (newvalue >=10 ){
stopwatch()
}
})
</script>
<style>
</style>
2.监视ref定义的对象类型数据
监视ref定义的【对象类型】数据:直接写数据名,监视的是对象的【地址值】,若想监视对象内部的数据,要手动开启深度监视。
<template>
<div class="person">
<h1>情况二:监视【ref】定义的【对象类型】数据</h1>
<h2>姓名:{{person.name}}</h2>
<h2>年龄:{{person.age}}</h2>
<button @click="changeName">修改姓名</button>
<button @click="chanegAge">修改年龄</button>
<button @click="changeAll">修改全部</button>
</div>
</template>
<script lang="ts" setup name="app">
import { ref,watch} from 'vue';
let person = ref({
name:'张三',
age:18
})
function changeName(){
person.value.name += '~'
}
function chanegAge(){
person.value.age += 1
}
function changeAll(){
person.value = {name:'李四',age:60}
}
/*监视:情况二:监视【ref】定义的【对象类型】数据,监视的是对象那个的地址,若想监视对象属性的变化,需要开启深度监视
watch的第一个参数:被监视的数据
watch的第二个参数:监视的回调
watch的第三个参数:配置对象(deep,immediate等。。。
*/
watch(person,(newvalue,oldvalue)=>{
console.log(newvalue,oldvalue)
},{deep:true})
</script>
<style scoped>
</style>
3.监视reactive定义的对象类型数据
监视reactive定义的【对象类型】数据,且默认开启了深度监视。
<template>
<div class="person">
<h1>情况三:监视【reactive】定义的【对象类型】数据</h1>
<h2>姓名:{{person.name}}</h2>
<h2>年龄:{{person.age}}</h2>
<button @click="changeName">修改姓名</button>
<button @click="chanegAge">修改年龄</button>
<button @click="changeAll">修改全部</button>
<br>
<h2>测试:{{obj.a.b.c}}</h2>
<button @click="changeC">点我c变</button>
</div>
</template>
<script lang="ts" setup name="app">
import { reactive,watch } from 'vue'
let person = reactive({
name:'zhang-san',
age:18
})
let obj = reactive({
a:{
b:{
c:666
}
}
})
function changeName(){
person.name += '-'
}
function chanegAge(){
person.age += 1
}
function changeAll(){
Object.assign(person,{name:'li-si',age:60})
}
function changeC(){
obj.a.b.c = 999
}
//情况三:监视【reactive】定义的【对象类型】数据,且默认开启深度监视
watch (person,(newvalue,oldvalue)=>{
console.log(newvalue,oldvalue)
})
watch(obj,(newvalue,oldvalue)=>{
console.log(newvalue,oldvalue)
})
</script>
<style scoped>
</style>
4.监视ref或reactive定义的对象类型数据中的某个属性
监视ref或reactive定义的【对象类型】数据中的某个属性,注意点如下:
-
若该属性值不是【对象类型】,需要写成函数形式。
-
若该属性值是依然是【对象类型】,可直接编,也可写成函数,建议写成函数。
<template>
<div class="person">
<h1>情况四:监视【ref】或【reactive】中的【对象类型】数据的某个属性</h1>
<h2>姓名:{{person.name}}</h2>
<h2>年龄:{{person.age}}</h2>
<h2>年龄:{{person.car.car1}},{{ person.car.car2 }}</h2>
<button @click="changeName">修改姓名</button>
<button @click="chanegAge">修改年龄</button>
<button @click="changeCar1">修改第一辆车</button>
<button @click="changeCar2">修改第二辆车</button>
<button @click="changeCar">修改全部的车</button>
</div>
</template>
<script lang="ts" setup name="app">
import { reactive,watch } from 'vue'
let person = reactive({
name:'zhangsan',
age:18,
car:{car1:'奔驰',
car2:'宝马'
}
})
function changeName(){
person.name += '-'
}
function chanegAge(){
person.age += 1
}
function changeCar1(){
person.car.car1 = '大众'
}
function changeCar2(){
person.car.car2 = '长安'
}
function changeCar(){
person.car = {car1:'雅迪',car2:'九号'}
}
//情况四:监视【ref】或【reactive】中的【对象类型】数据的某个属性,且该属性是基本类型的,要写成函数式
/*watch(()=>person.name,(newvalue,oldvalue)=>{
console.log(newvalue,oldvalue)
})*/
//该属性是对象类型的,可以直接写,也能写函数,更推荐写函数
//不加deep,监视整个;加deep,可以监视到单个
watch(()=>person.car,(newvalue,oldvalue)=>{
console.log(newvalue,oldvalue)
},{deep:true})
</script>
<style scoped>
</style>
5.监视上述的多个数据
<template>
<div class="person">
<h1>情况五:监视上述多个数据</h1>
<h2>姓名:{{person.name}}</h2>
<h2>年龄:{{person.age}}</h2>
<h2>年龄:{{person.car.car1}},{{ person.car.car2 }}</h2>
<button @click="changeName">修改姓名</button>
<button @click="chanegAge">修改年龄</button>
<button @click="changeCar1">修改第一辆车</button>
<button @click="changeCar2">修改第二辆车</button>
<button @click="changeCar">修改全部的车</button>
</div>
</template>
<script lang="ts" setup name="app">
import { reactive,watch } from 'vue'
let person = reactive({
name:'zhangsan',
age:18,
car:{car1:'奔驰',
car2:'宝马'
}
})
function changeName(){
person.name += '-'
}
function chanegAge(){
person.age += 1
}
function changeCar1(){
person.car.car1 = '大众'
}
function changeCar2(){
person.car.car2 = '长安'
}
function changeCar(){
person.car = {car1:'雅迪',car2:'九号'}
}
//情况五:监视上述多个数据
watch([()=>person.name,person.car],(newvalue,oldvalue)=>{
console.log(newvalue,oldvalue)
},{deep:true})
</script>
<style scoped>
</style>
6.watchEffect
<template>
<div class="person">
<h2>需求:当水温达到60度,或水位达到80cm时,给服务器发请求</h2>
<h2>当前水温:{{temp}}℃</h2>
<h2>当前水位:{{height}}cm</h2>
<button @click="changeTemp">水温+10</button>
<button @click="changeHeight">水位+10</button>
</div>
</template>
<script lang="ts" setup name="app">
import { ref,watch,watchEffect} from 'vue'
let temp = ref(10)
let height = ref(0)
function changeTemp(){
temp.value += 10
}
function changeHeight(){
height.value += 10
}
//情况五:监视上述多个数据
/*监视:watch实现
watch([temp,height],(value)=>{
//从value中获取最新的水温(newTemp)、最新的水位(newHeight)
let [newTemp,newHeight] = value
if(newTemp>=60 || newHeight >=80){
console.log("发送请求")
}
})*/
//监视:watchEffect实现
watchEffect(()=>{
if(temp.value >= 60 || height.value >= 80){
console.log("发送请求")
}
})
/* 1. 都能监听响应式数据的变化,不同的是监听数据变化的方式不同
2. `watch`:要明确指出监视的数据
3. `watchEffect`:不用明确指出监视的数据(函数中用到哪些属性,那就监视哪些属性)。*/
</script>
<style scoped>
</style>
2681

被折叠的 条评论
为什么被折叠?



