1. 创建vite项目
cmd打开终端
npm init vite
输入项目名
选择vue框架
选择使用js
2. 打开项目文件 配置路由
npm i 初始化项目
npm install vue-router 安装路由
新建router文件 创建index.js
内容:
import {createRouter,createWebHashHistory} from "vue-router";
const routes = [
{
path: "/",
redirect: "/login",
},
{
path: "/login",
name: "login",
component: () => import("../views/login.vue"),
},
]
const router = createRouter({
history: createWebHashHistory(),
routes,
});
export default router;
main.js中引入router createvue后面加上use(router)
在app.vue页面加上router-view 显示路由界面
3. 配置页面
创建views文件夹存放页面
创建路由中的vue页面
4. vite.config.js配置文件的基本设置:
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import { resolve } from "path";
// 引入自动导入import的插件
import AutoImport from "unplugin-auto-import/vite";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
AutoImport({
imports: ["vue", "vue-router"],
}),
],
// 配置代理解决跨域问题
server: {
proxy: {
"/api": {
target: "https://test.ktyfz.com/",
changeOrigin: true,
// rewrite: (path) => path.replace(/^\/api/, ''),
},
},
// host: 'localhost', //设置域名
host: "0.0.0.0",
// open: true, //设置自动打开
port: 8090, //端口
hmr: true, //开启热更新
},
build: {},
// 配置别名 @
resolve: {
alias: {
"@": resolve(__dirname, "src"),
},
},
});
vue3学习:
响应式数据:
reactive:
import { reactive } from 'vue'
const state = reactive({ count: 0 })
reactive()
的局限性:
1.仅对对象类型有效(对象、数组和 Map
、Set
这样的集合类型),而对 string
、number
和 boolean
这样的 原始类型 无效
2.
ref: 定义响应式简单数据类型使用ref 在使用时需要.value进行使用、
watch
监听单个数据:
watch(str, (newvalue, oldvalue) => {
console.log(newvalue, oldvalue);
})
监听多个数据:
watch([str1, str2], (newvalueArr, oldvalueArr) => {
console.log(newvalueArr, oldvalueArr);
//newvalueArr为新值的数组 第一项为str1 第二项为str2
//oldvalueArr为旧值的数组 第一项为str1 第二项为str2
})
监听对象中的某个key的值的变化:
// 监听 obj中key属性的值
watch(() => obj.key, (newvalue, oldvalue) => {
console.log(newvalue, oldvalue);
})
//obj.key也可写成obj['key']
当需要立即监听和深度监听时 :
watch(() => obj['key'], (newvalue, oldvalue) => {
console.log(newvalue, oldvalue);
}, {
immediate: true,
deep:true
//当obj.key(obj['key'])的值为一个对象时 需要用到深度监听
})
动态组件:
使用<compontent :is='组件名'> 控制显示的组件 可使用KeepAlive内置组件进行缓存
(组件要引入)
异步组件:
使用场景1:
例如:页面包含A、B、C三个组件 ,当用户没下拉访问到C组件时 ,就不加载C组件,达到优化性能的效果
1.异步引入组件
import { defineAsyncComponent } from 'vue'
const AsyncComp = defineAsyncComponent(() =>
import('./components/MyComponent.vue')
)
虽然异步引入了组件 但是C组件也进行了加载 需要安装个插件 进行观察
1.需要安装@vueuse/core插件
参考连接:https://vueuse.org/core/useIntersectionObserver/#demo
并在父组件中引入
import {useIntersectionObserver} from ‘@vueuse/core’
<template>
<div>
<A></A>
<B></B>
<!-- 注意加上ref= 'target'-->
<div ref="target">
<C v-if="targetIsVisible"></C>
</div>
</div>
</template>
<script setup>
import { defineAsyncComponent, ref } from 'vue';
//1、 引入A B C组件 其中C使用异步加载
import A from '@/components/A.vue'
import B from '@/components/B.vue'
const C = defineAsyncComponent(() =>
import('@/components/C.vue')
)
// 引入观察器 (@vueuse/core中)
import { useIntersectionObserver } from '@vueuse/core'
const target = ref(null)
//C组件的加载条件默认为false
const targetIsVisible = ref(false)
// 侦听 滑动到C组件时 isIntersecting会变成true
const { stop } = useIntersectionObserver(
target,
([{ isIntersecting }]) => {
// 判断 当isIntersecting变为true时 将C组件的加载条件设置为true
if (isIntersecting) {
targetIsVisible.value = isIntersecting
}
},
)
</script>
<style lang = 'less' scoped></style>
以上就实现了 当下滑到C组件时才开始加载C组件的内容
使用场景2:分包 run build时 异步组件会单独打包js文件(从主体js文件中分出来的) 仅在页面需要它渲染时才会调用加载内部实际组件的函数
搭配 Suspense 内置组件 使用
<Suspense>
组件有两个插槽:#default
和 #fallback
。两个插槽都只允许一个直接子节点。在可能的时候都将显示默认槽中的节点。否则将显示后备槽中的节点。
<Suspense>
<!-- 具有深层异步依赖的组件 -->
<component />
<!-- 在 #fallback 插槽中显示 “正在加载中” -->
<template #fallback>
加载中...
</template>
</Suspense>
示例:
A中使用awiat操作发送axios请求 可将A组件写成异步加载组件 搭配Suspense内置组件使用 在响应数据回来之前显示 #fallback插槽的加载状态
A组件:
<template>
<div class="A_page">
{{ list }}
</div>
</template>
<script setup>
import axios from 'axios';
import { reactive, ref } from 'vue';
const list = ref([])
// setup上 已经有async 所以内部可直接使用await
let res = await axios.get('http://xxxxxx/api/xxx/xxx')
list.value = res.data.data
</script>
<style lang = 'less' scoped>
.A_page {
height: 60vh;
background-color: pink;
}
</style>
父组件:
<template>
<div>
<!--A中使用awiat操作发送axios请求 可将A组件写成异步加载组件 搭配Suspense内置组件使用 在响应数据回来之前显示 #fallback插槽的加载状态 -->
<Suspense>
<template #default>
<!-- 具有深层异步依赖的组件 -->
<A></A>
</template>
<!-- 在 #fallback 插槽中显示 “正在加载中” -->
<template #fallback>
加载中...
</template>
</Suspense>
<B></B>
<!-- 注意加上ref= 'target'-->
<div ref="target">
<C v-if="targetIsVisible"></C>
</div>
</div>
</template>
<script setup>
import { defineAsyncComponent, ref } from 'vue';
//1、 引入A B C组件 其中A、C使用异步加载
const A = defineAsyncComponent(() =>
import('@/components/A.vue')
)
import B from '@/components/B.vue'
const C = defineAsyncComponent(() =>
import('@/components/C.vue')
)
// 引入观察器 (@vueuse/core中)
import { useIntersectionObserver } from '@vueuse/core'
const target = ref(null)
//C组件的加载条件默认为false
const targetIsVisible = ref(false)
// 侦听 滑动到C组件时 isIntersecting会变成true
const { stop } = useIntersectionObserver(
target,
([{ isIntersecting }]) => {
// 判断 当isIntersecting变为true时 将C组件的加载条件设置为true
if (isIntersecting) {
targetIsVisible.value = isIntersecting
}
},
)
</script>
<style lang = 'less' scoped></style>
当需要C异步组件使用await并在加载时也加上加载状态的 可以将vueuse中的观察器与Suspense结合使用
<!-- 异步组件搭配vueues中的观察器一起使用 -->
<!-- 异步组件使用 Suspense内置组件包裹-->
<div ref="target">
<Suspense v-if="targetIsVisible">
<template #default>
<!-- 具有深层异步依赖的组件 -->
<C></C>
</template>
<!-- 在 #fallback 插槽中显示 “正在加载中” -->
<template #fallback>
加载中...
</template>
</Suspense>
</div>
Mixins 混入:
一个包含组件选项对象的数组,这些选项都将被混入到当前组件的实例中 组件引入后不相互共享
示例:
src下新建mixin/mixin.js
import { ref } from "vue";
export default function () {
let num = ref(1);
let fav = ref(false);
let changeNum = () => {
num.value++;
fav.value = !fav.value;
};
return {
num,
fav,
changeNum,
};
}
使用:
A组件中引入并使用:
<template>
<div class="A_page">
<button @click="changeNum">按钮</button>
{{ num }}---{{ fav }}
</div>
</template>
<script setup>
import axios from 'axios';
import { reactive, ref } from 'vue';
import mixin from '@/mixins/mixins.js'//引入mixin
let { num, fav, changeNum } = mixin()//解构
</script>
当B组件也引入使用mixin时 其中使用的变量或方法不会互通
当mixin中有生命周期组件中也有生命周期时 会先执行mixin中的生命周期 再执行组件的生命周期
组件通讯 (<script setup>语法糖中的写法):
子传父:
父组件:
<A :msg="msg"></A>
子组件接收:
const props = defineProps({
msg: {
type: String,
default: '默认值'
}
})
// 接收后可以进行解构 然后直接使用 不需要props.msg
let { msg } = props
子传父:
子组件:使用defineEmits 可以传入多个
const sonStr = ref('我是子组件的str')
const emit = defineEmits(['fn1', 'fn2'])
const clickHandler = () => {
emit('fn1', sonStr.value)
}
const clickHandler2 = () => [
emit('fn2')
]
父组件中:
<A :msg="msg" @fn1="fatherFn" @fn2="fatherFn2"></A>
// 子传父后需要触发的事件1 接收参数
let fatherFn = (str) => {
console.log('父组件接收到的str', str);
}
// 子传父需要触发的事件2
let fatherFn2 = () => {
console.log('触发的事件2');
}
v-model双向传值:
父组件:
<A v-model:msg="msg"></A>
const msg=ref('我是父组件的msg')
子组件:
// 1.接收父组件传过来的数据
const props = defineProps({
msg: {
type: String,
default: '默认值'
}
})
// 使用 defineEmits 要在子组件修改msg update:msg update为固定写法 写成其他的无效
const emit = defineEmits(['update:msg'])
const sonChangeFn = () => {
emit('update:msg', '子组件修改了msg')
}
兄弟组件之间传值:
此处为使用插件形式的示例:
1.下载安装 mitt 插件
npm install mitt -S
新建一个utils/Bus.js
import mitt from 'mitt'
const busEmitter =mitt() //调用一下mitt
export default busEmitter;
兄弟组件 A---B
A组件中:
import busEmitter from '@/utils/Bus.js'
const msg=ref('我是A组件的msg')
busEmitter.emit('fn',msg)
B组件中接收:
import busEmitter from '@/utils/Bus.js'
onBeforeMount(() => {
busEmitter.on('fn', e => {
console.log(e.value);
})
})
爷孙组件传值 : provide+inject 依赖注入
父组件:
import {provide} from 'vue'
const msg = ref('我是父组件上的msg');
provide('sendMsg',msg)//
子组件:
import {inject} from 'vue'
const myMsg=inject('sendMsg')
console.log(myMsg)
注入方可以修改提供方提供的数据
如果你想确保提供的数据不能被注入方的组件更改,你可以使用 readonly() 来包装提供的值。
import { ref, provide, readonly } from 'vue'
const count = ref(0)
provide('read-only-count', readonly(count))
Vuex:
1.安装vuex
npm install vuex
2.新建/store/inde.js
import { createStore } from "vuex";
export default createStore({
state: {
num: 1,
},
getters: {},
mutations: {
change(state) {
state.num += 1;
},
},
actions: {
changeNumAsync(content) {
setTimrout(() => {
content.state.num += 2;
}, 1000);
},
},
modules: {},
});
在组件中使用:
pinia使用:
1.pinia没有mutations,只有state、getters、action,
2.pinia分模块不需要modules
3.pinia支持直接修改state的数据 不经过action
1.安装pinia
npm install pinia
2.在main.js中引入使用
import { createPinia } from "pinia"; //引入pinia
createApp(App).use(router).use(ElementPlus).use(createPinia()).mount("#app");
3.store/index.js中
import { defineStore } from "pinia";
export const useStore = defineStore("storeId", {
state: () => {
return {
number1: 10,
storeName: "Eduardo",
isAdmin: true,
};
},
getters: {},
// Action 相当于组件中的 method action 也可通过 this 访问整个 store 实例
actions: {
changehandler() {
this.number1++;
},
},
});
4.组件中使用:
import { useStore } from '@/store/index'
const store = useStore();
const { number1 } = store.number1;//结构使用store中的数据
//clickHandler为组件中的点击事件
const clickHandler = () => {
store.changehandler()//直接调用pinia中 action中的方法
}
5.组件中直接修改store中的数据:
结构出来的数据需要使用storeToRefs转为proxy
import { useStore } from '@/store/index'
import { storeToRefs } from 'pinia'
const store = useStore();
const { number1 } = storeToRefs(store);//解构使用store中的数据
console.log(store, 66666);
const clickHandler3 = () => {
// 直接修改store中的数据 注意:解构出来要使用storeToRefs转为响应式
number1.value += 5
}
批量修改:
const batchChange = () => {
//批量更新
store.$patch(state=>{
state.number1++;
state.isAdmin=false;
state.storeName = '你好世界';
})
}
pinia分模块 使用不同的js文件即可 user.js 、cart.js....
pinia持久化:插件形式
1.安装插件
npm i pinia-plugin-persist --save
2.store/index.js
import { createPinia } from 'pinia'
import piniaPluginPersist from 'pinia-plugin-persist'
const store = createPinia()
store.use(piniaPluginPersist)
export default store
3.main.js中修改
store import store from './store'
createApp(App).use(router).use(ElementPlus).use(store).mount("#app");
4.在对应模块中开启数据存储
store/user.js
import {defineStore} from ''pinia
export const useUserStore = defineStore({
id: 'user',
state: () => {
return {
name: '张三'
}
},
// 开启数据缓存
persist: {
enabled: true
}
})
自定义key:
persist: {
enabled: true, //开启数据持久化
strategies: [
{
key: 'my_user', //存储时的key命名
storage: localStorage, //默认存在sessionstorage中 可改为localStorage
}
]
}
持久化局部 state
默认所有 state 都会进行缓存,你能够通过 paths 指定要长久化的字段,其余的则不会进行长久化。
persist: {
enabled: true,
strategies: [
{
storage: localStorage,
paths: ['name', 'age'] //要执行持久化的数据变量
}
]