目录
Toggle一.了解vue3
Vue3 是一套构建用户界面的渐进式框架,用来构建响应式页面。
Vue 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。
二.创建vue3
1.在文件夹中打开终端 输入npm create vue@latest(确保node版本大于20)
2.创建过程 第一个选择typescript 第二个不选直接回车 然后选择yes即可创建成功
3.安装node npm install
4.启动服务 npm run dev

三.vue3基础
1.更改名称
①.先在当前项目文件夹终端输入 npm i vite-plugin-vue-setup-extend -D 下载
②.在vite.config.ts进行配置
1.import vueSetupExtend from ‘vite-plugin-vue-setup-extend’;
2. vueSetupExtend(),

直接在script 标签后面使用即可,如图⬇

2.setup
setup时vue3新增的语法糖(api)
不支持使用this
直接在script 标签后面使用即可,如图⬇

3.响应式
1.ref
1.用于基本数据类型时:
* 需要添加.value;

2.用于引用数据类型时:
* proxy底层
* 修改时 可以直接修改对象 也可使用Object.assign() 
3.作用于多层结构修改整体时
都可直接修改,也可以使用Object.assign()

2.reactive
1.用于引用数据类型
* 修改整体时候 使用Object.assign()进行合并,第一个参数为要合并到的地方,第二个参数为要合并的参数

2.用于多层结构修改整体时
必须用Object.assign() 进行修改

3.vue2与vue3 响应式的区别
vue2响应式:Object.defineproperty() 中的getter和setter去劫持数据修改数据 以达到数据响应式
vue3响应式:通过Proxy代理 去执行响应式
4.解构
1.引入
toRefs(全部解构)或toRef(部分解构)

2.全部解构:
const{属性,属性}=toRefs(对象名)
3.部分解构
let 对应属性的变量名 =toRef(对象名,’对应属性’)
也要用.value才可以使用
//全部解构
const{name,age}=toRefs(obj)
console.log(name,age)
//部分解构
let age1 =toRef(obj,'age')
function changeName() {
//.value使用
name.value = '小李'
}
5.计算属性 computed
1.使用计算属性需引入

2..计算属性包含get 和 set
let firstName = ref("");
let lastName = ref("");
let fullName = computed({
// 计算属性包含get 和 set
get() {
return firstName.value + lastName.value;
},
set(val) {
<!-- 解构数组 -->
let [x, y] = val.split("-");
firstName.value = x;
lastName.value = y;
},
});
// 设置计算属性的设置函数
function setName() {
fullName.value = "张-飞";
}
split(“-“) 用来表示以-为标志 拆分字符串 变为数组
6.监听属性Watch
监听属性 使用时先引用

