1.vue3 1.1 vue3认识 vue3提供了更好的性能,更小的捆绑包体积,更好的TypeScript集成,用于处理大规模用例的新的API
(1)vue3比vue2更快
(2)vue3加入typescript的支持
(3)vue3没有beforecreate,created ,用setup取代
(4)vue3的组合式API和vue2的选项式API同时存在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 export default { data ( ){ return {} }, methods :{} computed :{} watch :{} } ----------------------------------------------------------------------------------------- <script setup > import { ref, onMounted } from 'vue' const count = ref (0 ) function increment ( ) { count.value ++ } onMounted (() => { console .log (`计数器初始值为 ${count.value} 。` ) }) </script >
(5)代码更利于维护 vue2—》vue3
1.2 搭建脚手架工程 如果以前安装过的 先卸载脚手架
npm uninstall vue-cli -g
安装好之后,通过
vue -V 查看版本
构建项目
vue create 项目名 回车
cd 项目名
npm run serve 运行项目即可
浏览器访问:
文件夹认识
1.3 vue3的setup函数 setup函数:
(1)setup函数是组合式API的入口
(2)setup函数是启动之后自动运行的函数
修改HelloWorld.vue里面内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <template> <div class ="hello" > 1222222 </div > </template> <script > export default { setup ( ){ console .log ('setup运行了' ) } } </script > <style scoped > </style >
(3)定义的变量和常量,方法 都放到setup函数里面去,最后都要return出去,才能在视图层中使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 <template> <div class ="hello" > {{ msg }} <div v-for ="(item,index) in arr" :key ="index" > <h1 > {{ item }}</h1 > </div > <div > <button @click ="test" > 点击</button > </div > </div > </template> <script > export default { setup ( ){ console .log ('setup运行了' ) let msg = '测试1111' let arr = ['1' ,'2' ,'3' ] function test ( ){ console .log ('oooooooooo' ) } return {msg,arr,test} } } </script > <style scoped > </style >
1.4 ref函数 使用示例:
1 2 import {ref} from 'vue' ref ('xxx' )
作用:通过ref包裹的数据,成为响应式的数据 ,可以通过 .value
属性获取或修改值。
说明:
当ref里面的值发生变化,视图里面更着变化
ref可以操作基本类型 ,也可以操作复杂类型,比如数组 对象
操作代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 <template> <div class ="hello" > {{ msg }} <div v-for ="(item,index) in arr" :key ="index" > <h1 > {{ item }}</h1 > </div > <div > {{ obj.name }}</div > <div > <button @click ="test" > 点击</button > </div > </div > </template> <script setup > import {ref} from 'vue' let msg = ref ('测试1111' ) let arr = ref (['1' ,'2' ,'3' ]) let obj = ref ({name :'zs' ,age :18 }) function test ( ){ msg.value = 'hello ts3' arr.value [0 ] = '10' obj.value .name = 'lisi' } </script > <style scoped > </style >
建议ref操作基本类型 比如 数字 还有 字符串,操作复杂类型 通过reactive
1.5 reactive函数 1.5.1 reactive使用 reactive函数 也是返回一个响应式对象,reactive操作复杂的数据,比如数组和对象. 他返回响应式对象Proxy
注意: 定义基本普通类型,不能使用reactive,如下代码:
1 2 3 import {reactive} from 'vue' let msg = reactive ('测试1111' )
测试对象和数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 <template> <div class ="hello" > <div v-for ="(item,index) in arr" :key ="index" > <h1 > {{ item }}</h1 > </div > <div > {{ obj.name }}</div > <div > <button @click ="test" > 点击</button > </div > </div > </template> <script setup > import {reactive} from 'vue' let arr = reactive (['1' ,'2' ,'3' ]) let obj = reactive ({name :'zs' ,age :18 }) function test ( ){ arr[0 ] = '10' obj.name = 'lisi' } </script > <style scoped > </style >
reactive可以操作更深层的对象 ,操作对象都建议使用reactive操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 <template> <div class ="hello" > <div v-for ="(item,index) in arr" :key ="index" > <h1 > {{ item }}</h1 > </div > <div > {{ obj.name }}</div > <div > {{ obj.pros.a.arr[0] }}</div > <div > <button @click ="test" > 点击</button > </div > </div > </template> <script setup > import {reactive} from 'vue' let arr = reactive (['1' ,'2' ,'3' ]) let obj = reactive ( {name :'zs' , age :18 , pros :{ a :{ arr :['我是深层次的数据' ] } }}) function test ( ){ arr[0 ] = '10' obj.name = 'lisi' obj.pros .a .arr [0 ] = '数据变化了' } </script > <style scoped > </style >
1.5.2 ref和reactive区别 ref 是可以操作基本数据类型和数组,对象类型,reactive只能操作数组 对象 这种复杂类型 。
reactive可以操作深层次对象,ref也可以定义数组和对象,ref会自动通过reactive转为代理proxy对象
ref操作数据需要.value,reactive不需要。
1.6 toRef函数 toRef:它也可以创建一个响应式的数据
ref的是一种数据拷贝 ,修改响应式数据是不会影响原始数据
toRef是本质是引用,和原始数据交换,修改响应式数据会影响原始数据 .
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 <template> <div class ="hello" > <div > ref里面的值:{{ num1 }}</div > <div > toRef里面的值:{{ obj.name }}</div > <div > <button @click ="test" > 点击</button > </div > </div > </template> <script setup > import {ref,toRef} from 'vue' let num = 0 let num1 = ref (num) let obj = {name :'zhangsan' } let refv= toRef (obj,'name' ) function test ( ){ num1.value ++ console .log ('ref元数据值:' +num) refv.value = 'zs' console .log ('toRef元数据值:' +obj.name ) } </script > <style scoped > </style >
1.7 toRefs函数 可以批量设置多个数据为响应式数据
toRefs还可以与其他响应式函数交互,更加方便处理视图层数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <template> <div class ="hello" > <div > ---------reactive-------</div > <div > {{ obj.name }}</div > <div > {{ obj.age }}</div > <div > ---------toRefs-------</div > <div > {{ name }}</div > <div > {{ age }}</div > </div > </template> <script setup > import {reactive,toRefs} from 'vue' let obj = reactive ({name :'zs' ,age :10 }) let {name,age} =toRefs (reactive ({name :'zhangsan' ,age :18 })) </script > <style scoped > </style >
1.8 计算属性 computed计算属性,和vue2变化不大,都是用来监听数据的变化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <template> <div class ="hello" > <div > {{ result }}</div > </div > </template> <script setup > import {ref,computed} from 'vue' let str1 = ref ('hello' ) let str2 = ref ('world' ) let result = computed (()=> { return str1.value + '-' +str2.value }) </script > <style scoped > </style >
computed 的 getter 和 setter
当 computed 有 getter 和 setter 时,需要传入一个对象而不是一个函数作为 computed 的参数 ,然后在 computed 中实现 get 和 set 两个属性方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <template> <div class ="hello" > <div > <input type ='text' v-model ="result" /> </div > </div > </template> <script setup > import {ref,computed} from 'vue' let str1 = ref (10 ) let str2 = ref (2 ) let result = computed ({ set (value ){ console .log (value) }, get ( ){ return str1.value + str2.value } }) </script > <style scoped > </style >
1.9 watch监听器 用来监听数据的变化
1 2 import {watch} from vue
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <template> <div class ="hello" > <div > <input type ='text' v-model ="p" /> </div > </div > </template> <script setup > import {ref,watch} from 'vue' let p = ref (0 ) watch (p,(newVal,oldVal )=> { console .log (newVal,oldVal) }) </script > <style scoped > </style >
1.10 watchEffect watchEffect监听的效果,在组件初始化的时候,会执行
watch可以监听新值和老值,而watchEffect拿不到
watchEffect不需要监听属性,在里面可以获取
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <template> <h1 v-text ='num' > </h1 > <button @click ="countFun" > 叠加num</button > <button @click ='stopAll' > 停止监听</button > </template> <script setup > import { ref, watchEffect } from 'vue' let num = ref (0 ) let wfn =watchEffect (()=> { console .log ('---执行监听' , num.value ) }) const stopAll = ( ) => { wfn () } let countFun = ( )=>{ num.value ++ } </script >
1.11 vue3的生命周期 `Vue3的组合式API提供了一套新的生命周期钩子,与Vue2中的选项式生命周期钩子有着对应关系。在Composition API中,组合式生命周期钩子有:
onBeforeMount:对应Vue2中的beforeMount钩子,Vue实例挂载之前调用。
onMounted:对应Vue2中的mounted钩子,Vue实例挂载完成后调用。
onBeforeUpdate:对应Vue2中的beforeUpdate钩子,数据更新时调用,但在DOM更新前。
onUpdated:对应Vue2中的updated钩子,数据更新后在DOM更新后调用。
onBeforeUnmount:对应Vue2中的beforeDestroy钩子,Vue实例销毁前调用。
onUnmounted:对应Vue2中的destroyed钩子,Vue实例销毁后调用。
生命周期4个主要事件
创建—在组件创建时候执行
挂载-DOM被挂载时执行
更新-当响应数据被修改时候执行
销毁-在元素被销毁之前立即执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 在HelloWorld .vue 代码 <template> <h1 v-text ='num' > </h1 > <button @click ="countFun" > 叠加num</button > </template> <script setup > import { ref, onBeforeMount,onMounted,onBeforeUpdate,onUpdated,onBeforeUnmount,onUnmounted } from 'vue' let num = ref (0 ) let countFun = ( )=>{ num.value ++ } onBeforeMount (()=> { console .log ('onBeforeMount' ,'在挂载开始之前调用' ) }) onMounted (()=> { console .log ('onMounted' ,'在挂载时调用' ) }) onBeforeUpdate (()=> { console .log ('onBeforeUpdate' ,'在更新之前调用' ) }) onUpdated (()=> { console .log ('onUpdated' ,'在更新调用' ) }) onBeforeUnmount (()=> { console .log ('onBeforeUnmount' ,'在销毁前调用' ) }) onUnmounted (()=> { console .log ('onUnmounted' ,'在销毁时候调用' ) }) </script >
销毁测试: 在App.vue页面 设置隐藏
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <template> <HelloWorld v-if ="isShow" /> <button @click ="isShow = !isShow" > 隐藏</button > </template> <script > import HelloWorld from './components/HelloWorld.vue' import {ref} from 'vue' export default { name : 'App' , components : { HelloWorld }, setup ( ){ let isShow = ref (true ) return {isShow} } } </script > <style > </style >
1.12 组件传值 1.12.1 父传子 父组件:
1 2 const p1 = reactive ({name :'zs' ,age :18 })provide ('p1' ,p1)
子组件:
1 const obj = inject ('p1' )
完整代码:
App.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <template> <div > 我是父组件:{{p1 }}</div > <HelloWorld /> </template> <script setup > import { provide, reactive } from 'vue' ;import HelloWorld from './components/HelloWorld.vue' let p1 = reactive ({name :'zs' ,age :18 })provide ("p1" ,p1) </script > <style > </style >
HelloWorld.vue子组件
1 2 3 4 5 6 7 8 9 10 11 12 <template> <div > <div > 我是子组件:{{ obj }}</div > </div > </template> <script setup > import { inject } from 'vue' let obj = inject ('p1' ) </script >
结果:
1.12.2 子传父 通过defineEmits
子组件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <template> <div > <div > 我是子组件:{{ obj }}</div > <button @click ="toParent" > 点击我传到父组件</button > </div > </template> <script setup > import { inject,defineEmits } from 'vue' let obj = inject ('p1' ) let emit = defineEmits (['toParent' ]) const toParent =( )=>{ emit ('toParent' ,'我是子数据' ) } </script >
父组件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <template> <div > 我是父组件:{{p1 }}</div > <HelloWorld @to-parent ="getSon" /> </template> <script setup > import { provide, reactive } from 'vue' ;import HelloWorld from './components/HelloWorld.vue' let p1 = reactive ({name :'zs' ,age :18 })provide ("p1" ,p1) const getSon = (sonValue )=>{ console .log ("父组件获取子组件的Value:" +sonValue) } </script > <style > </style >
1.Element Plus认识 基于 Vue 3,面向设计师和开发者的组件库,提供很多组件,可以在项目中使用
官网地址:
https://element-plus.org/zh-CN/
2.搭建vue3+ts脚手架 (1)创建项目文件夹 ,比如 vue3_02
(2) vue create 项目名
(3) 选择最后 手动安装
(4) 选择对应的组件
光标到对应行,然后按空格即可选中 需要的配置
选中之后 回车:
注意:下面的lint 先默认选择第一个 回车 选择 Lint on save
配置好的目录结构:
启动访问的效果:
3.ElementPlus安装和配置 3.1 安装elementplus 1 npm install element-plus --save
3.2 配置elementplus 在main.ts里面配置
1 2 3 import ElementPlus from 'element-plus' import 'element-plus/dist/index.css' app.use (ElementPlus )
完整代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 import { createApp } from 'vue' import App from './App.vue' import router from './router' import store from './store' import ElementPlus from 'element-plus' import 'element-plus/dist/index.css' createApp (App ) .use (store) .use (router) .use (ElementPlus ) .mount ('#app' )
修改HelloWorld.vue里面的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <template> <div class ="hello" > <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> <script lang ="ts" setup > </script >
浏览器访问:
4.ElementPlus组件使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 <template> <el-row > <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 > </el-row > <el-row class ="mb-4" > <el-button plain > Plain</el-button > <el-button type ="primary" plain > Primary</el-button > <el-button type ="success" plain > Success</el-button > <el-button type ="info" plain > Info</el-button > <el-button type ="warning" plain > Warning</el-button > <el-button type ="danger" plain > Danger</el-button > </el-row > <el-row class ="mb-4" > <el-button round > Round</el-button > <el-button type ="primary" round > Primary</el-button > <el-button type ="success" round > Success</el-button > <el-button type ="info" round > Info</el-button > <el-button type ="warning" round > Warning</el-button > <el-button type ="danger" round > Danger</el-button > </el-row > <el-row > <el-button :icon ="Search" circle /> <el-button type ="primary" :icon ="Edit" circle /> <el-button type ="success" :icon ="Check" circle /> <el-button type ="info" :icon ="Message" circle /> <el-button type ="warning" :icon ="Star" circle /> <el-button type ="danger" :icon ="Delete" circle /> </el-row > </template> <script lang ="ts" setup > import { Check , Delete , Edit , Message , Search , Star , } from '@element-plus/icons-vue' </script >
效果:
4.2 布局layout 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 <template> <el-row > <el-col :span ="24" > <div class ="grid-content ep-bg-purple-dark" > </div > </el-col > </el-row > <el-row > <el-col :span ="12" > <div class ="grid-content ep-bg-purple" > </div > </el-col > <el-col :span ="12" > <div class ="grid-content ep-bg-purple-light" > </div > </el-col > </el-row > <el-row > <el-col :span ="8" > <div class ="grid-content ep-bg-purple" > </div > </el-col > <el-col :span ="8" > <div class ="grid-content ep-bg-purple-light" > </div > </el-col > <el-col :span ="8" > <div class ="grid-content ep-bg-purple" > </div > </el-col > </el-row > <el-row > <el-col :span ="6" > <div class ="grid-content ep-bg-purple" > </div > </el-col > <el-col :span ="6" > <div class ="grid-content ep-bg-purple-light" > </div > </el-col > <el-col :span ="6" > <div class ="grid-content ep-bg-purple" > </div > </el-col > <el-col :span ="6" > <div class ="grid-content ep-bg-purple-light" > </div > </el-col > </el-row > <el-row > <el-col :span ="4" > <div class ="grid-content ep-bg-purple" > </div > </el-col > <el-col :span ="4" > <div class ="grid-content ep-bg-purple-light" > </div > </el-col > <el-col :span ="4" > <div class ="grid-content ep-bg-purple" > </div > </el-col > <el-col :span ="4" > <div class ="grid-content ep-bg-purple-light" > </div > </el-col > <el-col :span ="4" > <div class ="grid-content ep-bg-purple" > </div > </el-col > <el-col :span ="4" > <div class ="grid-content ep-bg-purple-light" > </div > </el-col > </el-row > </template> <script lang ="ts" setup > </script > <style lang ="scss" > .el-row { margin-bottom : 20px ; } .el-row :last-child { margin-bottom : 0 ; } .el-col { border-radius : 4px ; } .grid-content { border-radius : 4px ; min-height : 36px ; background-color : antiquewhite; } .ep-bg-purple { background-color : black; } .ep-bg-purple-light { background-color : aquamarine; } </style >
效果:
4.3 Container 布局容器 用于布局的容器组件,方便快速搭建页面的基本结构:
<el-container>
:外层容器。 当子元素中包含 <el-header>
或 <el-footer>
时,全部子元素会垂直上下排列, 否则会水平左右排列。
<el-header>
:顶栏容器。
<el-aside>
:侧边栏容器。
<el-main>
:主要区域容器。
<el-footer>
:底栏容器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 <template> <el-container > <el-header > Header</el-header > <el-container style ="height: 500px;" > <el-aside width ="200px" > Aside</el-aside > <el-container > <el-main > Main</el-main > <el-footer > Footer</el-footer > </el-container > </el-container > </el-container > </template> <script lang ="ts" setup > </script > <style lang ="scss" > .el-header , .el-footer { background-color : #B3C0D1 ; color : #333 ; text-align : center; line-height : 60px ; } .el-aside { background-color : #D3DCE6 ; color : #333 ; text-align : center; line-height : 200px ; } .el-main { background-color : #E9EEF3 ; color : #333 ; text-align : center; line-height : 160px ; } body > .el-container { margin-bottom : 40px ; } .el-container :nth-child (5 ) .el-aside , .el-container :nth-child (6 ) .el-aside { line-height : 260px ; } .el-container :nth-child (7 ) .el-aside { line-height : 320px ; } </style >
4.4 Icon 图标 main.ts引入所有图标
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import { createApp } from 'vue' import App from './App.vue' import router from './router' import store from './store' import ElementPlus from 'element-plus' import 'element-plus/dist/index.css' import * as ElementPlusIconsVue from '@element-plus/icons-vue' const app = createApp (App )for (const [key, component] of Object .entries (ElementPlusIconsVue )) { app.component (key, component) } app.use (store) .use (router) .use (ElementPlus ) .mount ('#app' )
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 <template> <el-icon :size ="30" :color ="color" > <Edit /> </el-icon > </template> <script lang ="ts" setup > import {ref} from 'vue' let color = ref ('#ff0011' ) </script >
效果:
参考页面:
https://element-plus.org/zh-CN/component/icon.html
4.5 link链接 用法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <template> <div > <el-link href ="https://element-plus.org" target ="_blank" > default</el-link > <el-link type ="primary" :underline ="false" > 去下划线链接</el-link > <el-link type ="success" disabled > 禁用链接</el-link > <el-link type ="warning" > warning</el-link > <el-link type ="danger" > danger</el-link > <el-link type ="info" > info</el-link > </div > </template> <script lang ="ts" setup > </script > <style scoped > .el-link { margin-right : 8px ; } .el-link .el-icon--right .el-icon { vertical-align : text-bottom; } </style >
效果:
4.6 Text文本 4.6.1 基本文本使用 1 2 3 4 5 6 7 8 9 10 11 12 13 <template> <el-text class ="mx-1" style ="margin-right: 10px;" > Default</el-text > <el-text class ="mx-1" type ="primary" style ="margin-right: 10px;" > Primary</el-text > <el-text class ="mx-1" type ="success" style ="margin-right: 10px;" > Success</el-text > <el-text class ="mx-1" type ="info" style ="margin-right: 10px;" > Info</el-text > <el-text class ="mx-1" type ="warning" style ="margin-right: 10px;" > Warning</el-text > <el-text class ="mx-1" type ="danger" style ="margin-right: 10px;" > Danger</el-text > </template> <script lang ="ts" setup > </script >
效果:
4.6.2 文本省略 通过 truncated
属性,在文本超过视图或最大宽度设置时展示省略符。
1 2 3 4 5 <el-row> <el-col :span ="4" > <el-text truncated > Squeezed by parent element111111111111111111</el-text > </el-col > </el-row>
效果:
4.6.3 覆盖 使用属性 tag
覆盖元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <el-space direction="vertical" > <el-text > span</el-text > <el-text tag ="p" > This is a paragraph.</el-text > <el-text tag ="b" > Bold</el-text > <el-text tag ="i" > Italic</el-text > <el-text > This is <el-text tag ="sub" size ="small" > subscript</el-text > </el-text > <el-text > This is <el-text tag ="sup" size ="small" > superscript</el-text > </el-text > <el-text tag ="ins" > Inserted</el-text > <el-text tag ="del" > Deleted</el-text > <el-text tag ="mark" > Marked</el-text > </el-space>
效果:
4.7.1 常用表单组件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 <template> <el-form :model ="form" label-width ="120px" > <el-form-item label ="Activity name" > <el-input v-model ="form.name" /> </el-form-item > <el-form-item label ="Activity zone" > <el-select v-model ="form.region" placeholder ="please select your zone" > <el-option label ="Zone one" value ="shanghai" /> <el-option label ="Zone two" value ="beijing" /> </el-select > </el-form-item > <el-form-item label ="Activity time" > <el-col :span ="11" > <el-date-picker v-model ="form.date1" type ="date" placeholder ="Pick a date" style ="width: 100%" /> </el-col > <el-col :span ="2" class ="text-center" > <span class ="text-gray-500" > -</span > </el-col > <el-col :span ="11" > <el-time-picker v-model ="form.date2" placeholder ="Pick a time" style ="width: 100%" /> </el-col > </el-form-item > <el-form-item label ="Instant delivery" > <el-switch v-model ="form.delivery" /> </el-form-item > <el-form-item label ="Activity type" > <el-checkbox-group v-model ="form.type" > <el-checkbox label ="Online activities" name ="type" /> <el-checkbox label ="Promotion activities" name ="type" /> <el-checkbox label ="Offline activities" name ="type" /> <el-checkbox label ="Simple brand exposure" name ="type" /> </el-checkbox-group > </el-form-item > <el-form-item label ="Resources" > <el-radio-group v-model ="form.resource" > <el-radio label ="Sponsor" /> <el-radio label ="Venue" /> </el-radio-group > </el-form-item > <el-form-item label ="Activity form" > <el-input v-model ="form.desc" type ="textarea" /> </el-form-item > <el-form-item > <el-button type ="primary" @click ="onSubmit" > Create</el-button > <el-button > Cancel</el-button > </el-form-item > </el-form > </template> <script lang ="ts" setup > import { reactive } from 'vue' const form = reactive ({ name : '' , region : '' , date1 : '' , date2 : '' , delivery : false , type : [], resource : '' , desc : '' , }) const onSubmit = ( ) => { console .log ('submit!' ) } </script >
要使用它,只需要在 <el-input-number>
元素中使用 v-model
绑定变量即可,变量的初始值即为默认值。
1 2 3 4 5 6 7 8 9 10 11 12 <template> <el-input-number v-model ="num" :min ="1" :max ="10" @change ="handleChange" /> </template> <script lang ="ts" setup > import { ref } from 'vue' const num = ref (1 )const handleChange = (value: number ) => { console .log (value) } </script >
效果:
4.10 导航组件 菜单,使用还是比较多的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 <template> <el-menu :default-active ="activeIndex" class ="el-menu-demo" mode ="horizontal" @select ="handleSelect" > <el-menu-item index ="1" > Processing Center</el-menu-item > <el-sub-menu index ="2" > <template #title > Workspace</template > <el-menu-item index ="2-1" > item one</el-menu-item > <el-menu-item index ="2-2" > item two</el-menu-item > <el-menu-item index ="2-3" > item three</el-menu-item > <el-sub-menu index ="2-4" > <template #title > item four</template > <el-menu-item index ="2-4-1" > item one</el-menu-item > <el-menu-item index ="2-4-2" > item two</el-menu-item > <el-menu-item index ="2-4-3" > item three</el-menu-item > </el-sub-menu > </el-sub-menu > <el-menu-item index ="3" disabled > Info</el-menu-item > <el-menu-item index ="4" > Orders</el-menu-item > </el-menu > <div class ="h-6" /> <el-menu :default-active ="activeIndex2" class ="el-menu-demo" mode ="horizontal" background-color ="#545c64" text-color ="#fff" active-text-color ="#ffd04b" @select ="handleSelect" > <el-menu-item index ="1" > Processing Center</el-menu-item > <el-sub-menu index ="2" > <template #title > Workspace</template > <el-menu-item index ="2-1" > item one</el-menu-item > <el-menu-item index ="2-2" > item two</el-menu-item > <el-menu-item index ="2-3" > item three</el-menu-item > <el-sub-menu index ="2-4" > <template #title > item four</template > <el-menu-item index ="2-4-1" > item one</el-menu-item > <el-menu-item index ="2-4-2" > item two</el-menu-item > <el-menu-item index ="2-4-3" > item three</el-menu-item > </el-sub-menu > </el-sub-menu > <el-menu-item index ="3" disabled > Info</el-menu-item > <el-menu-item index ="4" > Orders</el-menu-item > </el-menu > </template> <script lang ="ts" setup > import { ref } from 'vue' const activeIndex = ref ('1' )const activeIndex2 = ref ('1' )const handleSelect = (key: string, keyPath: string[] ) => { console .log (key, keyPath) } </script >
效果:
4.11 Tabs 标签页 abs 组件提供了选项卡功能, 默认选中第一个标签页,你也可以通过 value
属性来指定当前选中的标签页。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <template> <el-tabs v-model ="activeName" class ="demo-tabs" @tab-click ="handleClick" > <el-tab-pane label ="User" name ="first" > User</el-tab-pane > <el-tab-pane label ="Config" name ="second" > Config</el-tab-pane > <el-tab-pane label ="Role" name ="third" > Role</el-tab-pane > <el-tab-pane label ="Task" name ="fourth" > Task</el-tab-pane > </el-tabs > </template> <script lang ="ts" setup > import { ref } from 'vue' import type { TabsPaneContext } from 'element-plus' const activeName = ref ('first' )const handleClick = (tab: TabsPaneContext, event: Event ) => { console .log (tab, event) } </script > <style > .demo-tabs > .el-tabs__content { padding : 32px ; color : #6b778c ; font-size : 32px ; font-weight : 600 ; } </style >
4.12 反馈组件 4.12.1 dialog对话框 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 <template> <el-button text @click ="dialogVisible = true" > click to open the Dialog </el-button > <el-dialog v-model ="dialogVisible" title ="Tips" width ="30%" :before-close ="handleClose" > <span > This is a message</span > <template #footer > <span class ="dialog-footer" > <el-button @click ="dialogVisible = false" > Cancel</el-button > <el-button type ="primary" @click ="dialogVisible = false" > Confirm </el-button > </span > </template > </el-dialog > </template> <script lang ="ts" setup > import { ref } from 'vue' import { ElMessageBox } from 'element-plus' const dialogVisible = ref (false )const handleClose = (done: () => void ) => { ElMessageBox .confirm ('Are you sure to close this dialog?' ) .then (() => { done () }) .catch (() => { }) } </script > <style scoped > .dialog-footer button :first -child { margin-right : 10px ; } </style >
效果:
4.13 表格组件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 <template> <el-table border :data ="tableData" style ="width: 100%" > <el-table-column prop ="date" label ="日期" width ="180" > </el-table-column > <el-table-column prop ="name" label ="姓名" width ="180" > </el-table-column > <el-table-column prop ="address" label ="地址" > </el-table-column > </el-table > </template> <script lang ="ts" setup > import {reactive} from 'vue' let tableData = reactive ([{ date : '2024-05-02' , name : '王小虎' , address : '上海市普陀区金沙江路 1518 弄' }, { date : '2024-05-04' , name : '王小虎' , address : '上海市普陀区金沙江路 1517 弄' }, { date : '2024-05-01' , name : '王小虎' , address : '上海市普陀区金沙江路 1519 弄' }, { date : '2024-05-03' , name : '王小虎' , address : '上海市普陀区金沙江路 1516 弄' }]) </script >
效果:
1.nodejs和express后端服务 1.1 创建项目名 (1)在指定目录创建一个文件夹比如vue3_03
1.2 安装express-generator (2)安装express-generator -g(快速生成express框架的结构)
1 npm install express-generator -g
1.3 创建express项目工程 1 2 3 4 5 6 7 8 express -e 项目名 比如 express -e backp cd backp npm install
1.4 项目热启动nodemon
修改package.json里面
1.5 启动项目 npm start
1.6 启动mongodb服务
通过navicat连接mongodb 创建一个数据库
创建集合
插入数据
1.7 node连接mongodb 安装一些 mongoose
1 npm install mongoose@6.8 .0
创建文件夹db/index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 const mongoose = require ('mongoose' )mongoose.set ("strictQuery" , false ); module .exports = function (success,error ){ if (typeof error !== 'function' ){ error = ()=> { console .log ('链接失败' ) } } mongoose.connect ('mongodb://127.0.0.1:27017/abc' ) mongoose.connection .on ('open' ,()=> { success () }) mongoose.connection .on ('error' ,()=> { error () }) mongoose.connection .on ('close' ,()=> { console .log ('链接关闭' ) }) }
在启动bin/www 下面链接数据库
新创建一个models文件夹,然后在下面创建一个UserModel.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 var mongoose = require ('mongoose' ) let userSchema = new mongoose.Schema ({ name :String , age :Number , email :String , tel :String }) let UserModel = mongoose.model ('users' ,userSchema)module .exports = UserModel
在路由文件里面引入 routers/users.js引入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 var express = require ('express' );var router = express.Router ();const UserModel = require ('./../models/UserModel' )router.get ('/' , function (req, res, next ) { UserModel .find ((err,data )=> { if (err){ console .log ('读取失败' ) return } console .log (data) }) res.send ('respond with a resource' ); }); module .exports = router;
启动项目测试:
npm start
2.vue3+ts+elementplus前端服务 2.1 创建项目文件夹 比如 vue3_03/frontp
2.2 vue create 项目名 vue create 项目名
选择最后 手动安装
2.3 选择对应的组件
光标到对应行,然后按空格即可选中 需要的配置
选中之后 回车:
配置好的目录结构:
启动访问的效果:
2.4 安装elmentplus npm install element-plus —save
在main.ts里面配置
1 2 3 import ElementPlus from 'element-plus' import 'element-plus/dist/index.css' app.use (ElementPlus )
完整代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 import { createApp } from 'vue' import App from './App.vue' import router from './router' import store from './store' import ElementPlus from 'element-plus' import 'element-plus/dist/index.css' createApp (App ) .use (store) .use (router) .use (ElementPlus ) .mount ('#app' )
修改HelloWorld.vue里面的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <template> <div class ="hello" > <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> <script lang ="ts" setup > </script >
浏览器访问:
2.5 引入table组件 在HelloWorld里面引入table组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 <template> <el-table :data ="tableData" style ="width: 100%" > <el-table-column prop ="date" label ="日期" width ="180" > </el-table-column > <el-table-column prop ="name" label ="姓名" width ="180" > </el-table-column > <el-table-column prop ="address" label ="地址" > </el-table-column > </el-table > </template> <script lang ="ts" setup > import {reactive} from 'vue' let tableData = reactive ([{ date : '2024-05-02' , name : '王小虎' , address : '上海市普陀区金沙江路 1518 弄' }, { date : '2024-05-04' , name : '王小虎' , address : '上海市普陀区金沙江路 1517 弄' }, { date : '2024-05-01' , name : '王小虎' , address : '上海市普陀区金沙江路 1519 弄' }, { date : '2024-05-03' , name : '王小虎' , address : '上海市普陀区金沙江路 1516 弄' }]) </script > <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped lang ="scss" > h3 { margin : 40px 0 0 ; } ul { list-style-type : none; padding : 0 ; } li { display : inline-block; margin : 0 10px ; } a { color : #42b983 ; } </style >
3 前后端联调 3.1 前端axios 安装axios
引入axios,创建axios实例
请求拦截
响应拦截
暴露实例
在src创建api文件夹,在创建request.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import axios from 'axios' const api = axios.create ({ baseURL : 'http://localhost:3000' , timeout : 5000 , headers : { "Content-type" : 'application/json;charset:utf-8' } } ) api.interceptors .request .use ((config: any ) => { if (localStorage .getItem ('token' )) { config.headers .token = localStorage .getItem ('token' ) || '' } return config }) api.interceptors .response .use ((res: any ) => { const msg = res.data .msg || '' const result = res.data .data || {} if (msg === 'success' ) { return result } else { return Promise .reject (res.data ) } }, (err ) => { console .error (err) }) export default api;
在HelloWorld.vue引入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 <template> <el-table :data ="tableData.usersData" style ="width: 100%" > <el-table-column prop ="name" label ="姓名" width ="180" > </el-table-column > <el-table-column prop ="email" label ="邮箱" > </el-table-column > <el-table-column prop ="tel" label ="电话号码" > </el-table-column > <el-table-column prop ="age" label ="年龄" > </el-table-column > </el-table > </template> <script lang ="ts" setup > import {reactive,onMounted} from 'vue' import api from '@/api/request' let tableData = reactive ({ usersData :[], total :100 }) let getUserData = async ( )=>{ try { let result :[] = await api ({ url :'/users' , method :'get' }); tableData.usersData = result }catch (err :any){ console .log (err); } } onMounted ( ()=> { getUserData () }) </script >
3.2 后端解决跨域 在app.js里面引入:
1 2 3 4 5 6 7 8 9 10 app.all ('*' , function (req, res, next ) { res.header ("Access-Control-Allow-Origin" , "*" ); res.header ('Access-Control-Allow-Headers' , 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild' ); res.header ("Access-Control-Allow-Methods" , "PUT,POST,GET,DELETE,OPTIONS" ); res.header ("X-Powered-By" , ' 3.2.1' ) res.header ("Content-Type" , "application/json;charset=utf-8" ); next (); });
在users.js查询返回数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 var express = require ('express' );var router = express.Router ();const UserModel = require ('./../models/UserModel' )router.get ('/' , function (req, res, next ) { UserModel .find ((err,data )=> { if (err){ console .log ('读取失败' ) return } res.json ({msg :'success' ,data :data}); }) }); module .exports = router;
最终效果: