Vue3快速上手(简易版)

0.小前置

javascript 复制代码
<script lang="ts" setup name="App">
<style scoped>

define开头的函数是可以不用引入的哦

第一阶段:ref (值,对象响应化), reactive(对象响应化)

1.ref处理响应式数据 ref (单值)

目标1:实现一个加法

javascript 复制代码
<template>
    <p>这是一个数字{{ number }}</p>
    <button @click="Add">我是加法</button>  //绑函数
</template>
​
<script setup lang="ts">
import { ref } from "vue"   //引入响应包
let number = ref(0);        //数据响应化
function Add(){
    number.value++;         //必须改数据的值
}
</script>

2.reactive处理响应式数据 reactive (只能对象,数组)

目标1:实现一个对象修改

javascript 复制代码
<template>
    <p>我是{{ number.name }} , 我值{{ number.price }}元</p>
    <button @click="Add">我是加法</button>
</template>
​
<script setup lang="ts">
import { reactive } from "vue"      //引入响应包
let number = reactive({name:"苹果",price:100});   //数据响应化 
function Add(){
    number.price = number.price + 10;
}
</script>

3.ref处理响应式数据 ref (对象,数组)

目标1:实现一个对象修改

javascript 复制代码
<template>
    <p>我是{{ number.name }} , 我值{{ number.price }}元</p>
    <button @click="Add">我是加法</button>
</template>
​
<script setup lang="ts">
import { ref } from "vue"
let number = ref({name:"苹果",price:100});
function Add(){
    number.value.price = number.value.price + 10;
}
</script>

4.上述小知识总结

ref > reactive ------- ref._value == reactive

宏观角度看:

1.ref 用来定义:--> 基本类型数据 , 对象类型数据

2.reactive用来定义:--> 对象类型数据

区别:

1.ref创建的变量必须使用.value

2.reactive重新分配一个新对象,会失去响应式

使用原则:

1.若需要一个基本类型的响应式数据,必须使用ref

2.若需要一个响应式对象,层级不深,ref,reactive都可以

3.若需要一个响应式对象,且层级较深,推荐使用reactive

5.(1,2,3重难点)(数据的再赋值)ref,reactive

ref

javascript 复制代码
<template>
    <p>我是{{ number.name }} , 我值{{ number.price }}元</p>
    <button @click="Add">我是加法</button>
    <button @click="Switch">我是切换</button>
</template>
​
<script setup lang="ts">
import { ref } from "vue"
let number = ref({name:"苹果",price:100});
​
function Add(){
    number.value.price = number.value.price + 10;
}
function Switch(){
    number.value = {name:"梨" , price: 200}
}
</script>

reactive

javascript 复制代码
<template>
    <p>我是{{ number.name }} , 我值{{ number.price }}元</p>
    <button @click="Add">我是加法</button>
    <button @click="Switch">我是切换</button>
</template>
​
<script setup lang="ts">
import { reactive } from "vue"
let number = reactive({name:"苹果",price:100});
​
function Add(){
    number.price = number.price + 10;
}
function Switch(){
    //number = {name:"梨" , price: 200}  //错误写法
    //number = reactive({name:"梨" , price: 200})    //错误写法
    Object.assign(number,{name:"梨" , price: 200})
}
​
</script>

恭喜你,学到这你已经学完了Vue3的第一阶段了


第二阶段:toRefs , toRef (内值响应化)

前置

toRefs与reactive的比对 , ref好像不需要

javascript 复制代码
Proxy(Object) {name: '苹果', price: 100}  //reactive的内值并没有响应化
{name: ObjectRefImpl, price: ObjectRefImpl} //toRefs会使内值响应化
复制代码
        所以,我们现在有一个要解决的问题
javascript 复制代码
<template>
    <p>我是{{ number.name }} , 我值{{ number.price }}元</p>
    <button @click="Add">我是加法</button>
</template>

<script setup lang="ts">
import { reactive } from "vue"
let number = reactive({
    name:"苹果",
    price:100
});

let {price} = number;

function Add(){
    price += 1	//为什么数据没有发生变化
}

</script>

1.toRefs数据内全值响应化

目标1:使内数据响应化