格式:watch(监听对象,(新值,旧值)=>{ 监听时执行的函数},{ deep:true,
immediate:true}
* 1.监听对象
* 2.回调方法(自带两个属性 newValue, oldValue)
* 3.开启立即深度监听 deep:true, immediate:true

1.Watch:监听ref定义的基本数据类型
监视ref定义的基本类型数据:直接写数据名即可,监视的是其value值的改变
只要数值变化 即可监听
2.Watch:监听ref定义的引用数据类型
watch监听ref引用数据类型 监听的是整体 而不是单独的属性
监视ref定义的引用类型数据:直接写数据名,监视的是对象的地址值,若想监视对象内部的数据,要手动开启深度监视。
注意:
- 若修改的是ref定义的对象中的属性,newValue 和 oldValue 都是新值,因为它们是同一个对象。
- 若修改整个ref定义的对象,newValue 是新值, oldValue 是旧值,因为不是同一个对象了。

<script lang='ts' setup>
import { ref, watch} from 'vue';
let obj = ref({
name:'张三',
city:'上海'
})
function changeName() {
obj.value.name = '李四'
}
function changeAll() {
obj.value = {
name:'王五',
city:'北京'
}
}
watch(obj,(newValue, oldValue)=>{
console.log(newValue, oldValue);
},{
deep:true,
immediate:true
})
</script>
3.Watch:监听reactive引用数据类型
无论是单层还是多层或者是整体,都可以监听到,有没有deep也都没有影响,监听变化时 旧值和新值相等
但是如果监听某一个属性的变化,需要写成函数体形式 ()=>对象名.属性名,,此时新旧值不相等

⭐如果监听对象中的第二层对象 则只有第二层对象中所有属性都变化时才会被监听,但如开启深度监听,则有一个属性变化即可被监听
⭐如果需要监听多个属性,则写成数组形式,里面写函数体即可,其他同上
watch(
// 两个属性同时监听 写成数组形式
[()=>obj.main,()=>obj.name],
(newValue, oldValue) => {
console.log(newValue, oldValue);
},
{
deep: true,
immediate: true,
}
);
综上。监视ref或reactive定义的引用类型数据中的某个属性,注意
- 若该属性值不是引用类型数据,需要写成函数形式。
- 若该属性值是依然是引用类型数据,可直接编,也可写成函数,建议写成函数。
- 监视的要是对象里的属性,那么最好写函数式,注意点:若是对象监视的是地址值,需要关注对象内部,需要手动开启深度监视
7.生命周期函数
1. vue2生命周期
三个阶段:
1.初始化:
beforeCreate 创建前 方法methods与数据data都是无法访问的
created 创建后 方法methods与数据data都是可以访问的
2.运行:
beforeMount 挂载前 页面没有真实渲染dom 无法进行dom操作
mounted 挂载后 页面真实渲染dom 可以进行dom操作
beforeUpdate 更新前 数据变化 视图未变(页面内的内容以改变
但未渲染页面,所以获取到还是之前视图的数据)

updated 更新后 数据变化 视图改变
3.销毁:
beforeDestory 销毁前 对DOM操作已经无效
destoryed 销毁后 彻底销毁
2.vue3生命周期
写作回调函数:例如⬇
onBeforeMount(() => {
console.log(“onBeforeMount”);
});
1.初始:setup
2.运行:
挂载:onBeforeMount onMounted(同理)
更新:onBeforeUpdate onUpdated(同理)
3.卸载:
onBeforeUnmount onUnmounted
8.在vue3中使用ts
1)引用
1.引用ts 直接在scrpit后面写 lang=”ts”

2)ref
1.ref定义的基本数据类型 直接在ref后面加上<数据类型1 | 数据类型2>(| 表示二者都可以)

2.ref定义的引用数据类型 先定义接口 然后在ref后面加上<接口名>
interface Person{
name:string;
age:number;
}
let obj:Person = reactive({
name: "图图",
age: 3,
});
3)reative
reative定义的引用数据类型 先定义接口 然后在对象名后面加上:接口名
interface Person{
name:string;
age:number;
}
let obj = ref<Person>({
name: "美羊羊",
age: 4,
});
4)函数
函数加数据类型 直接在函数名()后面加上数据类型
注意:加除了any,unknow的数据类型外 函数体内都要加return 返回值,否则加void返回空也可以

5)computed计算属性
直接在computed后面加<>
如有set 就在set中的参数后面加数据类型 set()后面也加数据类型
let fullName = computed<string>({
get() {
return firstName.value + lastName.value;
},
set(val: string):void{
let [x, y] = val.split("-");
firstName.value = x;
lastName.value = y;
},
});
6)watch监听属性加数据类型
直接在newValue, oldValue 后面添加数据类型
注意 如果开启了立即深度监听 则oldValue 后除了正常的数据类型还要加undefined
watch(
flower,
(newValue:number, oldValue:number|undefined) => {
console.log(newValue, oldValue);
},
{
deep: true,
immediate: true,
}
);
对象也同理 但是newValue, oldValue 后面添加定义好的接口

7)将ts写入单独文件再引用
⭐将ts抽离到文件中引用
①.想要在其他文件中被使用的 必须前面加export

②.在需要引用的文件中import 直接引用名字不好使就在前面加type 例如 type Person

