vue3 - 图灵
目录
- vue3简介
- 整体上认识vue3项目
- 创建Vue3工程
- 使用官方脚手架创建Vue工程[推荐]
- 主要⼯程结构
- 数据双向绑定
- vue2语法的双向绑定
- 简单表单双向绑定
- 复杂表单双向绑定
- CompositionAPI替代OptionsAPI
- CompositionAPI简单不带双向绑定写法
- CompositionAPI简单带双向绑定写法
- setup简写⽅式
- 脚本单独写到ts⽂件中
- Vue3中的数据双向绑定
- ref定义基础类型响应式数据
- reactive定义对象型响应式数据
- ref也可以定义对象型响应式数据(不推荐)
- 通过toRef或toRefs函数将转出来的数据具备响应式能力
- 标签的ref属性/ref绑定标签
- 通过ref将当前DOM元素绑定给响应式变量
- 父组件拿到自定义组件里的值
- 子组件接收父组件传来的数据
- VUE3⽣命周期
- Vue-Router组件路由机制
- 基础使⽤
- 路由⼯作模式
- replace
- 嵌套路由
- 路由传参
- query传参
- params传参
- Pinia集中式状态存储
- 理解状态
- 创建store
- 使⽤store操作数据
- storeToRefs声明响应式数据
- store的混合式写法
- 快速上⼿Element-Plus
vue3快速上手指南
你只要会基础的HTML,JS,CSS,那么就可以上手Vue了。如果你会Java,那么上手Vue非常轻松。如果你会Vue2,那么上手Vue3会更加舒服。
vue3简介
官网地址:https://vuejs.org/。中文官网 https://cn.vuejs.org/
Vue是什么?易学易用,性能出色,适用场景丰富的 Web 前端框架。
Vue2已经于2023年12月31日停止维护。建议升级到Vue.js3.0版本。打包更小,内存更少,渲染更快。好消息是,vue3向下兼容vue2的语法
Vue3于2020年9月18日发布,代号:One Piece 海贼王。久经磨砺
Vue3新特性:组合式API(重点),更好的支持TypeScript(熟悉),状态存储框架Pinia(重点),新组件(了解)。。。。。详见官网
整体上认识vue3项目
创建Vue3工程
前置:安装NodeJS。NodeJS版本最好在18.0以上。下载地址:https://nodejs.org/en
ps:lts:长期支持的版本
vite简介:类似于maven可以打包
1、所有功能组件都可以后续手动添加。
关于TypeScript,在Vue中的TypeScript可以认为是在JS的基础上,增加面向对象的能力。可以定义接口、类、抽象类等。
2、 npm install过程中会去node仓库下载很多依赖库,放到项目本地node-modules目录。建议将npm源设定为淘宝提供的国内镜像,可以下载快一点。
npm config get registry https://registry.npmmirror.com
使用官方脚手架创建Vue工程[推荐]
找一个空的文件夹
D:\WorkspaceOfIdea\vue3>npm create vue@latest
Need to install the following packages:
create-vue@3.10.3
Ok to proceed? (y) yVue.js - The Progressive JavaScript Framework√ 请输入项目名称: ... vue-project
√ 是否使用 TypeScript 语法? ... 否 / 是√
√ 是否启用 JSX 支持? ... 否√ / 是
√ 是否引入 Vue Router 进行单页面应用开发? ... 否√ / 是
√ 是否引入 Pinia 用于状态管理? ... 否√ / 是
√ 是否引入 Vitest 用于单元测试? ... 否√ / 是
√ 是否要引入一款端到端(End to End)测试工具? » 不需要
√ 是否引入 ESLint 用于代码质量检测? ... 否 / 是√
√ 是否引入 Prettier 用于代码格式化? ... 否√ / 是
√ 是否引入 Vue DevTools 7 扩展用于调试? (试验阶段) ... 否√ / 是正在初始化项目 D:\WorkspaceOfIdea\vue3\vue-project...项目初始化完成,可执行以下命令:cd vue-projectnpm installnpm run devD:\WorkspaceOfIdea\vue3>cd vue-projectD:\WorkspaceOfIdea\vue3\vue-project>npm installD:\WorkspaceOfIdea\vue3\vue-project>npm run dev> vue-project@0.0.0 dev
> viteVITE v5.2.11 ready in 702 ms➜ Local: http://localhost:5173/➜ Network: use --host to expose➜ press h + enter to show help
浏览器访问:http://localhost:5173/
主要⼯程结构
ps:官⽅建议开发IDE: vscode。提供了辅助开发插件 vue-official。 在这之前有个插件叫volar,现在已经停⽤
主要代码结构如下图