javascript 复制代码
<template>
    <p>我是{{ number.name }} , 我值{{ number.price }}元</p>
    <button @click="Add">我是加法</button>
</template>

<script setup lang="ts">
import { reactive , toRefs } from "vue"
let number = reactive({
    name:"苹果",
    price:100
});

let {price} = toRefs(number);	//内数据ref化 ,注:此处为地址引用,
												//修改的为实际number
function Add(){
    price.value += 1	//所以这里要加value
}

</script>

2.toRef数据内单值响应化

目标1:使内数据某一个值响应化

javascript 复制代码
<template>
    <p>我是{{ number.name }} , 我值{{ number.price }}元</p>
    <button @click="Add">我是加法</button>
</template>

<script setup lang="ts">
import { reactive , toRef } from "vue"
let number = reactive({
    name:"苹果",
    price:100
});

let price = toRef(number , "price")

function Add(){
    price.value += 1
}

</script>

恭喜你,学到这你已经学完了Vue3的第二阶段了


第三阶段:computed , v-model

彩蛋插入 v-model

打断一下,这里教大家一下数据的双向绑定v-model

javascript 复制代码
<template>
    姓:<input type="text" v-model="firstName"><br>
    名:<input type="text" v-model="lastName"><br>
    姓名:{{ firstName + lastName }}
</template>

<script setup lang="ts">
import { ref } from "vue"

let firstName = ref("博丽")
let lastName = ref("七七")
</script>

当数据更改时 input.value赋值给firstName导致姓名发生变化,lastName同理

1.computed处理多次执行函数(有缓存)

目标1:不想让全名等于firstName+lastName

javascript 复制代码
<template>
    姓:<input type="text" v-model="firstName"><br>
    名:<input type="text" v-model="lastName"><br>
    姓名:{{ fullName }}
</template>

<script setup lang="ts">
import { ref , computed } from "vue"

let firstName = ref("博丽")
let lastName = ref("七七")
let fullName = computed(()=>{
    return firstName.value + lastName.value;
})
</script>

但是,我们又出现了新的问题,computed绑定的fullName是可读的,我们修改不了它的值,fullName.value = "1" 这会报错的,那我们应该怎么优化呢?

javascript 复制代码
<template>
    姓:<input type="text" v-model="firstName"><br>
    名:<input type="text" v-model="lastName"><br>
    姓名:{{ fullName }}
</template>

<script setup lang="ts">
import { ref , computed} from "vue"

let firstName = ref("博丽")
let lastName = ref("七七")
let fullName = computed({
    get(){
        return firstName.value + lastName.value
    },
    set(val){	val就是传入的fullName.value
        console.log(val)
        firstName.value = val
        ....		//这里我们就可以进行后续操作啦
    }
})

恭喜你,学到这你已经学完了Vue3的第三阶段了


第四阶段:watch(手动监视器) , watchEffect(自动监视器)

前置

作用:监视数据的变化

特点:Vue3中的watch只能监视以下四种数据

1.ref定义的数据

2.reactive定义的数据

3.函数返回一个值

4.一个包含上述内容的数组

注:watch里ref不写value哦

1.watch监视情况1 ref

目标1:加到10后停止输出

javascript 复制代码
<template>
    我是数字{{ number }}
    <button @click="Add">我是加法</button>
</template>

<script setup lang="ts">
import { ref, watch } from "vue"

let number = ref(0);
function Add() {
    number.value++;
}
const stopWatch = watch(number, (newValue, oldValue) => {
    console.log(newValue , oldValue);
    if(newValue > 10){
        stopWatch()	//大于10就结束监视
    }
})
</script>

2.watch深度监视 ref

若修改的是ref定义的对象中的属性,newValue和oldValue都是新值,因为它们是同一个对象

若修改整个ref定义的对象,newValue是新值,oldValue是旧值,因为不是同一个对象了

目标1:深度监视

javascript 复制代码
<template>
    我是名字:{{ number.name }}<br>
    我是价格:{{ number.price }}<br>
    <button @click="Add">我是加法</button>
    <button @click="Switch">我是切换</button>
</template>

<script setup lang="ts">
import { ref, watch } from "vue"