③.如果想引用接口 泛型继承接口,方法如下👇
import {Person} from '../type/Demo23'
function fn1<T extends Person>(a:T):T {
return a;
}
fn1({name:'图图'})
④.如果想用接口定义的数据类型组成的数组
则数组前面加type,后面添加接口为数据类型
格式:type 数组名=接口名[ ]

引用这个数组方法如下👇
import {list} from '../type/Demo23'
let newList:list = reactive([
{
name:'图图',
age: 103,
sex:'男'
}
])
9.Ref
1.ref的使用
在标签中定义ref 然后在script中用定义的名字加.value即可获得标签
<p ref="aaa">标签</p>
<!-- script 中 -->
console.log(aaa.value);

⭐添加类型数据时后面是null,<>内可以用any(但少用),也可以用HTMLInputElement 表示标签内容的类型
let inputRef = ref<HTMLInputElement | null>(null);
input标签同理
2.使用ref控制input标签聚焦、失焦
1.定义ref
2.使用ref定义的名字加.value加.focus控制聚焦
使用ref定义的名字加.value加.blur控制失焦
<input type="text" ref="inputRef" />
<!--sc -->
onMounted(() => {
// 聚焦失焦
setTimeout(
() => {
inputRef.value?.focus();
2000;
},
setTimeout(() => {
inputRef.value?.blur();
}, 4000)
);
});
3.defineExpose
defineExpose后面写谁 谁就可以被展示
例如👇子页面中
let a = ref<number>(1);
let b = ref<number>(2);
defineExpose({ a, b })
同时主页面中👇
<Demo24 ref='main'></Demo24>
</template>
<script lang="ts" setup>
import { ref ,onMounted} from "vue";
import Demo24 from "./components/Demo24.vue";
let main =ref<any>(null)
onMounted(() => {
console.log(main.value.a)
console.log(main.value.b)
})
即可展示a,b
10.defineProps 父组件向子组件传参
1.传什么接什么
例子👇
父组件传参:
<Demo25 :list1='list'></Demo25>
<!-- sc中 -->
import Demo25 from "./components/Demo25.vue";
interface Person{
name:string;
age:number;
}
let list:Person[]=[
{name:"张三",age:18},
{name:"李四",age:20},
{name:"赵五",age:100}
]
⭐ 其中list1为子组件接受时的名字 list为父组件传参时的名字
子组件接收
<ul>
<li v-for="item in list1" :key="item.index">
我叫{{ item.name }},今年{{ item.age }}岁
</li>
</ul>
// sc中
defineProps(['list1'])
效果:

2.规定接收类型传参
例子👇
父组件传参:
<Demo25 :name1='name' :age1='age'></Demo25>
<!--sc-->
let name = ref<string>('迪迦')
let age = ref<number>(15)
子组件接收:
<p>我叫{{ name1 }},今年{{ age1 }}岁</p>
// sc
defineProps({
name1:String,
age1:Number,
})
此时如果父组件传进来的参数类型不符合 则报错
效果:

3.是否必传+展示默认
格式:withDefaults(defineProps<{ ①写必传项所有参数的类型}>(),
{ ②写如果不传参 则默认展示的内容})
⭐①处如果在属性后面加上?则表示不是必传
例子👇 子组件中:
withDefaults(
defineProps<{
list1?: Person[];
name1?: string;
age1?: number;
}>(),
{
name1: "未知用户",
age1: 100,
list1: () => {
return [{ name: "q", age: 12 }];
},
}
);
效果:

注意:此处👇 数组类型加return 因为类型默认为接口定义的类型 必须有返回值
11.watchEffect
watchEffect 自动的监听数据 发生改变 依赖也会随之变化
直接在里面拼接 每当有值变化 结果就会随之变化
watchEffect(()=>{
console.log(user,'user')
console.log(fullName.value,'fullName')
fullName.value = user.firstName + user.lastName
})
12.自定义HOOKS
就是把自己定义的方法抽离出来 使用时引入
1.新建hooks文件夹
钩子文件一定要以use开头命名
例子 鼠标位置可视化:
2.写钩子 useMove:
import { ref, onMounted, onUnmounted } from 'vue'
export function useMove() {
let x = ref<number>(0);
let y = ref<number>(0);
function handleMove(e: MouseEvent): void {
x.value = e.pageX;
y.value = e.pageY;
}
onMounted(() => {
window.addEventListener('mousemove', handleMove)
})
onUnmounted(() => {
window.removeEventListener('mousemove', handleMove)
})
// 要返回!
return { x, y }
}
⭐①.因为我们要使用的是x,y 所以一定要返回x和y 不然引用的时候无法接收
②.e(event)类型可以写MouseEvent 鼠标事件自带的类型
3.引用:
<template>
<div>
<h1>自定义hooks</h1>
<p>鼠标位置:x轴:{{x}};y轴:{{y}}</p>
</div>
</template>
<script lang='ts' setup>
import {useMove} from '../hooks/useMove';
// 解构
const {x,y}=useMove();
因为useMove钩子返回的是数组{x,y} 所以直接解构即可使用 名字一定要对应
⭐addEventListener(①,②,③ )
默认的三个参数 第一个为监听对象,第二个为监听方法,第三个为事件方法 默认为false 即事件冒泡 ,写true即为事件捕获
⭐ 事件冒泡与事件捕获
由里向外为事件冒泡,由外向里为事件捕获
13.路由
1.创建项目后安装路由
npm install vue-router@4
2.配置
①.在src下新建文件夹router,router下新建index.ts 进行配置
②.在index.ts 引入👇并且抛出 否则无法挂载


③.在main.ts中用use进行挂载
或
④.在src下新建文件夹views,在views下新建页面写路由页面

⑤.在index.ts中引入路由页面: 1.引入地址 2.匹配路由
其中history表示路由类型(createWebHashHistory表示哈希;createWebHistory表示history)
routes表示引入的当前项目匹配的路由(path表示路径,component表示该页面的名字)

⑥.在app.vue中显示 RouterView为router的占位符,在template写入后在网页中切换网页地址即可展示


3.多级路由
引入子页面后 直接在父路由下加children
只要是多级路由 path就不需要写/
但是其他操作还是需要从父路由开始写 比如声明式导航 to后面的path

4.给router加ts类型
1.引入RouteRecordRaw类型
RouteRecordRaw类型 是vue-router自带的类型 包括了path component children等类型

2.提出routes 重新定义 再在router中直接引用

3.将RouteRecordRaw类型 加到routes

⭐注意!是给router中的routes加RouteRecordRaw类型 不是router整体
5.重定向
重定向就是进入一个页面的地址直接定位到重定向的页面
重定向也是通过 routes 配置来完成,下面例子是从 / 重定向到 /home:

6.query 传参
①.直接在RouterLink 动态绑定to 后面传参内容一定要加反引号“,后面写xx:${yy.xx}用&合并
<RouterLink
:to="`/list/demo1?id=${item.id}&user=${item.name}&sex=${item.sex}`" >{{ item.name }}</RouterLink>
然后在跳转的子路由引入 useRoute ,对传入的数组解构 toRefs(route.query) 就是useRoute().query

②.直接在RouterLink 动态绑定to 后面传参内容写成对象
<RouterLink
:to="{
path: '/list/demo1',
query: {
id: item.id,
user: item.name,
sex: item.sex,
},
}"
>{{ item.name }}</RouterLink>
其他不变 path也可用name
7.params传参
①.直接在RouterLink 动态绑定to 后面传参内容直接写{yy.xx}用/间隔
<RouterLink :to="`/list/demo1/${item.id}/${item.name}/${item.sex}`">{{
item.name
}}</RouterLink>
与此同时index.ts中跳转的子页面path要随之更改 传什么加什么

然后在跳转的子路由引入 useRoute ,对传入的数组解构
toRefs(route.params)就是useRoute().params
②.直接在RouterLink 动态绑定to 后面传参内容写成对象,但不可用path 只能用name
<RouterLink :to="{
name:'dier',
params:{
user:item.name,
id:item.id,
sex:item.sex
}
}">{{ item.name }}</RouterLink>
8.声明式导航
在父路由页面 引入RouterLink和RouterViews
在template直接使用RouterLink 用来展示路由界面 其中to属性表示定位
然后使用RouterViews占位显示 无论几个子路由 只需要一个占位

