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&…...
一款开源的原神工具箱,专为现代化 Windows 平台设计,旨在改善桌面端玩家的游戏体验
Snap.Hutao 胡桃工具箱是一款以 MIT 协议开源的原神工具箱,专为现代化 Windows 平台设计,旨在改善桌面端玩家的游戏体验。通过将既有的官方资源与开发团队设计的全新功能相结合,提供了一套完整且实用的工具集,且无需依赖任何移动设…...
python日常消费数据占比分析总结年消费方向
欢迎关注我👆,收藏下次不迷路┗|`O′|┛ 嗷~~ 目录 一.前言 整体消费情况 消费趋势 特定领域消费数据...
MySQL变量的浮点数问题处理
schooldb库——utf8字符集——utf8_general_ci排序规则 先创建库,点击查询再去使用下列DQL。 DQL SET dx3.14,dy3.25; SELECT dxdy; #mysql浮点数计算显示异常,会有很多00000的提示 SET resultdxdy;select result;...
MWeb Pro for Mac:功能强大的Markdown博客编辑器
MWeb Pro for Mac是一款功能强大的Markdown博客编辑器,专为Mac用户设计,提供了一站式的博客写作和发布体验。这款软件不仅支持Markdown语法,还提供了丰富的编辑和排版功能,让用户能够轻松创建出精美的博客内容。 MWeb Pro的即时预…...
基于FPGA实现的HDMI TO MIPI扩展显示器方案
FPGA方案,HDMI IN接收原始HDMI 信号,输出显示到LCD 屏上 客户应用:扩展显示器 主要特性: 1.支持2K以下任意分辨率显示 2.支持OSD 叠加多个图层 3.支持MIPI/EDP/LVDS/RGB屏 4.支持放大缩小匹配屏分辨率 5.零延时,输…...
2024年美国市场亚太游戏品牌数字广告洞察报告
来源:Sensor Tower 美国是全球最大的游戏市场之一,也是亚太游戏品牌出海的重要市场。2023年Q2至2024年Q1,美国市场广告投放额排名前10的亚太游戏品牌,合计支出 超过7.5亿美元,环比上涨23%。 排名第一的米哈游(miHoY…...
DDD面试题:DDD聚合和表的对应关系是什么 ?(来自蚂蚁面试)
尼恩说在前面: 在40岁老架构师 尼恩的读者交流群(50)中,最近有小伙伴拿到了一线互联网企业如字节、阿里、滴滴、极兔、有赞、希音、百度、网易、美团的面试资格,遇到很多很重要的面试题: DDD 的外部接口调用,应该放在…...
【华为】路由策略小实验
【华为】软考中级-路由策略实验 实验需求拓扑配置AR1AR2需求1需求2 AR3 检验 实验需求 1、让 R3 可以学到R1的 192.168.10.0/24和192.168.20.0/24的 路由,不能学到192.168.30.0/24。 2、让 R1可以学到 R3 的 172.16.20.0/24和172.16.30.0/24的路由,不能…...
docker安装elasticsearch:7.17.21
docker安装elasticsearch:7.17.21 下载对应版本的docker镜像 docker pull docker.elastic.co/elasticsearch/elasticsearch:7.17.21启动容器 docker run --name elasticsearch-test -p 9200:9200 -p 9300:9300 -e "discovery.typesingle-node" -t docker.elastic.…...
10.Java对象内置结构
文章目录 Java对象内置结构1.Java对象的三个部分1.1.对象头1.2.对象体1.3.对齐字节 2.对象结构中核心字段的作用2.1.MarkWord(标记字)2.2.Class Pointer(类对象指针)2.3.Array Length(数组长度)2.4.对象体2.5.对齐字节 3.Mark Word的结构信息3.1.不同锁状态下的Mark Word字段结…...
哪些网站是用asp.net开发的/市场调研怎么写
场景 今天运用到了锁,记录一下lock和Synchronized的区别。 Synchronized synchronized 是 Java 中的关键字,是一种同步锁。它修饰的对象有以下几种: 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大…...
佛山网站搭建费用/点点站长工具
Q:A1 A2 A3 A4 A5五名研究人员有可能报名化学比赛,根据下列条件判断那些人参加了比赛: 1. A1参加时,A2也参加; 2. A2和A3只有一个人参加; 3. A3和A4或者都参加,或者都不参加; 4. A4和…...
wordpress 视频播放插件/产品故事软文案例
API: Mail/xsend 原文链接 概览 mail/xsend 是邮件 API 的升级版本。与 mail/send API 一样,mail/xsend 提供强大的邮件发送功能,区别于 mail/send API,mail/xsend 无需提交 html 源码或邮件文本内容,甚至无需提交邮件标题或发…...
腾讯邮箱网页版/seo技术服务外包
51%的企业在过去12月内发生过数据泄漏面对日益复杂的安全环境,多样化的攻击手段,传统的防护已经失效,你的安全团队是否做好了准备? 深井式的管理架构,各自封闭的信息系统,无迹可寻的内部泄漏,防…...
求大神帮忙做网站/搜索引擎营销有哪些
JavaScript For 循环循环在编程中用于自动执行重复性任务。例如,假设我们要打印“ Hello World” 10次。可以如下所示进行:document.write("Hello World");document.write("Hello World");document.write("Hello World");…...
网络营销内容有哪些方面/seo网站排名推广
问题: 项目中 前端传JSON数据到后端接口时 数据尾部多了一个等于号 解决办法: 前端 设置请求体类型 以及 数据格式 后端也要指定 接受数据 的格式 在写前后端接口的时候,我的前端将表单的数据封装后转成JSON格式 想着传到后端来解析一波 前端…...