let number = ref({name:"博丽七七" , price:100});
function Add() {
    number.value.price++;
}
function Switch(){
    number.value = {name:"李四" , price:300}
}
watch(number, (newValue, oldValue) => {
    console.log(newValue , oldValue);
} , {deep:true})//深度监视可选
</script>

此时,有个注意点深度监视开启时,如果价格改变,新旧值则是相同的

javascript 复制代码
Proxy(Object) {name: '博丽七七', price: 101}
Proxy(Object) {name: '博丽七七', price: 101}
javascript 复制代码
​​​​​​​Proxy(Object) {name: '博丽七七', price: 101}
Proxy(Object) {name: '博丽七七', price: 101}

如果改变对象,新旧值则是

javascript 复制代码
Proxy(Object) {name: '李四', price: 300} 
Proxy(Object) {name: '博丽七七', price: 102}

一般我们不管旧值

3.watch深度监视 reactive

监视reactive定义的对象类型数据,默认开启了深度监视,且无法关闭

同上

javascript 复制代码
<template>
    我是名字:{{ number.name }}<br>
    我是价格:{{ number.price }}<br>
    <button @click="Add">我是加法</button>
    <button @click="Switch">我是切换</button>
</template>

<script setup lang="ts">
import { reactive, watch } from "vue"

let number = reactive({name:"博丽七七" , price:100});
function Add() {
    number.price++;
}
function Switch(){
    Object.assign(number,{name:"李四" , price:300})
}
watch(number, (newValue, oldValue) => {
    console.log(newValue , oldValue);
})
</script>

4.watch监听特定属性

若该属性值不是对象类型,需要写成函数形式

若该属性值依然是对象类型,可直接写,也可写成函数,建议直接写成函数

同上

javascript 复制代码
<template>
    我是名字:{{ number.name }}<br>
    我是价格:{{ number.price }}<br>
    <button @click="Add">我是加法</button>
    <button @click="Switch">我是切换</button>
</template>

<script setup lang="ts">
import { reactive, watch } from "vue"

let number = reactive({
    name: "博丽七七",
    price: 100,
    other: {
        a: 1,
        b: 2,
    }
});
function Add() {
    number.price++;
    number.other.a++;
}
function Switch() {
    Object.assign(number, { name: "李四", price: 300 })
}
watch(() => number.price, (newValue, oldValue) => {
    console.log(newValue, oldValue);
})
   //这里只展示推荐写法
watch(() => number.other, (newValue, oldValue) => {
    console.log(newValue, oldValue);
}, { deep: true })
</script>

5.watch监视多个数据

同上

javascript 复制代码
watch([() => number.other , number.price , ......], (newValue, oldValue) => {
    console.log(newValue, oldValue);
}, { deep: true })

其他

javascript 复制代码
watch([temp , heigth], (Value) => {
    let [newTemp , newHeigt] = value
	传入不同变化,是会赋给两个哦
})

6.watchEffect实现自动监视

watch与watchEffect对比

1.都能监听响应式数据的变化,不同的是监听数据变化的方式不同

2.watch:要明确指出监视的数据

3.watchEffect:不用明确指出监视的数据

目标1:实现一个水位控制器

javascript 复制代码
<template>
    需求:当水温达到60度,或水位达到80cm<br>
    当前水温:{{ temp }}<br>
    当前水位:{{ height }}<br>
    <button @click="tempAdd">增加水温</button><br>
    <button @click="heightAdd">增加水位</button><br>
</template>

<script setup lang="ts">
import { ref, watchEffect } from "vue"

let temp = ref(10);
let height = ref(0);

function tempAdd() {
    temp.value += 10;
}
function heightAdd() {
    height.value += 10;
}
watchEffect(()=>{
    if(temp.value >=60 || height.value >=80){
        console.log("发出警告")
    }
})
</script>

<style></style>

与之相对的watch写法

javascript 复制代码
watch([temp , height],(value)=>{
    let [newTemp , newHeight] = value
    if(newTemp >= 60 || newHeight >= 80){
        console.log("发出警告")
    }
})

恭喜你,学到这你已经学完了Vue3的第四阶段了


第五阶段(休息区):标签内ref , defineExpose(暴露值)

这里是轻松愉快小课堂

父组件

javascript 复制代码
<template>
    <Test ref="abc"></Test>		//ref命名
    <button @click="add">点我</button>