9.编程式导航
直接在父页面 引用useRouter

router.go(1),是前一页 -1是后一页
router.back()回退一夜
router.forword()向前一页
10.路由懒加载
就是不直接引入 而在component中引入

11.RouterLink
RouterLink用来显示页面
在to 前面加push表示可以回退的路由方式
加replace 表示不能回退
回退:
12.组件缓存
①.在父路由的RouterViews中 写入
<RouterView v-slot="{Component}">
<KeepAlive>
<component :is="Component" v-if="route.meta.KeepAlive"></component>
</KeepAlive>
<component :is="Component" v-if="!route.meta.KeepAlive"></component>
</RouterView>
v-slot=”{Component}”和 <component :is=”Component” v-if=”!route.meta.KeepAlive”></component>是用插槽绑定组件,再用组件标签将其展示
②.KeepAlive
用KeepAlive标签包起来的部分将缓存 也就是保留组件状态 如需部分缓存:👇
使用:
1.在index.ts中引入KeepAlive

2.在index.ts的子路由中加meta 加入KeepAlive属性 值为true或false
即可利用route.meta.KeepAlive进行判断 如上代码

14.组件间传参
1.props
直接用动态绑定传参 然后子组件用 defineProps 接受使用即可
2.custom
在父组件中自定义事件名传给子组件
子组件用 defineEmits 接收 方法:👇
①.子组件定义一个变量接收defineEmits, 一般为 emit
②.如在父组件传过来事件时定义了类型,则接收时就不要定义类型 否则报错
③.在子组件接收完成后直接在使用时用 变量名(emit).(接收的参数(senfMoney),传出的参数(part))
<template>
<button @click="emit('sendMoney',part)">给父亲钱</button>
<button @click="emit('sendFlower',part1)">给父亲花</button>
</div>
</template>
<script lang='ts' setup>
import { ref, defineEmits } from "vue";
const part = ref(50);
const part1 = ref(10);
const emit = defineEmits(["sendMoney","sendFlower"]);
接收多个参数时用数组
3.$refs 与$parent
1.$refs 父组件同时控制子组件共有的变量
①.在父组件中给想获取的所有子组件绑定上 ref 然后定义


②.在子组件中开放权限 用 defineExpose

③.在父组件中 绑定函数后面加$refs
<button @click=”changeMoney($refs)”>偷钱</button>
④.在父组件中用 for in 循环控制子组件中元素 (money 就为所有子组件都有的)

for in 循环
在对象中循环 key 为对象属性名
const changeMoney=(val:any)=>{
for(let key in val){
val[key].money -=100
}
}
2.$parent
①.在子组件 绑定函数 后面加$parent

②.父组件中开放权限 用 defineExpose

③.子组件函数中控制父组件的元素

4.mitt
实现随意两个组件间传参
1.安装 mitt :npm install mitt
安装完后 src 中新建 utils 文件夹 再新建 mitt.ts/js 文件 定义之后再抛出


2.使用 mitt 传参
①.在想使用 mitt 的组件引入

②.传参方绑定事件后 函数定义中使用 emitter.emit 调用
function sendMoney(){
emitter.emit('foo',money.value/5)
}
③.接参方使用 emitter.on 监听 可在组件卸载时用 emitter.off 取消监听
emitter.on('foo', (val: number) => {
main.value = val
})
5.attrs
用于父子孙三代中父孙传参
只需在子页面中对孙标签绑定v-bind=”$attrs”即可像父子之间一样正常传参

父页面中

孙页面中 defineProps 接收
defineProps<{
my:number
getCar(val:number):void
}>()
6.provide 与 inject
provide: 提供 由父组件提供 在父组件中引入

