目录
七、插槽
插槽就是子组件中的提供给父组件使用的一个占位符,用<slot></slot> 表示,父组件可以在这个占位符中填充任何模板代码,如 HTML、组件等,填充的内容会替换子组件的<slot></slot>标签。
1、匿名插槽
父级:
<!--例-->
<template>
<div>
<A>
数据或结构A1
数据或结构A2
</A>
</div>
</template>
<script setup>
import A from '../url.vue'
</script>
子级 :
<template>
<div>
<header>
<div>
头部
</div>
<slot></slot> <!--接收父级传输数据-->
</header>
<footer>
<div>
底部
</div>
<slot></slot> <!--接收父级传输数据-->
</footer>
</div>
</template>
以上为匿名插槽,缺点明显,slot会接收父级传来的所有匿名插槽数据或结构,且使用一遍slot,就遍历一遍,无法选择想插入的父级的某一部分匿名插槽数据或结构。
2、具名插槽
父级:
<!--例-->
<template>
<div>
<A>
<template v-slot:A1>
数据或结构A1
</template>
<template v-slot:A2>
数据或结构A2
</template>
</A>
</div>
</template>
<script setup>
import A from '../url.vue'
</script>
子级:
<template>
<div>
<header>
<div>
头部
</div>
<slot name='A1'></slot> <!--接收父级传输数据-->
</header>
<footer>
<div>
底部
</div>
<slot name='A2'></slot> <!--接收父级传输数据-->
</footer>
</div>
</template>
其中,父级的 <template v-slot:A2>,可简写成 <template #A2>
具名插槽充分解决了匿名插槽不能特定引用的问题。
3、作用域插槽
父级:
<!--例-->
<template>
<div>
<A>
<template v-slot='{data}'>
{{ data.age }}
</template>
<template v-slot='{data}'>
{{ data.name }}
</template>
</A>
</div>
</template>
<script setup>
import A from '../url.vue'
</script>
子级:
<!--例-->
<template>
<div>
<header>
<div>
头部
</div>
<slot name='A1'></slot> <!--接收父级传输数据-->
</header>
<footer>
<div>
底部
</div>
<div v-for="item in list":key="item.id"> <!--接收父级传输数据-->
<slot :data="item"></slot>
</div>
</footer>
</div>
</template>
<script setup>
import {ref} from "vue";
let list = ref([
{
id:1001,
name:Tony,
age:24
},
{
id:1002,
name:Sandy,
age:24
}
])
</script>
4、动态插槽
父级:
<!--例-->
<template>
<div>
<A>
<template #[str]>
数据A1
</template>
<template v-slot='{data}'>
{{ data.name }}
</template>
</A>
</div>
</template>
<script setup>
import A from '../url.vue'
import {ref} from "vue";
let str = ref('A1');
</script>
子级:
<!--例-->
<template>
<div>
<header>
<div>
头部
</div>
<slot name='A1'></slot> <!--接收父级传输数据-->
</header>
<footer>
<div>
底部
</div>
<div v-for="item in list":key="item.id"> <!--接收父级传输数据-->
<slot :data="item"></slot>
</div>
</footer>
</div>
</template>
<script setup>
import {ref} from "vue";
let list = ref([
{
id:1001,
name:Tony,
age:24
},
{
id:1002,
name:Sandy,
age:24
}
])
</script>
八、传送(Teleport)
1、Teleport的使用
通过类传送:
<!--父级-->
<div class='main'>
这是类
</div>
<A></A>
<script setup>
import A from '../url.vue'
</script>
<!--子级-->
<teleport to='.main'></teleport>
通过id传送:
<!--父级-->
<div id='main'>
这是id
</div>
<A></A>
<script setup>
import A from '../url.vue'
</script>
<!--子级-->
<teleport to='#main'></teleport>
通过组件传送:
<!--父级-->
<div id='main'>
这是id
</div>
<div class='main'>
这是类
</div>
<A></A>
<script setup>
import A from '../url.vue'
</script>
<!--子级-->
<teleport to='body'></teleport> <!--传送至body信息显示完全后-->
注意!!!teleport传送目标必须在传送命令之前,即传送命令执行时,目标dom已存在,否则不进行传送。
2、使用场景
常见的情景是创建一个包含全屏模式的组件,在大多数情况下,你希望模态框的逻辑存在于组件中,但是模态框的快速定位就很难通过CSS来解决,或者需要更改组件组合。
九、动态组件
通过点击切换页面
<template>
<ul>
<li
v-for='(data,key) in tabList'
:key="key"
@click="changevalue(key)"
>
id: {{ data.id }} 姓名:{{ data.name }}
</li>
</ul>
<component :is="begin.key"></component>
</template>
<script setup>
import A from './A.vue'
import B from './B.vue'
import C from './C.vue'
import {markRaw, reactive} from "vue";
const tabList =reactive([
{key:markRaw(A),id:10010,name:'Tony'}, // markRaw 用于提高响应
{key:markRaw(B),id:10011,name:'Sandy'},
{key:markRaw(C),id:10012,name:'John'},
]);
const begin = reactive({ // 设置默认,当前设置默认为A
key:A
});
const changevalue = (key) => { // 设置鼠标点击事件
begin.key = tabList[key].key
}
</script>
<!--./A.vue-->
<template>
这是A页面
</template>
<!--./B.vue-->
<template>
这是B页面
</template>
<!--./C.vue-->
<template>
这是C页面
</template>
十、异步组件
异步组件用于提升性能,当下滑滑到目标组件区域时,组件再进行显示。
参考链接:异步组件:https://cn.vuejs.org/guide/components/async.html
vueuse:https://vueuse.org/core/useintersectionobserver
vueuse库安装命令:
npm i @vueuse/core -S
异步组件案例一,简单异步显示:
<!--主页面-->
<template>
<A></A>
<B></B>
<div ref='target'>
<C v-if="targetIsVisible"></C>
</div>
</template>
<script setup>
import A from './A.vue'
import B from './B.vue'
import { useIntersectionObserver } from '@vueuse/core'
// 若useIntersectionObserver在下载vueuse后还无法使用(No documentation found),就将@vueuse/core的路径写全
import {defineAsyncComponent, ref} from "vue"; // defineAsyncComponent设定异步组件,当下滑滑到组件区域组件再显示
const C = defineAsyncComponent(()=>
import('./C.vue')
)
const target = ref(null);
const targetIsVisible = ref(false);
const { stop } = useIntersectionObserver(
target,
([{ isIntersecting }]) => {
if ( isIntersecting ){ // 一定要if语句判断,否则你的组件C会鬼畜
targetIsVisible.value = isIntersecting
}
},
)
</script>
<!--A、B、C样本界面-->
<template>
<div style="width: 100%;height: 700px;background-color: #646cff">
A model Hello world
</div>
</template>
<script>
export default {
name: "A"
}
</script>
异步组件案例二,接口数据引用:
<!--主页面-->
<template>
<Suspense>
<template #default> <!--加载成功-->
<A></A>
</template>
<template #fallback> <!--加载失败-->
加载中...
</template>
</Suspense>
</template>
<script setup>
import A from './A.vue'
import {ref} from "vue";
</script>
Suspense方法使用参考连接:https://cn.vuejs.org/guide/built-ins/suspense.html
<!--A页面-->
<template>
<div>
<h1>A model</h1>
{{ list }}
</div>
</template>
<script setup>
import {ref} from "vue";
import axios from 'axios';
let list = ref([]);
let res = await axios.get('目标接口数据的URL'); //用于发送请求
list.value = res.data.data.list
</script>
axios安装命令:
npm install axios -S
十一、Mixin
作用:用来分发Vue组件中的可复用功能
例1:
// Mixin.js文件
import {ref} from "vue";
export default function (){
let num = ref(1);
let fav = ref(false); // 加一个判断
let favBtn = ()=>{ // 添加点击事件
num.value += 1; // 点击一下num+1
fav.value =true; // 判断改为true
setTimeout(()=>{ // 点击完成后,过两秒改为false
fav.value = false;
},2000)
}
return{
num,
fav,
favBtn
}
}
想要复用的A、B界面:
<!--A.vue-->
<template>
<div>
<h1>A model</h1>
收藏数: {{ num }}
<button @click="favBtn">
{{ fav ? '收藏中...' : '收藏'}}
</button>
</div>
</template>
<script setup>
import Mixin from "./Mixin.js";
const { num , fav , favBtn } = Mixin();
console.log(Mixin());
</script>
<!--B.vue-->
<template>
<div>
<h1>B model</h1>
收藏数: {{ num }}
<button @click="favBtn">
{{ fav ? '收藏中...' : '收藏'}}
</button>
</div>
</template>
<script setup>
import Mixin from "./Mixin.js";
const { num , fav , favBtn } = Mixin();
console.log(Mixin());
</script>
主页面:
<!--主页面-->
<template>
<A></A>
<B></B>
</template>
<script setup>
import A from './A.vue'
import B from './B.vue'
</script>
效果图:
十二、Provide / Inject (依赖注入)
<!--数据提供-->
<!--主页面-->
<template>
<A></A>
</template>
<script setup>
import A from './A.vue'
import {provide, ref} from "vue";
const num = ref(100);
provide('changeNum',num); // 数据提供,changeNum为接收名,num为提供数据内容
</script>
<!--子级注入 ——A.vue -->
<template>
{{ aNum }}
<hr />
<B></B>
</template>
<script setup>
import { inject } from "vue";
import B from './B.vue'
const aNum = inject('changeNum') // 数据接收
</script>
<!--孙级注入 ——B.vue-->
<template>
{{ bNum }}
<button @click='btn'>click</button>
</template>
<script setup>
import {inject} from "vue";
const bNum = inject('changeNum'); // 数据接收
const btn = () => { // 对接收数据进行操作
bNum.value++;
}
</script>
十三、Vuex
// stores中index.js文件
import { createStore } from 'vuex';
export default createStore({
state:{
num:10, // 例
str:'The data that we need to have', // 例
}, // vuex的基本数据,用来存储相关变量
getters:{}, // 与state结合使用,相当于是state的计算属性
mutations:{},// 提交更新数据的方法,必须是同步的(如果需要异步使用actions)。每个mutations都有一个字符串的事件类型(type)和一个回调函数(handler)。回调函数就是我们实际进行状态更改的地方,并且它会接受 state作为第一个参数,提交载荷作为第二个参数。
actions:{}, // 和mutations的功能大致相同
modules:{}, // 模块化vuex,可以让每一个模块拥有自己的 state、mutation、action、 getters,使得结构非常清晰,方便管理。
});
Vue2与Vue3的区别参考网址:https://github.com/vuejs/rfcs/pull/271
十四、Pinia
Pinia同Vuex一样同为vue中的状态管理
Pinia的特点:
1、支持选项式api和组合式api写法
2、Pinia没有mutations,只有state、getters、actions
3、Pinia分块不需要modules
4、自动化代码拆分
5、支持TS写法
6、Pinia性能更好
7、可以直接修改state数据
Pinia的使用:
Pinia安装指令:
主页面配置(main.ts):
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router'
import {createPinia} from "pinia";
createApp(App).use(createPinia()).use(router).mount('#app')
1、state的使用
router配置:
import { defineStore } from 'pinia';
export const useStore = defineStore('storeId',{
state:()=>{
return {
key:0,
name:'Tony',
age:24,
gender:'boy'
}
},
getters:{
},
actions:{
}
})
Pinia中方法state的使用:
<!--显示-->
<template>
{{ name }}
{{ age }}
</template>
<script setup>
import { useStore } from "../stores";
const store = useStore();
let { name ,age } = store;
</script>
<!--修改1-->
<template>
{{ name }}
{{ age }}
<button @click="changeName">修改名称</button>
</template>
<script setup>
import {storeToRefs} from 'pinia'
import { useStore } from "../stores";
const store = useStore();
let { name ,age } = storeToRefs(store);
const changeName = () => {
name.value = 'John';
}
</script>
<!--修改2-->
<template>
{{ name }}
{{ age }}
<button @click="changeName">修改名称</button>
</template>
<script setup>
import {storeToRefs} from 'pinia'
import { useStore } from "../stores";
const store = useStore();
let { name ,age } = storeToRefs(store);
const changeName = () => {
store.$patch(state=>{
state.name = 'John';
state.age = 23;
})
}
</script>
2、getters的使用
router配置:
import { defineStore } from 'pinia';
export const useStore = defineStore('storeId',{
state:()=>{
return {
key:0,
name:'Tony',
age:24,
gender:'boy'
}
},
getters:{
changeAge(){
return this.age + 1;
}
},
actions:{
}
})
<!--显示-->
<template>
{{ name }}
{{ age }}
<button @click="changeName">修改名称</button>
{{ changeAge }}
</template>
<script setup>
import {storeToRefs} from 'pinia'
import { useStore } from "../stores";
const store = useStore();
let { name ,age ,changeAge } = storeToRefs(store);
const changeName = () => {
store.$patch(state=>{
state.name = 'John';
state.age = 23;
})
}
</script>
3、actions的使用
router配置:
import { defineStore } from 'pinia';
export const useStore = defineStore('storeId',{
state:()=>{
return {
key:0,
name:'Tony',
age:24,
gender:'boy'
}
},
getters:{
changeAge(){
return this.age + 1;
}
},
actions:{ // 用于写方法
upAge(val){
this.age += val;
}
}
})
<!--显示-->
<template>
{{ name }}
{{ age }}
<button @click="changeName">修改名称</button>
<button @click="changebtn">年龄增加</button>
{{ changeAge }}
</template>
<script setup>
import {storeToRefs} from 'pinia'
import { useStore } from "../stores";
const store = useStore();
let { name ,age ,changeAge } = storeToRefs(store);
const changeName = () => {
store.$patch(state=>{
state.name = 'John';
state.age = 23;
})
}
const changebtn = ()=>{
store.upAge( 200 ); // 年龄上+200
}
</script>
4、分模块
例:
<!--主页面-->
<template>
</template>
<script setup>
import { user } from "../stores/user";
import { shop } from "../stores/shop";
const userStore = user();
const userShop = shop();
</script>
// user.js
import {defineStore} from "pinia";
export const user =defineStore('user',{
state:()=>{
return{
key:0,
name:'Tony',
age:24,
gender:'boy'
}
},
getters:{
},
actions:{
}
})
// shop.js
import {defineStore} from "pinia";
export const shop =defineStore('shop',{
state:()=>{
return{
shopList:['显卡','固态','内存条']
}
},
getters:{
},
actions:{
}
})
5、Pinia持久化存储
下载插件:
npm i pinia-plugin-persist --save
插件引入:
import {createPinia} from 'pinia';
// 引入Pinia的持久化存储插件
import piniaPluginPersist from 'pinia-plugin-persist'
const store = createPinia()
// 使用插件
store.use(piniaPluginPersist)
export default store
main.ts配置
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router'
import store from './stores'
createApp(App).use(store).use(router).mount('#app')
十五、设置代理解决跨域问题
1、设置代理
// vite.config.ts 文件
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/dist/vite'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
AutoImport({
imports:['vue','vue-router']
})
],
server:{
proxy:{
'/api':'https://blog.csdn.net/qq_39753433?spm=1011.2266.3001.5343(目标链接)'
}
}
})
2、axios二次封装
import axios from "axios";
// 创建axios对象
const service = axios.create();
// 请求拦截器
service.interceptors.request.use(config =>{
return config;
},error => {
Promise.reject(error);
});
// 响应拦截器
service.interceptors.response.use(response =>{
// 判断code码
return response.data;
},error => {
return Promise.reject(error);
});
export default service;
3、解耦合
import request from "../utils/request";
export function getSliders( ){ // 解耦合
return request({
url:'/api/slider/getSliders'
})
}
4、使用
<template>
</template>
<script setup>
import {getSliders} from "../api/slider.js";
import {onBeforeMount} from "vue"; // 选择生命周期
onBeforeMount(()=>{
getSliders().then(res=>{
console.log( res );
})
})
</script>
如果能解决您的问题,记得收藏+关注呀!!!
创作时间:2022.9.7
文章编号YU.NO.6