</template>

<script setup lang="ts">
import Test from "./components/test.vue"
import { ref } from "vue";
let abc = ref()		//ref获取
function add() {
    console.log(abc.value.a)	//获取子组件的值
}
</script>

子组件

javascript 复制代码
<template></template>
<script setup lang="ts">
import { ref, defineExpose } from "vue";
let a = ref("你好");
let b = ref(1);
defineExpose({ a, b })	//注意:必须要暴露出去父组件才可以拿的到哦
</script>

恭喜你,学到这你已经学完了Vue3的第五阶段了


第六阶段:这里是TS区(想看就看,不看也行)

How to write an interface document about typescript

my typescript file

javascript 复制代码
export interface PersonInter {
    id:string,
    name:string,
    age:number
    price?:number	//这是可选的
}	//这是给对象用的
export type Persons = Array<PersonInter , ... , ...>//这是给数组用的
export type Persons = PersonInter[]//这么写也写

use file

javascript 复制代码
<script ... ... >
import {type PersonInter , type Persons} from "ts路径"//记得要写type哦
let personList:Persons = [{},{},{}]
let personList = reactive<Persons>([{},{},{}])//优雅写法

恭喜你,学到这你已经学完了Vue3的第六阶段了...呃,应该叫ts第一阶段


第七阶段:终于到props啦 ,withDefaults

这节涉及到组件通信,非常重要哦,一定要好好听

入门

父组件

javascript 复制代码
<子组件 a = "abc"></子组件>	//父组件往子组件传了个值

子组件

javascript 复制代码
<template>
	{{ a }}
</template>
<script ... ... >
import { defineProps } from "vue"
defineProps(["a"])	//获得父组件传入的值	
//注意,defineProps是有返回值的,返回值为对象
const jkl = defineProps(["a"])//打印的话是一个对象哦 
</script>

基础props (限制类型)

javascript 复制代码
defineProps<{list:Persons}>()	//同ts , ()里面没东西

进阶props (限制类型+限制必要性+指定默认值)

javascript 复制代码
import { withDefaults } from "vue"
withDefaults(defineProps<{list?:Persons}>(),{
	list:()=> [{id:... , name:... , ......}]  
})
<Test person="ppa" ></Test>

withDefaults(defineProps<{person?: string}>(),{
    person: "bbc"
})

这么难的props居然都被你学会了,继续加油吧,第七阶段, complete!


第八阶段:生命周期函数!!!

这个不难,直接按流程走一遍就行

javascript 复制代码
import { ref , onBeforeMount , onMounted , 
			   onBeforeUpdate , onUpdated , 
			   onBeforeUnmount , onUnmounted} from "vue"
let sum = ref(0)	//数据
function add(){}	//方法
console.log()		//创建
onBeforeMount(()=>{})	//挂载前
onMounted(()=>{})	    //挂载完毕		出生
onBeforeUpdate(()=>{})	//数据更新前
onUpdated(()=>{})		//数据更新完毕	常用
onBeforeUnmount(()=>{})	//卸载前	例如v-if不满足的时候
onUnmounted(()=>{})		//卸载完毕		常用

子优先于父


第八阶段结束了,进入第九阶段Ciallo~(∠・ω< )⌒★


第九阶段:进网络啦,这阶段我写的比较杂

简单axios , 记得下载axios

javascript 复制代码
import { ref , reactive } from "vue"
import axios from "axios"
export default function (){
	let doglist = reactive([...])
	async function getDog(){
		try{
			let result = await axios.get()
			dogList.push(result.data.message)
		} catch(error){
			alert(error)
		}
	}
	//向外部提供东西
	return {dogList , getDog}
}

什么是hook

进入src目录,创建hook文件,里面就放常调用的函数

使用

javascript 复制代码
import useDog from "@/hook/useDog"
const {dogList,getDog} = useDog()

恭喜你,学到这你已经学完了Vue3的第九阶段了


第十阶段:路由

安装vue-router src文件夹里创建router文件夹

创建一个ts文件

javascript 复制代码
import { createRouter, createWebHistory } from "vue-router"
//引入一个一个可能要呈现的组件
import abc from "@/components/test.vue"