抛出 第一个参数 ① 为名字(自己取),第二个开始为要传递的参数 可以传递不同名字的 provide 同时孙组件也可以按名字接收
provide('flower', {flower,getFlower});
provide('vase', {book});
inject : 注入 由孙组件引入

接收 解构 在传过来的名字 ① 中解构 前面为结构出来的传递过来的参数
const { flower, getFlower } = inject<any>("flower");
const {book}=inject<any>("vase")
注意 ts 类型在 inject 后面定义
15.插槽
1.默认插槽
在哪放插槽 引用的时候就在哪出现
<h1>默认插槽</h1>
<br><br><br>
<hr>
<Part2>你好</Part2>
<h2>Part2</h2>
<slot>标题</slot>
<p>哈哈哈哈</p>
你好就会出现在标题位置覆盖标题
2.具名插槽
给插槽起名字后 ,如果只剩一个插槽没起名字,它的名字就为默认的 default 在父组件引用时要在子组件标签内用 temlpete 标签几个插槽就几个 temlpete 标签
直接在temlpete 标签上引用名字 方法有两种 #名字或 v-slot:名字
<h1>具名插槽</h1>
<br /><br /><br />
<hr />
<Part2>
<template #s2>
</template>
<template #default>
</template>
<template v-slot:s1>
</template>
</Part2>
3.作用域插槽
与具名插槽类似 但引用时要用 v-slot:名字=作用域
<Part2>
<template v-slot:two="{list2}">
<ul>
<li v-for="(item,index) in list2" :key="index">
{{ item.name }}
</li>
</ul>
</template>
<template v-slot:one="{list1}">
<ul>
<li v-for="(item,index) in list1" :key="index">
{{ item.desc }}
</li>
</ul>
</template>
</Part2>
<div>
<h2>Part2</h2>
<slot :list1="list" name="one"></slot>
<slot :list2="list" name="two"></slot>
</div>
</template>
<script lang='ts' setup>
import { ref, reactive } from "vue";
let list = reactive([
{
name: "孙悟空",
desc: "金箍棒",
},
{
name: "猪八戒",
desc: "九齿钉耙",
},
]);
16.pinia
1.安装 pinia
npm install pinia
2.配置
1.在 main.ts 中引入
引入 createPinia
定义createPinia()
挂载到 app 上
import{createPinia} from 'pinia'
// createApp(App).mount('#app')
const app = createApp(App);
const pinia = createPinia();
app.use(pinia);
app.mount('#app');
2.新建 store 文件夹
1.文件夹中新建 ts 文件
一般命名与同此 ts 文件的组件名一致
2.在 ts 文件中引入 defineStore
引入后 抛出定义字段,字段名一般为 useXxxStore
defineStore 函数第一个参数为名字,后面为 state getter action
import { defineStore } from "pinia";
export const useCountStore = defineStore('news', { })
3.在组件中引入此 ts 文件
import { useCountStore } from "../store/count";
3.构成
1.state
state 类似于 data 方法
直接在里面 return 想存储的值
state() {
return {
count: 100,
hello: 'hello'
}
},
2.getter
getter 类似 computed 计算属性
可以写为两种形式 可以使用 this
getters: {
bigCount: (state) => state.count * 10,
bigWord() {
return this.hello.toUpperCase()
}
},
3.action
action 类似与 methods 直接在里面写方法 可以用 this
actions: {
changeBig(val: string) {
console.log(val, 'val')
return val.toUpperCase()
},
addNumber(val: number) {
this.count += val;
}
}
4.调用
1.解构
引入 pinia 自带的结构方法 storeTorefs

引入 store 文件后自定义字段