典型的Vue项⽬,都是在index.html这⼀个单⻚⾯⾥形成各种交互,这也就是所谓的SPA(Single Page
Application)Vue3的核⼼是通过createApp函数创建⼀个应⽤实例,在这个实例中构建各种应⽤。(main.ts中)每个vue⽂件就是⼀个⻚⾯上的组件,组件可以嵌套使⽤。vue中的组件分为<template>⻚⾯模板,<script>脚本和<style>样式三个部分。Vue2中要求<template>下必
须有⼀个唯⼀的根元素,Vue3中则没有了这个限制。
数据双向绑定
双向绑定是Vue最为核⼼的功能。简单理解就是<template>中的⻚⾯数据和<script>中的脚本数据进⾏绑定,其
中任何⼀个数据发⽣了变化,另⼀个数据也随之发⽣变化。
vue2语法的双向绑定
简单表单双向绑定
App.vue
<template><div>姓名:<input v-model="userName" /> {{ userName }} <br />薪⽔:<input type="number" v-model="salary" /> {{ salary }} <br /><button @click="addSalary">提交</button></div>
</template>
<script lang="ts">
export default {//数据data() {return {userName: "王⼀",salary: 15000}},//⽅法methods: {addSalary() {this.salary += 1000}}}
</script>
<style scoped>
</style>
复杂表单双向绑定
数据双向绑定可以说是整个Vue的核⼼。例如,我们可以⽤数据双向绑定实现⼀些更为复杂的表单。
App.vue
<template><div>姓名:<input v-model="userName" /> {{ userName }} <br />薪⽔:<input type="number" v-model="salary" /> {{ salary }} <br /><button @click="addSalary">提交</button> <button @click="changeShowUserInfo">查看个⼈信息</button><hr /><div class="userInfo" v-show="showUserInfo"><h2>个⼈信息</h2><p>年龄:<input type="number" v-model="userInfo.age" /></p><p>性别:<input type="radio" value="1" v-model="userInfo.sex">男<input type="radio" value="2" v-model="userInfo.sex">⼥</p><p>岗位:<select v-model="userInfo.department"><option value="dev">开发</option><option value="test">测试</option><option value="maintain">运维</option></select></p><p>技术: <span v-for="skill in userInfo.skills" :key="skill">{{ skill }}</span></p><p>新技术: <input v-model="newSkill" /> <button @click="learnNewSkill">学习新技术</button></p><p>个⼈信息汇总:{{ userInfo }}</p></div></div></template><script lang="ts">
export default {data() {return {userName: 'roy',salary: 15000,userInfo: {age: 0,sex: 1,skills: ['java', 'vue', 'python'],department: ''},newSkill: '',showUserInfo: false}},methods: {addSalary() {this.salary += 1000},learnNewSkill() {if (this.newSkill)this.userInfo.skills.push(this.newSkill)},changeShowUserInfo() {this.showUserInfo = !this.showUserInfo}}
}
</script><style scoped>
.userInfo {background-color: bisque;width: 80%;
}.userInfo span {background-color: yellow;margin-left: 10px;border: 1px;border-radius: 5px;
}
</style>

CompositionAPI替代OptionsAPI
Vue2中常⽤的这种编写⽅式称为OptionsAPI,配置式。其实现⽅式是⽤⼀个统⼀的配置对象来实现全部代码逻辑。在这个对象中,通过data、methods、computed等配置选项来控制逻辑。
OptionsAPI是Vue2时的标准API编写⽅式。Vue3向下兼容了Vue2的API。因此,Vue2的⽼项⽬,在Vue3中基本可以⽆缝迁移。 实际上,OptionsAPI是在CompositionAPI的基础上实现的。关于Vue的基础概念和知识,在这两种API之间是通⽤的 。另外,官⽅建议,如果采⽤Vue构建完整的SPA应⽤,那么更建议使⽤CompositionAPI。
但是,OptionsAPI所有逻辑都混在⼀起,不便于维护和复⽤。 Vue3另外通过了⼀种更⽅便的API,Composition API,混合式API。
上⾯同样的示例,⽤Composition API的写法如下:
CompositionAPI简单不带双向绑定写法
<template><div>姓名:<input v-model="userName" /> {{ userName }} <br />薪⽔:<input type="number" v-model="salary" /> {{ salary }} <br /><button @click="addSalary">提交</button></div>
</template><script lang="ts">export default {setup() {//现在声明的变量还不具备双向绑定let userName = "王⼀"let salary = 15000function addSalary() {salary += 1000console.log("salary = " + salary)}//模板要⽤哪些,就返回哪些return { userName, salary, addSalary }}}
</script><style scoped>
</style>
1、setup是Vue3中的⼀个⽣命周期函数,他会在组件加载时执⾏。后⾯会细讲⽣命周期。
2、setup可以返回对象或者函数。如果是⼀个对象,则对象中的属性、⽅法等,可以在模板中直接使⽤(常
⽤)。如果返回⼀个函数,则通过函数的返回值直接渲染⻚⾯,不经过模板。例如 setup(){return ()=>"直
接渲染"}
3、setup是⼀个普通的函数,不能使⽤this。 OptionsAPI中可以通过this访问脚本本身的数据 同时 setup中
不处理this,意味着setup编写可以更灵活,不需要依赖当前⻚⾯上下⽂
4、此时声明的userName, salary等变量不具备双向绑定。Vue3对双向绑定做了重新设计,后⾯会详细分
享。
CompositionAPI简单带双向绑定写法
<template><div>姓名:<input v-model="userName" /> {{ userName }} <br />薪⽔:<input type="number" v-model="salary" /> {{ salary }} <br /><button @click="addSalary">提交</button></div>
</template><script lang="ts">
import { ref } from 'vue';export default {setup() {//现在声明的变量具备了双向绑定let userName = ref("王⼀")let salary = ref(15000)function addSalary() {salary.value += 1000console.log("salary = " + salary)}//模板要⽤哪些,就返回哪些return { userName, salary, addSalary }}}
</script><style scoped>
</style>
setup简写⽅式
5、setup有⼀种简写的⽅式<script setup lang="ts">。这样就不需要写函数了,标签内部直接写函数体。在
标签内部声明的对象,函数等,都会直接return出去。 项⽬中常⽤
<template><div>姓名:<input v-model="userName" /> {{ userName }} <br />薪⽔:<input type="number" v-model="salary" /> {{ salary }} <br /><button @click="addSalary">提交</button></div>
</template><script setup lang="ts">
import { ref } from 'vue';let userName = ref("王⼀")let salary = ref(15000)function addSalary() {salary.value += 1000console.log("salary = " + salary)}
</script><style scoped>
</style>
在CompositionAPI中,由于setup是⼀个不同的函数,不需要处理this。这也意味着setup函数编写可以更加灵活,不需要依赖当前⻚⾯上下⽂。例如:将示例中的脚本单独写到⼀个ts⽂件中。
脚本单独写到ts⽂件中
component文件夹下新建MySalary.ts
import { onMounted, ref } from "vue"
export default function () {//之前声明的变量还不具备双向绑定。现在添加ref函数才具备了响应式const userName = ref("王⼀")const salary = ref(15000)function addSalary() {salary.value += 1000console.log("salary = " + salary.value)}onMounted(() => {console.log("加载了外部脚本")});return { userName, salary, addSalary }
}
然后,在App.vue中就可以直接引⽤脚本
<template><div>姓名:<input v-model="userName" /> {{ userName }} <br />薪⽔:<input type="number" v-model="salary" /> {{ salary }} <br /><button @click="addSalary">提交</button></div>
</template><script setup lang="ts">
import MySalary from './components/MySalary';
let {userName,salary,addSalary} = MySalary()
</script><style scoped>
</style>
如果App.vue的逻辑越来越复杂,通过这种⽅式,就更易于将相关的属性和⽅法整理到⼀起,从⽽实现⼀个特定的业务功能。
1、ref函数让变量具备了双向绑定功能。后⾯详细分析。
2、复杂⻚⾯可以⽤这种⽅式。⼀般情况下,显然是将MySalary的模板和脚本封装到⼀起,这就是⾃定义组
件了。
Vue3中的数据双向绑定
ref包裹后可以在模板中直接使用,在js中要加上.value,因为ref包裹后是一个RefImpl对象
ref先后用不同值包裹两次后,value值改变,但没有和控件建立绑定关系,原来控件上的旧值也失去了响应式能力;改了别的ref后vue会重新扫描所有的ref,控件会和之前的ref重新绑定
ref定义基础类型响应式数据
语法: let userName=ref(初始值)。
返回值:⼀个RefImpl的实例对象,值被包裹在对象的value属性中。
注意点:脚本中要⽤ref对象的value属性访问值,例如userName.value。但是模板中可以直接⽤。ref对象本身不是响应式的,value属性是响应式的。例如js中修改值,要通过userName.value="xxx",⽽不能userName="xxx"。vue-official插件中可以选择⾃动添加value属性。(需要⼿动勾选)
<template><div>姓名:<input v-model="userName" /> {{ userName }} <br />薪⽔:<input type="number" v-model="salary" /> {{ salary }} <br /><button @click="addSalary">提交</button></div>
</template><script setup lang="ts">
import { ref } from 'vue';let userName = ref("王⼀") //基础类型⽤ref声明响应式let salary = ref(15000)function addSalary() {salary.value += 1000 //脚本中操作数据要加.valueconsole.log("salary = " + salary)}
</script><style scoped>
</style>
reactive定义对象型响应式数据
语法: let salaryInfo = reactive({userName:“王⼀”,salary:15000})
返回值:reactive包裹后变成了⼀个Proxy实例对象,具有双向绑定能⼒。
<template><div>姓名:<input v-model="salaryInfo.userName" /> {{ salaryInfo.userName }} <br />薪⽔:<input type="number" v-model="salaryInfo.salary" /> {{ salaryInfo.salary }} <br /><button @click="addSalary">提交</button></div>
</template><script setup lang="ts">
import { reactive } from 'vue';let salaryInfo = reactive({userName:"roy",salary:10000})function addSalary() {salaryInfo.salary += 1000console.log("salary = " + salaryInfo.salary)}
</script><style scoped>
</style>
ref也可以定义对象型响应式数据(不推荐)
ref包裹完对象类型数据后封装成reactive包裹的对象,对象里拆出来的属性不会有双向绑定能力
<template><div>姓名:<input v-model="salaryInfo.userName" /> {{ salaryInfo.userName }} <br />薪⽔:<input type="number" v-model="salaryInfo.salary" /> {{ salaryInfo.salary }} <br /><button @click="addSalary">提交</button></div>
</template><script setup lang="ts">
import { ref } from 'vue';let salaryInfo = ref({userName:"roy",salary:10000})function addSalary() {salaryInfo.value.salary += 1000console.log("salary = " + salaryInfo.value.salary)}
</script><style scoped>
</style>
通过toRef或toRefs函数将转出来的数据具备响应式能力
对象型响应数据,如果将其中的各个属性拆解出来,是不具备响应式的。如果需要响应式属性,可以使⽤toRefs或者toRef函数进⾏转换
将对象的属性换成ref包裹的属性
<template><div>姓名:<input v-model="userName" /> {{ userName }} <br />薪⽔:<input type="number" v-model="salary" /> {{ salary }} <br /><button @click="addSalary">提交</button></div>
</template><script setup lang="ts">
import { reactive, toRef } from 'vue';let salaryInfo = reactive({userName:"roy",salary:10000})// toRef将对象的某个属性转为⼀个响应式数据let userName = toRef(salaryInfo,'userName')let salary = toRef(salaryInfo,'salary')function addSalary() {salaryInfo.salary += 1000console.log(salaryInfo)}
</script><style scoped>
</style>
<template><div>姓名:<input v-model="userName" /> {{ userName }} <br />薪⽔:<input type="number" v-model="salary" /> {{ salary }} <br /><button @click="addSalary">提交</button></div>
</template><script setup lang="ts">
import { reactive, toRef, toRefs } from 'vue';let salaryInfo = reactive({userName:"roy",salary:10000})// toRefs将对象的所有属性⼀起转换成响应式数据let {userName,salary} = toRefs(salaryInfo)function addSalary() {salaryInfo.salary += 1000console.log(salaryInfo)}
</script><style scoped>
</style>
标签的ref属性/ref绑定标签
ref不仅可以通过v-model的形式形成双向绑定,也可以在元素上加上ref
在定义模板时,可以通过ref属性将当前DOM元素绑定给响应式变量。
通过ref将当前DOM元素绑定给响应式变量
<template><div>姓名:<input ref="name" abc="aaaaa" /> <br /><button @click="showRes">提交</button></div>
</template><script setup lang="ts">
import { reactive, toRef, toRefs, ref } from 'vue';let name = ref()function showRes(){console.log(name) //RefImpl ref对象console.log(name.value) //<input> dom元素console.log(name.value.value) //输⼊框的值console.log(name.value.getAttribute("abc")) //⾃定义属性的值}
</script><style scoped>
</style>
父组件拿到自定义组件里的值
如果只是针对普通元素,还体现不出Ref的作⽤。如果配合⾃定义组件,则更能体现Ref属性的作⽤。例如,针对薪⽔信息,可以⾃⼰写⼀个简单组件,把多个输⼊框整合到⼀起。
components下新建MySalaryInfo.vue
<!-- ⾃定义的薪⽔信息输⼊组件 -->
<template>姓名:<input v-model="userName"><br />薪⽔:<input type="number" v-model="salary">
</template><script lang="ts">
//组件名默认是⽂件名。如果不希望⽤⽂件名,也可以⾃定义
export default {name: "SalaryInfo"
}
</script><script setup lang="ts">
import { ref } from 'vue';//响应式数据默认值let userName = ref("unknown")let salary = ref(1000)//子组件对外暴露属性。只有暴露出去,组件外部才能访问defineExpose({ userName, salary })
</script><style></style>
App.vue
<template><MySalaryInfo ref="salaryInfo" /><button @click="showRes">查看薪⽔信息</button> <!--2-->
</template><script setup lang="ts">
import { reactive, toRef, toRefs, ref } from 'vue';
//引⼊⼦组件
import MySalaryInfo from '@/components/MySalaryInfo.vue'; //1
//获取绑定对象
let salaryInfo = ref() //3
function showRes() {console.log(salaryInfo) //RefImpl ref对象 //4console.log(salaryInfo.value) //Proxy ⼦组件的响应式数据console.log(salaryInfo.value.userName) //⼦组件的输⼊框的值console.log(salaryInfo.value.salary) //⼦组件的输⼊框的值
}
</script><style scoped></style>
子组件接收父组件传来的数据
MySalaryInfo.vue
接收值
<!-- ⾃定义的薪⽔信息输⼊组件 -->
<template>姓名:<input v-model="salaryInfo.userName"><br />薪⽔:<input type="number" v-model="salaryInfo.salary"><br />{{ salaryInfo }}
</template><script lang="ts">
//组件名默认是⽂件名。如果不希望⽤⽂件名,也可以⾃定义
export default {name: "SalaryInfo"
}
</script><script setup lang="ts">
defineProps([ //可以接收外面传进来的值"salaryInfo"
])
</script><style>
</style>
App.vue
父组件修改值,然后往子组件传值
<template><div><MySalaryInfo :salary-info="salaryInfo"></MySalaryInfo><button @click="showRes">修改薪⽔</button></div>
</template><script setup lang="ts">
import { reactive, toRef, toRefs, ref } from 'vue';
//引⼊⼦组件
import MySalaryInfo from '@/components/MySalaryInfo.vue';
//获取绑定对象
let salaryInfo = reactive({ userName: 'roy', salary: 10000 })
function showRes() {salaryInfo.salary += 1000
}
</script><style scoped></style>

TypeScript版:
但是上面的salaryInfo传到子组件时子组件并不知道它是什么类型,也不知道它有什么属性,可以引入ts对salaryInfo类型做限制
src下新建types文件夹和salaryInfo.ts
export interface SalaryInfo{userName:string,salary:number
}
子组件引入和定义泛型
MySalaryInfo.vue
<!-- ⾃定义的薪⽔信息输⼊组件 -->
<template>姓名:<input v-model="salaryInfo.userName"><br />薪⽔:<input type="number" v-model="salaryInfo.salary"><br />{{ salaryInfo }}
</template><script lang="ts">
//组件名默认是⽂件名。如果不希望⽤⽂件名,也可以⾃定义
export default {name: "SalaryInfo"
}
</script><script setup lang="ts">
import type { SalaryInfo } from '@/types/salaryInfo';defineProps<{salaryInfo:"SalaryInfo"}>( //接收外面传进来的值
)
</script><style>
</style>
VUE3⽣命周期
每个 Vue 组件实例在创建时都需要经历⼀系列的初始化步骤,⽐如设置好数据侦听,编译模板,挂载实例DOM,以及在数据改变时更新 DOM。在此过程中,它也会运⾏被称为⽣命周期钩⼦的函数,让开发者有机会在特定阶段运⾏⾃⼰的代码。
⽣命周期有四个阶段:创建,挂载,更新,销毁。每个阶段有⼀前⼀后两个函数
OptionsAPI的⽣命周期函数:
创建阶段: beforeCreate 、 created
挂载阶段: beforeMount 、 mounted
更新阶段: beforeUpdate 、 updated
销毁阶段: beforeDestroy 、 destroyed
CompositionAPI的⽣命周期函数:
创建阶段: setup
挂载阶段: onBeforeMount 、 onMounted
更新阶段: onBeforeUpdate 、 onUpdated
卸载阶段: onBeforeUnmount 、 onUnmounted
示例
<template><div>薪⽔:<input type="number" v-model="salary" /> <br /><button @click="addsum">薪⽔+1000</button></div>
</template><!-- vue3写法 -->
<script lang="ts" setup>
import {ref,onBeforeMount,onMounted,onBeforeUpdate,onUpdated,onBeforeUnmount,onUnmounted
} from 'vue'
// 数据
let salary = ref(0)
// ⽅法
function addsum() {salary.value += 1000
}
console.log('setup')
// ⽣命周期钩⼦
onBeforeMount(() => {console.log('挂载之前')
})
onMounted(() => {console.log('挂载完毕')
})
onBeforeUpdate(() => {console.log('更新之前')
})
onUpdated(() => {console.log('更新完毕')
})
onBeforeUnmount(() => {console.log('卸载之前')
})
onUnmounted(() => {console.log('卸载完毕')
})
</script>
Vue-Router组件路由机制
Vue项⽬虽然只有index.html⼀个⻚⾯,但是可以通过多路由机制实现多⻚⾯跳转的效果。访问不同链接,展示不同的⻚⾯内容,形成多⻚⾯的效果。
Vue官⽅提供了Vue-Router组件实现路由管理,官⽹地址:https://router.vuejs.org/zh/ 。该组件可以在创建Vue项⽬时选择引⼊。如果创建时没有安装,也可以⼿动安装。
npm install vue-router@4
vue3要求使⽤router组件最新版本。⽬前最新版本是4
基础使⽤
页面准备
HomePage.vue,AboutPage.vue,NewsPage.vue
<template>首页
</template><script setup lang="ts">
</script><style>
</style>
main.ts
import './assets/main.css'import { createApp } from 'vue'
import App from './App.vue'import { createRouter,createWebHistory } from "vue-router"
import HomePage from './pages/HomePage.vue'
import AboutPage from './pages/AboutPage.vue'
import NewsPage from './pages/NewsPage.vue'// 1.配置路由规则
const routes = [{ path: '/',redirect: '/home'}, //默认跳转到⾸⻚{ path: '/home', component: HomePage }, { path: '/about', component: AboutPage }, //命名路由{ path: '/news', component: NewsPage, name:'news' },
]// 2.创建路由器
const router = createRouter({history: createWebHistory(),//路由器⼯作模式routes,
})// 3.加载路由器
// createApp(App).mount('#app')
const app = createApp(App)
//加载路由器
app.use(router)
app.mount('#app')
App.vue
<template><div id="app"><h1>Hello App!</h1><p><!-- 路由链接--><router-link to="/home">⾸⻚</router-link> <!-- 直接字符串跳转 --><router-link :to="{ path: '/about' }">关于</router-link> <!-- 对象跳转 --><router-link :to="{ name: 'news' }">新闻</router-link> <!-- 具名跳转 --></p><div class="content"><router-view /> <!-- 路由出⼝,路由匹配到的组件将渲染在这⾥ --></div></div>
</template><!-- vue3写法 -->
<script lang="ts" setup>
</script><style>
a {margin: 10px;
}
.content {background: yellowgreen;widows: 10%;height: 400px;border: 1cap;border-radius: 10px;
}
</style>
路由⼯作模式
在router配置中的history项为路由⼯作模式。Vue提供了两种⼯作模式:
history模式
访问路径:URL不带#,斜杠链接,接近传统⽹站。缺点:容易产⽣404错误。
const router = createRouter({history:createWebHistory(), //history模式/******/
})
hash模式
访问路径:URL带有#。缺点:对SEO不太友好。⽐较适合内部系统。
const router = createRouter({history:createWebHashHistory(), //hash模式/******/
})
replace
route-link标签可以添加replace属性。有两种可选配置: push和replace
push 追加浏览器历史记录(默认值)。追加历史记录后,可以使⽤浏览器的返回按钮,跳回历史⻚
replace 替换浏览器历史记录。替换历史记录后,浏览器的返回按钮不可⽤。

嵌套路由
页面准备
NewsDetail1.vue,NewsDetail2.vue
<!-- NewsDetail1.vue -->
<template><p>新闻ID: 1</p><p>新闻标题: 1 </p><p>新闻内容: 1 </p>
</template>
<script lang="ts" setup>
</script>
<style></style>
main.ts
import NewsDetail1 from './pages/NewsDetail1.vue'
import NewsDetail2 from './pages/NewsDetail2.vue'const routes = [{ path: '/', redirect: '/home' }, //默认跳转到⾸⻚{ path: '/home', component: HomePage },{ path: '/about', component: AboutPage }, //命名路由{path: '/news',component: NewsPage,name: 'news',children: [ //⼦路由{path: "1",component: NewsDetail1,name: "xinwen1"},{path: "2",component: NewsDetail2,name: "xinwen2"}]},
]
NewsPage.vue
<template><div class="news"><!-- 导航区 --><ul><li><RouterLink to="/news/1">新闻1</RouterLink></li><li><RouterLink to="/news/2">新闻2</RouterLink></li></ul><!-- 展示区 --><div class="news-content"><RouterView></RouterView></div></div>
</template>
这样就实现了新闻⻚内的嵌套路由。点击新闻标题,会跳到对应的新闻详情⻚。
路由传参
上⾯的示例显然太呆板,现实的场景当然是希望查出⼀个完整的新闻列表,然后每个新闻⻚都是展示新闻列表中的内容,⽽不是每个组件内固定的内容。这也就需要进⾏路由传参,也就是NewsDetail中的内容是从新闻列表中传递进来的。
Vue3中提供了两种传参⽅式,query传参和param传参。
query传参
NewsPage.vue传参
<!-- 字符串传参 -->
<router-link to="/news/1?id=1&title=新闻1&content=asdfasdf">新闻1</RouterLink><!-- 对象传参 -->
<RouterLink:to="{path:'/news/1',query:{id:'1',title:'新闻1',content:'asdfasdf'}}">新闻1
</RouterLink>
NewsDetail.vue接收参数
<!-- NewsDetail1.vue -->
<template><p>新闻ID: {{ query.id }}</p><p>新闻标题:{{ query.title }}</p><p>新闻内容:{{ query.content }} </p>
</template>
<script lang="ts" setup>
import { useRoute } from 'vue-router'
import { toRef } from 'vue'
let route = useRoute()
// 获取和打印query参数
console.log(route.query)
// 双向绑定数据
let query = toRef(route, 'query')
</script>
<style></style>

params传参
params传参⽅式表示所有参数都拼接到URL上。
⾸先需要在route配置中预设占位符
main.ts
{ path: '/news', component: NewsPage, name:'news',children:[ //⼦路由{path: "1",component: NewsDetail1},{name:'xinwen2', // 对应params传参方式2path: "2/:id/:title/:content", // Param传参,URL预设占位符,?表示参数可有可没有component: NewsDetail2}]
},
然后,传参时,在RouteLink中直接传到预设的URL,或者⽤name属性指定⽬标。
NewsPage.vue
<!-- params传参方式1 -->
<RouterLink to="/news/2/2/新闻2/qowuieoiurr">param路径传参</RouterLink>
<!-- params传参方式2 -->
<RouterLink:to="{name:'xinwen2', <!-- main.ts里也要加name属性 -->params:{id:2,title :'新闻2',content :'qowiueoiqu'}}">param对象传参
</RouterLink>
接下来NewsDetail2.vue中通过路由的params属性接收参数
<!-- NewsDetail2.vue -->
<template><p>新闻ID: {{ params.id }}</p><p>新闻标题:{{ params.title }}</p><p>新闻内容:{{ params.content }} </p>
</template>
<script lang="ts" setup>
import { useRoute } from 'vue-router'
import { toRef } from 'vue'
let route = useRoute()
// 接收并打印query参数
console.log(route.params)
// 双向绑定数据
let params = toRef(route, 'params')
</script>
<style></style>
Pinia集中式状态存储
理解状态
在任意Vue⻚⾯之间共享的存储数据。简单理解:在当前Vue项⽬中使⽤的MySQL数据库。例如登录信息,只要完成了登录,所有Vue⻚⾯都能读取到当前登录⽤户。
Vue2中提供的集中状态存储框架是Vuex,Vue3中新提供了Pinia。如果你使⽤的还是Vue2,那么主要下,Vuex和Pinia不能⼀起使⽤。
创建store
Pinia可以在创建应⽤时选择引⼊。如果创建时没有引⼊,那就需要⼿动引⼊⼀下。
npm install pinia
Pinia的使⽤⽅式和Route组件基本相似。需要在启动的ts⽂件中使⽤use函数引⼊。
main.ts
import {createPinia} from 'pinia'
//加载pinia
const pinia = createPinia()
app.use(pinia)
接下来使⽤pinia需要创建Store。⼀个Store可以理解为MySQL中的⼀个库,保存⼀部分数据。Pinia的Store中有三个概念: state,getter , action。这三个概念也可以类⽐于熟悉的MVC。state相当于是数据;getter相当于是服务,⽤来获取并返回数据;action相当于Controller,组织业务逻辑。
创建定义store的⽂件 store/user.ts
import { defineStore } from 'pinia'export const userStore = defineStore('userStore', {//action封装修改state的业务动作actions: {changeUsername(value: string) {if (value && value.length < 10) {this.username += value}}},//getters读取state的计算值getters: {getUsername(): string {return this.username.toUpperCase()}},//state定义要保存的数据结构state() {return {//给定默认值username: '--'}}
})
使⽤store操作数据
App.vue中修改stroe的数据
<template><div id="app"><h1>Hello App!</h1></div>
</template><script lang="ts" setup>
//获取store
import { userStore } from '@/store/User';
const user = userStore()
//修改store中的值
//1、直接修改某⼀个state
user.username = 'roy'
//2、批量修改完整的state
user.$patch({username: 'roy2'
})
//3、通过action进⾏修改 推荐⽅式
user.changeUsername('roy')
console.log(user.username)
console.log(user.getUsername)
</script><style></style>
pinia的使⽤⼏乎没有⻔槛,相⽐vuex要简单很多,所以官⽅对Pinia的定义是符合直觉的状态管理库。因此,在使⽤pinia时,更应该是注意使⽤规范。
storeToRefs声明响应式数据
<script lang="ts" setup>
//获取store
import { userStore } from '@/store/User';
import { storeToRefs } from "pinia";
import { toRefs } from "vue";const user = userStore()//storeToRefs转换后只有username和getUsername
let userInfo = storeToRefs(user)
console.log(userInfo)
//toRefs转换后包含了很多隐藏⽅法和属性,⽐如$patch
let userInfo2 = toRefs(user)
console.log(userInfo2)</script>
store的混合式写法
store也有⼀种混合式的写法,将各种组件混合到⼀起。
import { defineStore } from 'pinia'
import { reactive } from 'vue'
export const userStore = defineStore('userStore',()=>{//相当于是stateconst userInfo = reactive({username:"---"})//相当于actionfunction changeUsername(value:string){if(value && value.length<10){userInfo.username = value}}//相当于gettersfunction getUsername():string{return userInfo.username.toUpperCase()}//不⽤区分什么类型,返回出去的就可以⽤return {userInfo,changeUsername,getUsername}
})
在App.vue中,也可以像使⽤普通对象⼀样,使⽤store中的⽅法和对象。
<template><div id="app"><!-- 注意对象拆包过程 --><h1>Hello {{ res.userInfo.value.username }}</h1>
</div>
</template>
<!-- vue3写法 -->
<script lang="ts" setup >
//获取store
import { userStore } from "@/store/user2";
import { storeToRefs } from "pinia";
const user = userStore()
//修改store中的值
//通过action进⾏修改 推荐⽅式
user.changeUsername('roy')
// 获取store中的数据
console.log(user.userInfo)
// 通过getter获取state数据 推荐⽅式
console.log(user.getUsername())
//混合式store转成Ref后,只有数据的ref
let res = storeToRefs(user)
console.log(res)
</script>
<style>
</style>
这种⽅式相当于在做MVC开发时,将Controller\Service\Dao这些组件写到⼀起。
复杂项⽬当中,不太建议这样⽤。但是如果别⼈这么⽤了,你要能看懂。
快速上⼿Element-Plus
ElementUI是饿了么开源的⼀套基于Vue2的经典UI库。针对Vue3,升级成为了ElementPlus。熟悉ElementPlus库,不但可以节省⼤量前端项⽬的开发时间,同时也是深⼊了解Vue3复杂组件开发的很好途径。
ElementPlus官⽹地址:https://element-plus.org/zh-CN/ 。 ⽬前还在迭代更新过程当中。
1、安装ElementPlus
npm install element-plus --save
2、引⼊ElementPlus
main.ts
import { createApp } from 'vue'
import App from './App.vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')
3、使⽤ElementPlus组件 参⻅官⽅⽂档。
<template><div class="mb-4"><el-button>Default</el-button><el-button type="primary">Primary</el-button><el-button type="success">Success</el-button><el-button type="info">Info</el-button><el-button type="warning">Warning</el-button><el-button type="danger">Danger</el-button></div>
</template>
<!-- vue3写法 -->
<script lang="ts" setup >
import { ElButton } from 'element-plus';
</script>
<style>
</style>
或者,你也可以直接使⽤element-plus提供的Demo:https://github.com/element-plus/element-plus-vite-starter 。 ⾥⾯有更多现成的案例。
ElementUI针对Vue2还推出过⼀个vue-admin模版,⾥⾯案例更丰富,集成度也更⾼。很多企业内部项⽬都可以直接拿来⽤。有兴趣可以了解⼀下。⽽针对Vue3,只推出了⼀个将ElementUI从Vue2升级到Vue3的迁移⼯具,尚未提供Vue3的版本。
类似的UI框架还有很多,给⼤家例举⼏个常⽤的
Ant Design Vue(https://www.antdv.com/docs/vue/getting-started-cn) 经典⽼框架
Native UI(https://www.naiveui.com/zh-CN/light) 仅⽀持Vue3的⼀个新的UI库
Tdesign(https://tdesign.tencent.com/) 腾讯开源的前端UI框架 包含桌⾯与移动端
NutUI(https://nutui.jd.com/#/) 京东开源的前端UI框架
uvuewui(https://www.uviewui.com/) 适合移动端uni-app开发
相关文章:
vue3 - 图灵
目录 vue3简介整体上认识vue3项目创建Vue3工程使用官方脚手架创建Vue工程[推荐] 主要⼯程结构 数据双向绑定vue2语法的双向绑定简单表单双向绑定复杂表单双向绑定 CompositionAPI替代OptionsAPICompositionAPI简单不带双向绑定写法CompositionAPI简单带双向绑定写法setup简写⽅…...
java设计模式八 享元
享元模式(Flyweight Pattern)是一种结构型设计模式,它通过共享技术有效地支持大量细粒度的对象。这种模式通过存储对象的外部状态在外部,而将不经常变化的内部状态(称为享元)存储在内部,以此来减…...
ELK原理详解
ELK原理详解 一、引言 在当今日益增长的数据量和复杂的系统环境中,日志数据的收集、存储、分析和可视化成为了企业运营和决策不可或缺的一部分。ELK(Elasticsearch、Logstash、Kibana)堆栈凭借其高效的性能、灵活的扩展性和强大的功能&…...
多线程学习Day09
10.Tomcat线程池 LimitLatch 用来限流,可以控制最大连接个数,类似 J.U.C 中的 Semaphore 后面再讲 Acceptor 只负责【接收新的 socket 连接】 Poller 只负责监听 socket channel 是否有【可读的 I/O 事件】 一旦可读,封装一个任务对象&#x…...
第33次CSP认证Q1:词频统计
🍄题目描述 在学习了文本处理后,小 P 对英语书中的 𝑛n 篇文章进行了初步整理。 具体来说,小 P 将所有的英文单词都转化为了整数编号。假设这 𝑛n 篇文章中共出现了 𝑚m 个不同的单词,则把它们…...
pytorch加载模型出现错误
大概的错误长下面这样: 问题出现的原因: 很明显,我就是犯了第一种错误。 网上的修改方法: 我觉得按道理哈,确实,蓝色部分应该是可以把问题解决了的。但是我没有解决,因为我犯了另外一个错…...
如何在Mac上恢复格式化硬盘的数据?
“嗨,我格式化了我的一个Mac硬盘,而没有使用Time Machine备份数据。这个硬盘被未知病毒感染了,所以我把它格式化为出厂设置。但是,我忘了备份我的文件。现在,我想恢复格式化的硬盘驱动器并恢复我的文档,您能…...
华为OD机试 - 手机App防沉迷系统(Java 2024 C卷 100分)
华为OD机试 2024C卷题库疯狂收录中,刷题点这里 专栏导读 本专栏收录于《华为OD机试(JAVA)真题(A卷B卷C卷)》。 刷的越多,抽中的概率越大,每一题都有详细的答题思路、详细的代码注释、样例测试…...
搜维尔科技:光学动作捕捉系统用于城市公共安全智慧感知实验室
用户名称:西安科技大学 主要产品:Optitrack Priime41 光学动作捕捉系统(8头) 在6米8米的空间内,通过8个Optitrack Priime41光学动作捕捉镜头,对人体动作进行捕捉,得到用户想要的人体三维空间坐…...
保研面试408复习 4——操作系统、计网
文章目录 1、操作系统一、文件系统中文件是如何组织的?二、文件的整体概述三、UNIX外存空闲空间管理 2、计算机网络一、CSMA/CD 协议(数据链路层协议)二、以太网MAC帧MTU 标记文字记忆,加粗文字注意,普通文字理解。 1、…...
实战攻防中关于文档的妙用
一、PPT钓鱼 简单制作一个用于钓鱼的PPTX文件 一般那种小白不知道PPT也能拿来钓鱼,这里主要是借用PPT中的”动作按钮”, 我们在插入的地方,选择“动作按钮” 然后在弹出的窗口处: 比如填入上线CS的语句:powershell.exe -nop -w …...
【使用ChatGPT的API之前】OpenAI API提供的可用模型
文章目录 一. ChatGPT基本概念二. OpenAI API提供的可用模型1. InstructGPT2. ChatGPT3. GPT-4 三. 在OpenAI Playground中使用GPT模型-ing 在使用GPT-4和ChatGPT的API集成到Python应用程序之前,我们先了解ChatGPT的基本概念,与OpenAI API提供的可用模型…...
【C语言】模拟实现深入了解:字符串函数
🔥引言 本篇将模拟实现字符串函数,通过底层了解更多相关细节 🌈个人主页:是店小二呀 🌈C语言笔记专栏:C语言笔记 🌈C笔记专栏: C笔记 🌈喜欢的诗句:无人扶我青云志 我自…...
钩子函数onMounted定义了太多访问MySQL的操作 导致数据库异常
先放几种后端遇到的异常,多数和数据库有关 pymysql.err.InternalError: Packet sequence number wrong - got 102 expected 1 127.0.0.1 - - [09/May/2024 17:49:37] "GET /monitorLastTenList HTTP/1.1" 500 AttributeError: NoneType object has no at…...
Excel文件解析---超大Excel文件读写
1.使用POI写入 当我们想在Excel文件中写入100w条数据时,使用XSSFWorkbook进行写入时会发现,只有将100w条数据全部加载到内存后才会用write()方法统一写入,效率很低,所以我们引入了SXXFWorkbook进行超大Excel文件读写。 通过设置 …...
TypeScript基础:类型系统介绍
TypeScript基础:类型系统介绍 引言 TypeScript,作为JavaScript的一个超集,引入了类型系统,这为开发大型应用程序带来了诸多好处。本文将介绍TypeScript类型系统的基础知识,帮助初学者理解其概念和用法。 基础知识 …...
【Unity】Unity项目转抖音小游戏(一) 项目转换
UnityWEBGL转抖音小游戏流程 业务需求,开始接触一下抖音小游戏相关的内容,开发过程中记录一下流程。 相关参考: 抖音文档:https://developer.open-douyin.com/docs/resource/zh-CN/mini-game/develop/guide/game-engine/rd-to-SC…...
element-ui 中修改loading加载样式
element-ui 中的 loading 加载功能,默认是全屏加载效果 设置局部,需要自定义样式或者修改样式,方法如下: import { Loading } from element-uiVue.prototype.$baseLoading (text) > {let loadingloading Loading.service({…...
QT登录界面,(页面的切换)
以登陆界面为例,(QDialog) 1.主界面先构造login 的对话框类 int main(int argc, char *argv[]) {QApplication a(argc, argv);//先显示Login的界面Study_Login_Dialog login;............ }2.Login的类,可以用自定义的信号&#…...
计算机毕业设计 | vue+springboot汽车销售管理系统(附源码)
1,项目介绍 本项目基于spring boot以及Vue开发,前端实现基于PanJiaChen所提供的开源后台项目vue-element-admin改造。 针对汽车销售提供客户信息、车辆信息、订单信息、销售人员管理、财务报表等功能,提供经理和销售两种角色进行管理。 2&…...
Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...
ES6从入门到精通:前言
ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var…...
微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
HBuilderX安装(uni-app和小程序开发)
下载HBuilderX 访问官方网站:https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本: Windows版(推荐下载标准版) Windows系统安装步骤 运行安装程序: 双击下载的.exe安装文件 如果出现安全提示&…...
多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
并发编程 - go版
1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...
uniapp 小程序 学习(一)
利用Hbuilder 创建项目 运行到内置浏览器看效果 下载微信小程序 安装到Hbuilder 下载地址 :开发者工具默认安装 设置服务端口号 在Hbuilder中设置微信小程序 配置 找到运行设置,将微信开发者工具放入到Hbuilder中, 打开后出现 如下 bug 解…...
【Kafka】Kafka从入门到实战:构建高吞吐量分布式消息系统
Kafka从入门到实战:构建高吞吐量分布式消息系统 一、Kafka概述 Apache Kafka是一个分布式流处理平台,最初由LinkedIn开发,后成为Apache顶级项目。它被设计用于高吞吐量、低延迟的消息处理,能够处理来自多个生产者的海量数据,并将这些数据实时传递给消费者。 Kafka核心特…...
用递归算法解锁「子集」问题 —— LeetCode 78题解析
文章目录 一、题目介绍二、递归思路详解:从决策树开始理解三、解法一:二叉决策树 DFS四、解法二:组合式回溯写法(推荐)五、解法对比 递归算法是编程中一种非常强大且常见的思想,它能够优雅地解决很多复杂的…...