//创建路由
const router = createRouter({
    history: createWebHistory(),
    routes: [
        {
            path:"/home",
            component:abc
        }
    ]
})

export default router

main.ts里引入router , 使用router

RouterView路由插槽占位

父组件

javascript 复制代码
<RouterLink to="路由path" active-class="激活时的类名"></RouterLink>	
//略等于a标签 , active-class路由自带的
to的第二种写法-->	:to="{path:"/about"}"

<RouterView></RouterView>	//路由展示区
<script......>
    import { RouterView , RouterLink } from "vue-router"
</script>

src创建pages或views放路由页

换路由会被视作生命周期(卸载)

命名路由

定义

javascript 复制代码
routes: [
        {
            name:"abc"
            path:"/home",
            component:abc
        }
    ]

使用

javascript 复制代码
<RouterLink :to="{name:'abc'}" active-class="激活时的类名"></RouterLink>

子集路由

定义

javascript 复制代码
routes: [
        {
            name:"abc"
            path:"/home",
            component:abc,
			children:[
				{
					path:"detail"	//子集就不用写/了
					component:...
				}
			]
        }
    ]

使用 , 别忘了路由插槽

javascript 复制代码
<RouterLink to="/news/detail"></RouterLink>

query参数 (query版路由传参)

太简单了,直接上代码

父组件

javascript 复制代码
<RouterLink 
	:to="{
         path:"/fff/fff",
         query:{
              id:news.id,...
              title:news.title...
         }
    }"></RouterLink>
//等同于....?fff=...&kkk=...

路由页获取

javascript 复制代码
{{ query.id }}
<script>
import { toRefs } from "vue"
import { useRoute } from "vue-router"
let route = useRoute()
let { query } = toRefs(route)
</script>

params参数 (params版路由传参)

太简单了,直接上代码

路由规则 , 记得占位

javascript 复制代码
routes: [
        {
            name:"abc"
            path:"/home",
            component:abc,
			children:[
				{	
					name:"//"
					path:"detail/:id/:title?"	//子集就不用写/了
									//?为可选
					component:...
				}
			]
        }
    ]

父组件

RouterLink 不能用path换路由了

javascript 复制代码
<RouterLink 
	:to="{
         name:"avcs",
         params:{
              id:news.id,...
              title:news.title...
         }
    }"></RouterLink>
//等同于/.../.../...

子组件用params就行

props配置 (是路由参数获取变得更简单)

第一种写法 (将路由收到的params参数作为props传给路由组件)

javascript 复制代码
children:[
				{	
					name:"//"
					path:"detail/:id/:title?"	//子集就不用写/了
									//?为可选
					component:...
					props:true
				}
			]

使用

javascript 复制代码
{{ id }}
defineProps(["id"])

第二种写法 (query传)

javascript 复制代码
children:[
				{	
					name:"//"
					path:"detail/:id/:title?"	//子集就不用写/了
									//?为可选
					component:...
					props(route){
						return route.query
					}
				}
			]

用法同上

第三种写法 (随便传)

javascript 复制代码
children:[
				{	
					name:"//"
					path:"detail/:id/:title?"	//子集就不用写/了
									//?为可选
					component:...
					props:{
						a:100,
						b:200
					}
				}
			]

repalce属性 (禁止返回上一步)

javascript 复制代码
<RouterLink replace :to="{name:'abc'}"></RouterLink>

编程式路由导航(脱离RouterLink进行路由跳转)

例:

javascript 复制代码
import { useRouter } from "vue-router"
const router = useRouter()
router.push("路由地址")

正确写法

javascript 复制代码
const router = useRouter()

interface NewsInter {
	id:string,
	number:number
}

function ...(news:NewInter){
	router.push({	//push换replace的话就不能返回上一步了 , 看需求
		name:"/"
		query:{
			id:news.id
			number:news.number
		}
})
}

重定向

javascript 复制代码
path:"原路径"
redirect:"新路由路径"	->  会执行这个地址

最长的路由你也都学会了吗,太棒啦,继续加油吧


第十一阶段:组件通信

1.props (父传子 , 子传父)

父传子

javascript 复制代码
<template>
    父组件
    <Test :car="car"></Test>
</template>