直接用storeTorefs 解构即可
let { count, bigCount, bigWord, changeBig, addNumber } = storeToRefs(counter);
2.使用
在 templete 中直接使用解构后的名字即可
在 script 中要用定义好的字段去调用
<h3>初始值:{{ count }},变大:{{ bigCount }}</h3>
<p>
打招呼:{{ hi }},转大写:{{ bigWord }},转大写{{ counter.changeBig("nihao") }}
</p>
也可以直接在函数中用定义好的字段去调用
function handleAdd() {
console.log(num.value);
counter.addNumber(num.value)
counter.count += num.value;
}
4.$patch
可以直接深度接触 state 中去修改其中的数据
counter.$patch({
count: counter.count + num.value,
});
👆就可以直接讲 state 中的 count 重新赋值
17.toRaw 与 markRaw
1.toRaw 将响应式的对象变成原始对象
2.markRaw 将一个对象标记为不可被转为代理,返回该对象本身。(无论用什么包 都是原始对象)
18.shallowRef 与 shallowReactive
shallowRef 与 shallowReactive 就是将数据变成浅层响应式数据
1.shallowRef
shallowRef 定义基本数据类型是浅层 与 ref 定义的一样,定义引用数据类型时,只有最外层为响应式 里面的数据都不是响应式
let person1 = shallowRef({
name:'懒羊羊',
age:3
})
👆只有 person 是响应式的可以更改 里面的 name 和 age 都不是响应式
2.shallowReactive
shallowReactive 定义的引用数据类型 也是表层为响应式
let person2 = reactive({
name:'懒羊羊',
age:3,
address:{
a1:"青青草原",
a2:"铁锅"
}
})
👆person2 中 age name address 都是响应式,address 里面的 a1,a2 都不是 不可更改
19.readonly 与 shallowReadonly
readonly 就是将定义的类型变为只读 不可更改
shallowReadonly 只将浅层的变为只读 里面还是可以更改的
let person = reactive({
name:"图图",
age:3,
address:{
a1:"1",
a2:'2'
}
})
👆a1,a2 还是可以更改
20.Teleport
<Teleport> 是一个内置组件,它可以将一个组件内部的一部分模板“传送”到该组件的 DOM 结构外层的位置去。
就是可以控制该组件相对于哪层 dom 标签
<template>
<div>
<h1>Teleport</h1>
<div class="box">
<Teleport to='body'>
<Demo></Demo>
</Teleport>>
</div>
</div>
</template>
<script lang='ts' setup>
import { ref, reactive, Teleport} from 'vue';
import Demo from './demo.vue'
</script>
<style lang='scss' scoped>
.box{
width: 500px;
height: 500px;
background-color: rgb(18, 7, 234);
filter: saturate(200%);
}
</style>
比如👆引用的 Dome 组件是一个相对于屏幕居中的正方形,但他外层的组件 filter: saturate(200%);属性 会导致Dome 组件相对于他居中,如果在Dome 组件组件外套上Teleport 标签即可改变他的相对位置 to 后面=的谁 就相对于谁
21.Suspense
<Suspense> 是一个内置组件,用来在组件树中协调对异步依赖的处理。它让我们可以在组件树上层等待下层的多个嵌套异步依赖项解析完成,并可以在等待时渲染一个加载状态。
也就是异步加载的慢的时候控制显示的东西 👇Loading

想控制哪个组件就在外面包上Suspense 其自带 #fallback 插槽
标签内显示提示的信息
<div>
<h1>Suspense</h1>
<Suspense>
<Demo></Demo>
<template #fallback> Loading... </template>
</Suspense>
</div>
22.vant
官网
23:配服务
方法 1.
1.在 vite.config.vue 中配服务
在defineConfig 里面 写 service
2.在server 中 用 proxy 配置
格式👇
/api:名字
target:源
server: {
proxy: {
'/api': {
target: '接口网址',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
},
},
方法 2
1.在 src 新建 utils 文件夹 写 request 文件
参考 axios 官网
const instance = axios.create({
baseURL: 'https://some-domain.com/api/',
timeout: 1000,
headers: {'X-Custom-Header': 'foobar'}
});
baseURL 后面写 .evn.development 文件中 定义名字 格式👇
baseURL: ‘https://some-domain.com/api/’
2.在项目下新建.evn.development
在.evn.development 文件中 定义名字及地址
3.在 src 中新建 api 文件夹 在 xxx.js 写具体页面所需的请求方法
先引入request 中抛出的 axios 名 from ‘../untils/request’