<script setup lang="ts">
import { ref } from "vue"
import Test from "./components/test.vue"
let car = ref("奔驰");
</script>

<template>
    子拿到的{{ car }}
</template>

<script setup lang="ts">
defineProps(["car"])
</script>

子传父

javascript 复制代码
<template>
    父组件<br>
    父拿到的{{ toy }}
    <Test :sendToy="getToy"></Test>
</template>

<script setup lang="ts">
import { ref } from "vue"
import Test from "./components/test.vue"
let toy = ref("")

function getToy(value:string){
    toy.value = value
}
</script>

<template>
    子给的{{ toy }}
    <button @click="sendToy(toy)">子给父的</button>
</template>

<script setup lang="ts">
import { ref } from "vue"
let toy = ref("玩具车");
defineProps(["sendToy"])
</script>

2.自定义事件传参 emit

子传父

javascript 复制代码
<template>
    父组件<br>
    父拿到的{{ toy }}
    <Test @sendToy="getToy"></Test>
</template>

<script setup lang="ts">
import { ref } from "vue"
import Test from "./components/test.vue"

let toy = ref("")

function getToy(value:string){
    toy.value = value
}

</script>
///
<template>
    子给的{{ toy }}
    <button @click="emit('sendToy' , toy)">子给父的</button>
</template>

<script setup lang="ts">
import { ref } from "vue"
let toy = ref("玩具车");
const emit = defineEmits(["sendToy"])
</script>

3.mitt实现任意组件通信(第三方)

记得下载 pnpm i mitt

首先,src的目录里新建utils文件夹里面新建一个emitter.ts的文件

javascript 复制代码
//引入mitt
import mitt from "mitt"
const emitter = mitt()
export default emitter

使用

javascript 复制代码
<template>
    父组件<br>
    父有的{{ toy }}
    <Test></Test>
    <button @click="emitter.emit('send-toy' , toy)">父给子</button>
</template>

<script setup lang="ts">
import { ref } from "vue"
import Test from "./components/test.vue"
import emitter from './utils/emitter';

let toy = ref("玩具车")

</script>
/
<template>
    父给子的{{ toy }}
</template>

<script setup lang="ts">
import { ref, onUnmounted } from "vue"
import emitter from "../utils/emitter";
let toy = ref("");
emitter.on("send-toy", (value: string) => {
    toy.value = value
})
onUnmounted(() => {
    emitter.off("send-toy")
})
</script>

4.v-model以后再说

5.剩下的不写了,写多了记不住


恭喜你,学到这你已经学完了Vue3的第十一阶段了


第十二阶段:插槽

javascript 复制代码
<slot></slot>

具名插槽

javascript 复制代码
插得元素
<template v-slot:插槽名>
被插的
<slot name="插槽名"></slot>

作用域插槽

插槽子传父

插得元素

javascript 复制代码
<template v-slot="params">
    <ul>
        <v-for="item in params.youxi":key="item.id"></v-for>
    </ul>
</template>

被插的

javascript 复制代码
<slot :youxi="game"></slot>
<script>
	let games = reactive([
        {},{},{}
    ])
</script>

插的起名这么起

javascript 复制代码
<template v-slot:插槽名="params">
复制代码
相关推荐
come1123414 分钟前
Vue 响应式数据传递:ref、reactive 与 Provide/Inject 完全指南
前端·javascript·vue.js
前端风云志36 分钟前
TypeScript结构化类型初探
javascript
musk12121 小时前
electron 打包太大 试试 tauri , tauri 安装打包demo
前端·electron·tauri
翻滚吧键盘1 小时前
js代码09
开发语言·javascript·ecmascript
万少2 小时前
第五款 HarmonyOS 上架作品 奇趣故事匣 来了
前端·harmonyos·客户端
OpenGL2 小时前
Android targetSdkVersion升级至35(Android15)相关问题
前端
rzl022 小时前
java web5(黑马)
java·开发语言·前端
Amy.Wang2 小时前
前端如何实现电子签名
前端·javascript·html5
海天胜景2 小时前
vue3 el-table 行筛选 设置为单选
javascript·vue.js·elementui
今天又在摸鱼2 小时前
Vue3-组件化-Vue核心思想之一
前端·javascript·vue.js