站长之家域名查询官网,军事网站 模板,互联网企业100强名单,做外贸网站信息文章目录 Vue快速上手Vue是什么第一个Vue程序插值表达式Vue核心特性#xff1a;响应式 Vue指令v-htmlv-show 与 v-ifv-else 与 v-else-ifv-onv-bindv-forv-model指令修饰符 计算属性watch侦听器#xff08;监视器#xff09;watch——简写watch——完整写法 Vue生命周期 和 … 文章目录 Vue快速上手Vue是什么第一个Vue程序插值表达式Vue核心特性响应式 Vue指令v-htmlv-show 与 v-ifv-else 与 v-else-ifv-onv-bindv-forv-model指令修饰符 计算属性watch侦听器监视器watch——简写watch——完整写法 Vue生命周期 和 生命周期的四个阶段Vue生命周期函数钩子函数 工程化开发脚手架 Vue cli脚手架目录文件介绍 组件化开发普通组件的注册使用scoped样式冲突 组件通信父子通信流程图prop 非父子通信表单类组件封装.sync修饰符ref和$refsVue异步更新、$nextTick 自定义指令插槽默认插槽插槽后备内容默认值具名插槽作用于插槽 路由VueRouter的介绍VueRouter的使用52路由的封装抽离使用router-link声明式导航声明式导航——跳转传参重定向编程式导航组件缓存keep-alive ESlint代码规范vuex概述创建一个空仓库提供与访问vuex的数据修改vuex的数据actionsgetters模块module进阶语法 Vue3快速入门创建Vue3项目组合式API —— setup选项组合式API —— reactive 函数组合式API —— ref 函数组合式API —— computed组合式API —— watch组合式API —— 生命周期函数组合式API —— 父子通信组合式API —— 模板引用组合式API —— provide 和 inject新特性 —— defineOptions新特性 —— defineModel Pinia手动添加Pinia到Vue项目Pinia基础使用 —— 计数器案例action异步实现storeToRefs方法Pinia持久化插件 Vue快速上手
Vue是什么
概念Vue是一个用于构建用户界面的渐进式框架
优点大大提升开发效率缺点需要理解记忆规则 Vue的两种使用方式
Vue核心包开发 场景局部模块改造Vue核心包 Vue插件工程化开发 场景整站开发
第一个Vue程序
穿件Vue实例初始化渲染的核心步骤
准备容器引包官网—— 开发版本 / 生产版本创建Vue实例 new Vue()指定配置项 el data 渲染数据 el指定挂载点选择器指定控制饿时哪个盒子data提供数据 代码演示
!DOCTYPE html
html langen
headmeta charsetUTF-8titleTitle/title
/head
body
!--创建Vue实例初始化渲染1. 准备容器Vue所管理的范围2. 引包开发版本包 / 生产版本包 官网3. 创建实例4. 添加配置项 完成渲染
--
div idapp!-- 这里将来会编写一些用于渲染的代码逻辑 --{{msg}}
/div!--引入的是开发版本包包含完整的注释和警告--
script srchttps://cdn.jsdelivr.net/npm/vue2.7.14/dist/vue.js/scriptscript// 一但引入了Vue.js核心包在全局环境就有了Vue构造函数const app new Vue({// 通过el配置选择器指定Vue管理的是哪个盒子el: #app,// 通过data提供数据data:{msg: 小吴在敲Bug}})
/script
/body
/html插值表达式
插值表达式是一种Vue的模版语法
作用 利用表达式进行插值渲染到页面中 表达式是可以被求值的代码JS引擎会将其计算出一个结果语法 {{ 表达式 }} 使用的数据必须存在data支持的是表达式而非语句不能再标签属性中使用{{}}插值 代码演示
!DOCTYPE html
html langen
headmeta charsetUTF-8titleTitle/title
/head
body
!--插值表达式Vue的一种模板语法作用利用 表达式进行插值渲染语法{{表达式}}
--
div idappp{{msg}}/pp{{msg.toUpperCase()}}/pp{{msg 你好}}/pp{{age18? 成年:未成年}}/p/divscript srchttps://cdn.jsdelivr.net/npm/vue2.7.14/dist/vue.js/scriptscriptconst app new Vue({el: #app,data:{msg: 小吴在敲Bug,age: 21}})
/script
/body
/htmlVue核心特性响应式
我们已经掌握了寄出的模版渲染其实除了基本的模版渲染Vue背后还做了大量工作。 比如数据的响应式处理 —— 数据变化视图自动更新 聚焦于数据——数据驱动视图 使用Vue开发关注 业务的核心逻辑根据业务 修改数据即可 代码演示
!DOCTYPE html
html langen
headmeta charsetUTF-8titleTitle/title
/head
bodydiv idappp{{msg}}/p/divscript srchttps://cdn.jsdelivr.net/npm/vue2.7.14/dist/vue.js/scriptscriptconst app new Vue({el: #app,data:{// 响应式msg: 小吴在敲Bug}})// 1. 访问数据 实例.属性名// 2. 修改数据 实例.属性名新值
/script
/body
/html测试
Vue指令
Vue会根据不同的指令针对不同标签实现不同的功能 指令带有 v-前缀 的特殊 标签属性
v-html
v-html指令 作用向指定节点中渲染包含html结构的内容。 与插值语法的区别 v-html会替换掉节点中所有的内容{{xx}}则不会。 v-html可以识别html结构。 严重注意v-html有安全性问题 在网站上动态渲染任意HTML是非常危险的容易导致XSS攻击。 一定要在可信的内容上使用v-html永不要用在用户提交的内容上 代码演示
!DOCTYPE html
html langen
headmeta charsetUTF-8titleTitle/title
/head
bodydiv idappdiv v-htmlmsg/div/divscript srchttps://cdn.jsdelivr.net/npm/vue2.7.14/dist/vue.js/scriptscriptconst app new Vue({el: #app,data:{msg:a hrefwww.4399.com4399小游戏/a}})
/script
/body
/htmlv-show 与 v-if
v-show
作用控制元素显示和隐藏语法v-show“表达式” | 表达式值true显示false隐藏原理切换display:none 控制显示隐藏场景频繁切换显示隐藏的场景 v-if
作用控制元素显示隐藏条件渲染语法v-if“表达式” | 表达式值true显示false隐藏原理基于 条件判断是否创建或移除元素节点场景要么显示要么隐藏不频繁切换的场景
v-else 与 v-else-if
作用辅助v-if进行判断渲染语法v-else | v-else-if“表达式”注意需要紧挨着v-if一起使用 代码演示
!DOCTYPE html
html langen
headmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/title
/head
bodydiv idappdiv p v-ifgender1性别♂ 男/pp v-else性别♀ 女/phrp v-ifscoreA成绩评定A奖励电脑一台/pp v-else-ifscoreB成绩评定B奖励周末郊游/pp v-else-ifscoreC成绩评定C奖励零食礼包/pp v-else成绩评定D惩罚一周不能玩手机/p/div
/divscript srchttps://cdn.jsdelivr.net/npm/vue2.7.14/dist/vue.js/script
scriptconst app new Vue({el: #app,data: {gender: 1,score: B}})
/script/body
/htmlv-on
作用注册时间 添加监听 提供处理逻辑语法 v-on事件名 “内联语句”v-on事件名 “methods中的函数名” 简写事件名 v-on调用传参
语法click函数名(参数1,参数2……)接收参数使用函数的形参函数名(a,b){} 代码演示
!DOCTYPE html
html langen
headmeta charsetUTF-8titleTitle/title
/head
bodydiv idappbutton clickcount---/buttonspan{{count}}/spanbutton v-on:clickcount/button
/divscript srchttps://cdn.jsdelivr.net/npm/vue2.7.14/dist/vue.js/scriptscriptconst app new Vue({el: #app,data:{count: 0}})
/script
/body
/html!DOCTYPE html
html langen
headmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/title
/head
bodydiv idappbutton clickfn()切换显示隐藏/buttonh1 v-showisShow小吴在敲Bug/h1/divscript srchttps://cdn.jsdelivr.net/npm/vue2.7.14/dist/vue.js/scriptscriptconst app new Vue({el: #app,data: {isShow:true},methods:{fn(){this.isShow!this.isShow}}})/script
/body
/htmlv-bind
作用动态的设置html的标签属性语法v-bind:属性名“表达式”注意简写形式 :属性名“表达式” 代码演示
!DOCTYPE html
html langen
headmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/title
/head
bodydiv idappimg v-bind:srcimgUrl v-bind:titlemsg altimg :srcimgUrl :titlemsg alt/divscript srchttps://cdn.jsdelivr.net/npm/vue2.7.14/dist/vue.js/scriptscriptconst app new Vue({el: #app,data: {msg:波仔喝奶茶,imgUrl:./imgs/10-02.png}})/script
/body
/htmlv-bind对于样式控制的增强 为了方便开发者进行样式控制Vue扩展了v-bind的语法可以针对class类名和style行内样式进行控制。 语法 :class对象/数组 对象 —— 键就是类名值是布尔值。如果值为true有这个类否则没有这个类 div classbox :class{类名1:布尔值,类名2:布尔值}/div数组 —— 数组中所有的类都会添加到盒子上本质就是一个class列表 div classbox :class[类名1,类名2,类名3]/divv-for
作用基于数据循环多次渲染整个元素语法v-for “(item,index) in 数组” item每一项index下标 代码演示
!DOCTYPE html
html langen
headmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/title
/head
bodydiv idapph3小黑水果店/h3ulli v-for(item, index) in list{{ item }} - {{ index }}/li/ululli v-foritem in list{{ item }}/li/ul/divscript srchttps://cdn.jsdelivr.net/npm/vue2/dist/vue.js/scriptscriptconst app new Vue({el: #app,data: {list: [西瓜, 苹果, 鸭梨, 榴莲]}})/script
/body
/htmlv-for中的key
语法:key属性 “唯一标识”作用给列表项添加的唯一标识。便于Vue进行列表项的正确排序复用注意点 key的值只能是字符串或数字类型key的值必须具有唯一性推荐使用id作为key唯一不推荐使用index作为key会变化不对应
v-model
作用给表单元素使用双向数据绑定 —— 可以快速获取或设置表单元素内容 数据变化 —— 视图自动更新视图变化 —— 数据自动更新 语法v-model“变量” 代码演示
!DOCTYPE html
html langen
headmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/title
/head
bodydiv idapp!-- v-model 可以让数据和视图形成双向数据绑定(1) 数据变化视图自动更新(2) 视图变化数据自动更新可以快速[获取]或[设置]表单元素的内容--账户input typetext v-modelusername brbr密码input typepassword v-modelpassword brbrbutton clicklogin登录/buttonbutton clickreset重置/button/divscript srchttps://cdn.jsdelivr.net/npm/vue2/dist/vue.js/scriptscriptconst app new Vue({el: #app,data: {username: ,password: },methods: {login () {console.log(this.username, this.password)},reset () {this.username this.password }}})/script
/body
/html指令修饰符
通过“.”指明一些指令后缀不同后缀封装了不同的处理操作简化代码
按键修饰符 keyup.enter —— 键盘回车监听 v-model修饰符 v-model.trim —— 去除首尾空格v-model.number —— 转数字 事件修饰符 事件名.stop —— 阻止冒泡事件名.prevent —— 阻止默认行为
计算属性
概念基于现有的数据计算出来的新属性。依赖的数据变化自动重新计算 语法
声明在 computed配置项 中一个计算属性对应一个函数使用起来和普通属性一样使用{ { 计算属性名 } }
computed: {计算属性名() {基于现有的数据编写求值逻辑return 结果}
}computed计算属性 VS methods方法
computed计算属性 作用封装了一段对于数据的处理求得一个结果语法 写在 computed 配置中作为属性直接使用 —— this.计算属性 | { { 计算属性 } } 缓存特性提升性能 计算属性会对计算出来的 结果缓存 再次使用直接读取缓存依赖项变化了会 自动 重新计算并 再次缓存 methods方法 作用给实例提供一个方法调用以处理业务逻辑语法 写在 methods 配置项中作为方法需要调用 —— this.方法名() | 事件名“方法名” 计算属性完整写法 计算属性默认的简写只能读取访问 不能修改 如果要 修改 需要写计算属性的 完整写法
computed: {计算属性名: {get(){一段逻辑代码return 结果},set(修改的值){一段逻辑代码}}
}watch侦听器监视器
作用监视数据变化执行一些业务逻辑或异步操作
watch——简写
data:{words: 苹果
},
watch: {// 该方法会在数据变化时触发执行words —— 数据属性名(newValue,oldValue){一些业务逻辑 或 异步操作},对象.属性名(newValue,oldValue){一些业务逻辑 或 异步操作}
}watch——完整写法
deep: true 对复杂类型深度监视immediate: true 初始化立刻执行一次 handler方法
watch: {数据属性名:{ //数据属性是对象deep: true, //深度监视对对象里的所有子属性进行监视immediate: true // 立刻执行打开页面就马上执行一次handler(newValue,oldValue){一些业务逻辑 或 异步操作}
}Vue生命周期 和 生命周期的四个阶段
Vue生命周期一个Vue实例从创建到销毁的整个过程 生命周期四个阶段
创建响应式数据挂载渲染模版更新数据修改跟新视图销毁关闭浏览器
Vue生命周期函数钩子函数
Vue生命周期过程中会自动运行一些函数被称为生命周期钩子让开发者可以在特定阶段运行自己的代码
// 1.创建阶段准备数据
beforeCreate(){console.log(beforeCreate 响应式数据准备好之前)
},
created(){console.log(create 响应式数据准备好之后)
},
// 2.挂载阶段渲染模板
beforeMount(){console.log(beforeMount 模板渲染之前)
},
mounted(){console.log(mounted 模板渲染之后)
},
// 3.更新阶段
beforeUpdate(){console.log(beforeUpdate 数据修改了视图还没更新)
},
updated(){console.log(updated 数据修改了视图已经更新 )
},
// 4.卸载阶段
beforeDestroy(){console.log(beforeDestroy)
},
destroyed(){console.log(destroyed)
}工程化开发
开发Vue的两种方式
核心包传统开发模式基于html/css/js文件直接引入核心包开发Vue工程化开发模式基于构建工具webpack的环境中开发Vue
脚手架 Vue cli
基本介绍
Vue cli 是 Vue 官方提供的一个全局命令工具可以帮助我们快速创建一个开发 Vue 项目的标准化基础架子集成了web怕吃苦配置
好处
开箱既用零配置内置babel等工具标准化 使用步骤
全局安装一次 npm i vue/cli -g查看 Vue 版本 vue --version创建项目架子 vue create 项目名称 项目名不能用中文启动项目 npm run serve 找package.json
脚手架目录文件介绍 组件化开发
组件化 一个页面可以拆分成 一个个组件 每个组件有着自己独立的 结构 、样式 、行为好处便于维护利于复用 —— 提升开发效率组件分类普通组件、根组件 根组件 整个应用 最上层 的组件包裹了所有普通小组件 - template 结构 - style 样式可以支持less需要安装less和less-loader - script 行为
普通组件的注册使用
组件注册的两种方式
局部注册只能在注册的组件内使用 创建.vue文件在使用的组件内导入并注册 全局注册所有组件内部都能使用 创建.vue文件main.js 中进行全局注册 使用 当成html标签使用 组件名/组件名 注意 组件命名规范 —— 大驼峰命名法
scoped样式冲突
默认情况 写在组件中的样式会 全局生效 因此很容易造成多个组件之间的样式冲突问题 全局样式 默认组件中的样式会作用到全局 局部样式 可以给组件加上 scoped 属性 可以让样式只作用于当前组件 style scoped/style组件通信
组件通信就是指 组件与组件 之间的数据传递
组件的数据是 独立 的无法直接访问其他组件的数据想用其他组件的数据 —— 组件通信 组件关系分类
父子关系非父子关系 组件通信解决方案 父子通信流程图 父组件通过 props 将数据传递给子组件 子组件利用 $emit 通知父组件修改更新 prop
prop定义组件上 注册的一些 自定义属性 prop作用向子组件传递数据 特点
可以传递 任意数量 的prop可以传递 任意类型 的prop props校验
作用 为组件的prop指定 验证要求不符合要求控制台就会有 错误提示 语法 类型校验 props:{校验的属性名:类型 // 类型有 Number String Boolean Array Object Function
}非空校验 默认值 自定义校验 props:{校验的属性名:{type: 类型, // 类型有 Number String Boolean Array required: true, // 是否必填default: 默认值, // 默认值validator (value) { // 形参可以接受到传过来的值// 自定义校验逻辑return 是否通过校验 // true 通过校验 false 不通过校验}}
}非父子通信
作用 非父子组件之间进行简易消息传递 事件总线 创建一个都能访问到的事件总线空Vue实例 import Vue from vue
const Bus new Vue()
export default BusA 组件接收方监听 Bus 实例 的事件 created(){Bus.$on(sendMsg,(msg) {this.msg msg})
}B组件发送方触发 Bus 实例 的事件 Bus.$emit(sendMsg,这是一个消息)provide inject provide inject作用跨层级 共享数据 父组件provide提供数据 export default {provide() {return {// 普通类型【非响应式】color: this.color,// 复杂类型【响应式】userInfo: this.userInfo}}
}子/孙组件inject取值使用 export default {inject: [color,userInfo]created(){console.log(this.color,this.userInfo)}
}表单类组件封装
表单类组件封装
父传子数据应该是在父组件 props 传递过来的v-model 拆解 绑定数据子传父监听输入子传父传值给父组件修改 v-model简化代码
父组件v-model 简化代码实现子组件与父组件数据 双向绑定
子组件中props通过 value 接收事件触发 input父组件中 v-model 给组件直接绑定数据
.sync修饰符
作用可以实现子组件与父组件数据的双向绑定 特点prop属性名可以自定义非固定为value 本质就是:属性名和update:属性名和写
BaseDialog :visble.syncisShow /ref和$refs
作用利用ref和$refs可以用于获取dom元素或组件实例 特点查找范围 —— 当前组件内更精确稳定 获取dom 目标标签 —— 添加 ref 属性div refchartRef我是渲染图表的容器/div恰当时机通过this.$refs.xxx获取目标标签mounte(){console.log(this.$refs.chartRef)
}获取组件 目标组件 —— 添加ref属性BaseForm refbaseForm/BaseForm恰当时机通过this.$refs.xxx获取目标组件就可以 调用组件对象里面的方法this.$refs.baseForm.组件方法()Vue异步更新、$nextTick
$nextTick等DOM更新后才会触发执行此方法的函数体 语法 this.$nextTick(函数体)
this.$nextTick(() {// 业务逻辑
})自定义指令
自定义指令自己定义的指令可以封装一些DOM操作扩展额外功能 全局注册 —— 语法main.js中编写语句 Vue.directive(指令名,{// inserted 会在指令所在的元素被插入到页面中时触发inserted (el){// 可以对 el 标签扩展额外功能el.focus()}
})局部注册 —— 语法 directives:{指令名:{inserted(el){// 可以对 el 标签扩展额外功能el.focus()}}
}使用 input v-指令名 typetext插槽 作用让组件内部的一些结构支持自定义 默认插槽
插槽基本语法
组件内需要定制的结构部分改用slot/slot占位使用组件时组件名/组件名标签内部传入结构替换slot 插槽后备内容默认值
插槽后备内容封装组件时可以为预留的slot插槽提供后备内容默认值
语法在slot标签内放置内容作为默认值 效果 外部使用组件时不传东西则slot会显示默认值组件名/组件名外部使用组件时传东西了则slot整体会换掉组件名传的新内容/组件名具名插槽
具名插槽语法
多个slot使用name属性区分名字 template配合v-slot:名字来分发对应标签 v-slot:插槽名可以简化成#插槽名
作用于插槽
基本使用步骤 给slot标签以添加属性的方式传值 slot :iditem.id msg测试文本/slot所有添加的属性都会被收集到一个对象中 {id: 3, msg: 测试文本}咋提template中通过#插槽名obj接收默认插槽名为default MyTable :listlisttemplate #defaultobjbutton clickdel(obj.id)删除/button/template
/MyTable路由
VueRouter的介绍
作用修改地址栏路径时切换显示匹配的组件 说明Vue官方的一个路由插件是一个第三方包 官网
VueRouter的使用52
五个基本步骤main.js 下载下载VueRouter模板到当前工程 npm install vue-router3.6.5引入 import VueRouter from vue-router安装注册 Vue.use(VueRouter)创建路由对象 const router new VueRouter()注入将路由对象注入到new Vue实例中建立关联 new Vue({render: h h(App),router
}).$mount(#app)2个核心步骤 创建需要的组件views目录配置路由规则 const router new VueRouter({// routers 路由规则们// router 一条路由规则{path: 路径, component: 组件}routes: [{path: /find, component: Findchildren:[{ //子路由path: 路由路径,component: 组件名}]},{path: /my,component: My},{path: /friend,component: Friend}]
})配置导航配置路由出口路径匹配的组件显示的位置 templatedivdiv classfooter_wrapa href#/find发现音乐/aa href#/my我的音乐/aa href#/friend朋友/a/divdiv classtop!-- 路由出口 → 匹配的组件所展示的位置 --router-view/router-view/div/div
/template路由的封装抽离 问题所有的路由配置都堆在main.js中不合适 目标将路由模块抽离出来 好处拆分模块利于维护 创建router\index.js目录与文件 在index.js文件中编写路由规则 import Find from /views/Find;
import My from /views/My;
import Friend from /views/Friend;import Vue from vue;
import VueRouter from vue-router;
Vue.use(VueRouter) //VueRouter插件初始化const router new VueRouter({// routers 路由规则们// router 一条路由规则{path: 路径, component: 组件}routes: [{path: /find, component: Find},{path: /my,component: My},{path: /friend,component: Friend}]
})// 导出router
export default router在main.js文件中引用
使用router-link声明式导航
vue-router提供了一个全局组件router-link取代了a标签
能跳转配置to属性指定路径必须本质还是a标签to无需#能高亮默认就会提供高亮类名可以直接设置高亮样式 router-link —— 两个类名 router-link-active 模糊匹配常用 to“/my” 可以匹配 /my /my/a /my/b ……router-link-exact-active 精确匹配 to“/my” 仅可以匹配 /my 自定义匹配类名
说明router-link的两个类名太长了我们可以自定义匹配类名
const router new VueRouter({// routers 路由规则们// router 一条路由规则{path: 路径, component: 组件}routes: [ …… ]林肯ActiveClass: 精确匹配的类名,linkExactActiveClass: 模糊匹配的类名
})声明式导航——跳转传参
目标在跳转路由时进行传值
查询参数传参 语法to/path?参数名值参数名n值n对应页面组件接收传递过来的值$router.query.参数名 动态路由传参 配置动态路由path:/path/:参数名 /path/:参数名必须要传参数如果不传参数也希望匹配可以加个可选符 ?/path/:参数名?const router new VueRouter({routes: [{ path: /search/:words, component: Search }]
})配置导航链接to/path/参数值对应页面组件接收传递过滤的值$route.params.参数名
重定向
问题网页打开url默认是/路径未匹配到组件时会出现空白 重定向匹配到path后强制跳转path路径 语法 {path: 匹配路径,redirect: 重定向到的路径}
const router new VueRouter({routes: [{path: /,redirect: /home},{path: /home, component: Home},{path: /search, component: Search}]
})404页面设置
作用 当路径找不到匹配时给个提示页面 位置 配在路由最后 语法path:“*”任意路径—— 前面的路由不匹配就匹配最后一个
const router new VueRouter({routes: [{path: /,redirect: /home},{path: /home, component: Home},{path: /search, component: Search},{path: *,component: NotFind}]
})路由模式
问题路由的路径看起来不自然有#能否切换成真正的路径形式
hash路由默认例如http://localhost:8080/#/homehistory路由常用例如http:/localhost:8080/home
const router new VueRouter({routes: [ …… ]mode: history
})编程式导航
问题点击按钮跳转如何实现 编程式导航用JS代码来进行跳转
基本跳转 path路径跳转简易方便 this.$router.push(路由路径)this.$router.push({path: 路由路径
})name命名路由跳转适合path路径长的场景 this.$router.push({name: 路由名
}){name: 路由名,path: /path,component: 组件名}路由传参 两种传参方式查询参数动态路由传参 两种跳转方式对于两种传参方式都支持 path路径跳转传参query传参 this.$router.push(路由路径?参数名1参数值1参数名2参数值2)this.$router.push({path: 路由路径query:{参数名1: 参数值1,参数名2: 参数值2}
})path路径跳转传参动态路由传参 this.$router.push(路由路径/参数值)this.$router.push({path: 路由路径/参数值
})name命名路由跳转传参query传参 this.$router.push({path: 路由名query:{参数名1: 参数值1,参数名2: 参数值2}
})name命令路由跳转传参动态路由传参 this.$router.push({path: 路由名params:{参数名: 参数值}
})组件缓存keep-alive 使用keep-alive包裹路由出口可以使得切换组件时上一个组件不会被销毁 keep-aliverouter-view/router-view
/keep-alivekeep-alive的三个属性 include组件名数组只有匹配的组件会被缓存exclude组件名数组任何匹配的组件都不会被缓存max最多可以缓存多少组件实例 keep-alive :include[组件名1,组件名2]
router-view/router-view
/keep-alive两个钩子 activated进入页面钩子deactivated离开页面钩子
ESlint代码规范
代码规范一套写代码的约定规则 老话说“没有规矩不成方圆” —— 正规的团队需要统一的编码风格 如果你的代码不符合standard的要求ESlint会跳出来刀子嘴豆腐心提示你
JavaScript Standard Style 规范说明
字符串使用单引号‘abc’无分号const name ‘xw’关键字后加空格if (name ‘ls’) { ···}函数名后加空格 function name (arg) { ··· }坚持使用全等 摒弃 …… 代码规范错误解决方案
手动修正 更具错误提示一项一项手动修改纠正如果不认识命令行中的语法报错是什么意思根据错误代码去ESlint规则表中查找其具体含义 自动修正 快捷修复右键点击唤出快捷菜单点击“Fix ESLint Problems。
vuex
概述
vuex是一个vue的状态管理工具状态就是数据 大白话vuex是一个插件可以帮我们管理vue通用的数据多组件共享的数据 场景
某个状态在很多个组件来使用个人信息多个组件共同维护一份数据购物车 优势
共同维护一份数据数据集中化管理响应式变化操作简洁vuex提供了一些辅助函数
创建一个空仓库
多组件共享的数据环境
目标安装vuex插件初始化一个空仓库 npm install vuex3 新建 store/index.js专门存放vuex Vue.use(Vuex) 创建创库 new Vuex.Store() // 这里存放的就是 vuex的相关核心代码
import Vue from vue
import Vuex from vuex// 插件安装
Vue.use(Vuex)// 创建仓库空仓库
const store new Vuex.Store()// 导出给main.js使用
export default store在main.js中导入挂载到Vue实例上
提供与访问vuex的数据 目标明确如何给仓库提供数据如何使用仓库数据 提供数据 State提供唯一的公共数据源所有共享的数据都要统一放到Store中的State中存储。在State对象中可以添加我们要共享的数据 // 创建仓库
const store new Vuex.Store({// state状态即数据类似于Vue组件中的data/*区别1.data是自己的数据2.State是所有组件共享的数据*/state: {count: 100}
})使用数据 通过store直接访问获取 store
1this.$store
2import 导入 store模板中{{$store.state.xxx}}
组件逻辑中this.$store.state.xxx
JS模块中store.state.xxx通过辅助函数简化 mapState是辅助函数帮助我们把store中的数据自动映射到组件的计算属性中 import { mapState } from vuexmapState([count])computed: { ...mapState([count]) } 修改vuex的数据 目标明确vuex同样是遵循单向数据流组件中不能直接修改仓库的数据 通过strict: true 可以开启严格模式项目上线移除掉会吃性能
// 创建仓库空仓库
const store new Vuex.Store({// 开启严格模式strict: true,// state状态即数据类似于Vue组件中的data/*区别1.data是自己的数据2.State是所有组件共享的数据*/state: {title: 大标题,count: 100}
})mutations 目标掌握mutations的操作流程来修改state数据state数据的修改只能通过mutations 定义mutations对象对象中存放修改state的方法 const store new Vuex.Store({state: {title: 大标题,count: 100}// 定义mutationsmutations: {// 第一个参数是当前store的state属性addCount (state){state.count 1}}
})组件中提交调用mutations this.$store.commit(addCount)mutations传参语法 提供 mutation 函数带参数 —— 提交载荷 payload mutations: {...addCount (state, n) {state.count n}
}页面中调用 mutation this.$store.commit(addCount, 10)辅助函数mapMutationsmapMutations 和 mapState 很像它是把位于mutations中的方法提取出来映射到组件methods中
mutations: {subCount (state, n) {state.count - n}
}import { mapMutations } from vuexmethods: {...mapMutations([subCount])
}this.subCount(10) //JS中调用actions 目标明确 actions 的基本语法处理异步操作 说明mutations 必须是同步的便于检测数据变化记录调试 提供actions方法 actions: {setAsyncCount (context, num) {// 一秒钟后给一个数去修改 numsetTimeout(() {context.commit(changeCount, num)}, 1000)}
}页面中 dispatch 调用 this.$store.dispatch(setAsyncCount, 200)辅助函数mapActions 目标掌握辅助函数 mapActions映射方法 mapAction 是把位于actions中的方法提取出来映射到组件methods中 actions: {setAsyncCount (context, num) {// 一秒钟后给一个数去修改 numsetTimeout(() {context.commit(changeCount, num)}, 1000)}
}import { mapActions } from vuexmethods: {...mapActions([setAsyncCoun])
}this.setAsyncCoun(666) //调用getters 目标掌握核心概念 getters 的基本语法类似于计算属性 说明除了state之外有时我们还需要从state中派生出一些状态这些状态是依赖state的此时会用到getters 例如state 中定义了list为1-10的数组组件中需要显示所有大于5的数据
state: {list: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
}定义 getters getters: {/*注意1 getters函数的第一个参数是 state2getters函数必须要有返回值*/filterList (state) {return state.list.filter(item item 5)}
}访问getters 通过store访问getters {{ $store.getters.filterList }}通过辅助函数 mapGetterrs映射 import { mapGetters } from vuexcomputed: {...mapGetters([filterList])
}{{ filterList }} //使用模块module进阶语法 由于vuex使用单一状态树应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时store对象就有可能变得相当臃肿当项目变得越来越大的时候vuex会变得越来越难以维护 模块拆分
user模块store/modules/user.js 创建文件 编写模块 // user模块
const state {userInfo: {name: zhangsan,age: 18},score: 80
}
const mutations {}
const actions {}
const getters {}// 导出模块
export default {state,mutations,actions,getters
}导入和挂载 import user from /store/modules/user
const store new Vuex.Store({modules: {user}
})访问模块中的state 尽管已经分模块了但其实子模块的状态还是会挂到根级别的state中属性名就是模块名 使用模块中的数据
直接通过模块名访问 $store.state.模块名.xxx通过mapState映射 默认根级别的映射 mapState([xxx])子模块的映射 mapState(模块名,[xxx]) 需要开启命名空间export default {namespaced: true, // 开启命名空间state,mutations,actions,getters
}使用模块中getters中的数据
直接通过模块名访问**$store.getters[模块名/xxx]**通过mapGetters映射 默认根级别的映射 mapGetters([xxx])子模块的映射 mapGetters(模块名,[xxx] 需要开启命名空间export default {namespaced: true, // 开启命名空间state,mutations,actions,getters
}调用子模块中mutation 注意默认模块中的 mutation 和 actions 会被挂载到全局需要开启命名空间才会挂载到子模块 直接通过 store 调用 $store.commit(模块名/xxx,额外参数)通过 mapMutations 映射 默认根级别的映射 mapMutations([xxx])子模块的映射 mapMutations(模块名,[xxx]) 需要开启命名空间export default {namespaced: true, // 开启命名空间state,mutations,actions,getters
}调用子模块中action 注意默认模块中的 mutation 和 actions 会被挂载到全局需要开启命名空间才会挂载到子模块 直接通过 store 调用 $store.dispatch(模块名/xxx,额外参数)通过 mapMutations 映射 默认根级别的映射 mapActions([xxx])子模块的映射 mapActions(模块名,[xxx]) 需要开启命名空间export default {namespaced: true, // 开启命名空间state,mutations,actions,getters
}Vue3快速入门
Vue3的优势 Vue3 组合式API vs Vue2 选项式 API 代码量变少了 分散式维护转为集中式维护更容易封装复用 需求单击按钮让数字1 选项式API script
export default {data () {return {count: 0}}methods: {addCount () {this.count}}
}
/script组合式API script setup
import [ ref } from vue
const count ref(0)
const addCount () count.value
/script创建Vue3项目 create-vue是Vue官方新的脚手架工具底层切换到了 vite下一代构建工具为了开发提供极速响应 前提环境条件已安装 16.0 或更高版本的 Node.js
创建一个Vue应用npm init vuelatest这一指令将会安装并执行create-vue 项目目录 关键文件
vite.config.js —— 项目的配置文件 基于vite的配置package.json —— 项目包文件 核心依赖项变成了 Vue3.x 和 vitemain.js —— 入口文件 createApp函数创建应用实例app.vue —— 根组件 SFC单文件组件 script - template - style 变化一脚本script和模板template顺序调整变化二模板template不再要求唯一根元素变化三脚步script添加setup标识支持组合式API Index.html —— 单页入口 提供id为app的挂载点
组合式API —— setup选项
setup选项的写法和执行时机 setup选项中写代码的特点 script setup 语法糖
组合式API —— reactive 函数
作用接受对象类型数据的参数传入并返回一个响应式的对象 核心步骤
script setup
// 导入
import { reactive } from vue// 执行函数传入参数变量接收
const state reactive(对象类型数据)/script从 vue 包中导入 reactive 函数在script setup 中执行 reactive 函数并传入类型为对象的初始值并使用变量接收返回值
组合式API —— ref 函数
作用接受简单类型或者对象类型的数据传入并返回一个响应式的对象 核心语法
script setup
// 导入
import { ref } from vue// 执行函数传入参数变量接收
const state ref(简单类型或者复杂类型数据)/script从 vue 包中导入 ref 函数在 script setup 中执行 ref 函数并传入初始值使用变量接收 ref 函数的返回值ref参数类型支持更好但是必须通过 .value 访问修改
组合式API —— computed 计算属性基本思想和Vue2的完全一致组合式API下的计算属性只是修改了写法 核心步骤
script setup
// 导入
import { computed } from vue// 执行函数 变量接收 在回调参数中return计算值
const computedState computed( () {return 基于响应式数据做计算之后的值
})
/script导入computed函数执行函数在回调参数中return基于响应式数据计算的值用变量接收 计算属性Demo
script setup
import {computed, ref} from vue;// 声明数据
const list ref([1,2,3,4,5,6,7,8])// 基于list派生一个计算属性从list中过滤出 2
const computedList computed((){return list.value.filter((item) item2 )
})// 定义一个修改数组的方法
const addFn () {list.value.push(307)
}
/scripttemplatedivdiv原始数据{{list}}/divdiv计算后的数据{{computedList}}/divbutton clickaddFn修改/button/div
/template最佳实践
计算书中不应该有“副作用” 比如异步请求/修改DOM 避免直接修改计算属性的值 计算属性应该是只读的特殊情况可以配置 get set
组合式API —— watch 作用侦听一个或者多个数据的变化数据变化时执行回调函数 两个额外参数1. immediate立即执行 2.deep深度侦听 监听单个数据
导入watch函数执行watch函数传入要侦听的响应式数据ref对象和回调函数
script setup
// 1.导入watch
import { ref, watch } from vue
const count ref(0)// 2.调用watch 侦听变化
watch(count,(newValue, oldValue) {console.log(count发生了变化老值为${oldValue}新值为${newVaule})
})
/script监听多个数据 说明同时监听多个响应式数据的变化不管哪个数据变化都需要执行回调函数 script setup
// 1.导入watch
import { ref, watch } from vue
const count ref(0)
const name ref(cp)// 2.调用watch 侦听变化
watch([count, name],// watch([ref对象1,ref对象2], (newArr, oldArr) { …… })(count,([newCount, newName], [oldCount, oldName]) {console.log(count或者name发生了变化[newCount, newName], [oldCount, oldName])}
)
/scriptimmediate 说明在侦听器创建时立即出发回调响应式数据变化之后继续执行回调 script setup
// 1.导入watch
import { ref, watch } from vue
const count ref(0)// 2.调用watch 侦听变化
watch(count,(newValue, oldValue) {console.log(count发生了变化老值为${oldValue}新值为${newVaule})}, {immediate: true}
)
/scriptdeep 说明deep深度监视默认watch进行的是浅层监视 coust ref1 ref(简单类型) 可以直接监视 coust ref2 ref(复杂类型) 监视不到复杂类型内部数据的变化 script setup
const userInfo ref({name: 张三,age: 18
})watch(userInfo, (newValue, oldValue) {console.log(newValue, oldValue)
},{deep: true,immediate: true
})
/script精确侦听对象的某个属性 需求在不开启deep的前提下侦听age的变化只有age变化时才执行回调 const info ref({name: xw,age: 21
})
watch(() info.value.age,(newValue, oldValue) console.log(age发生变化了)
)组合式API —— 生命周期函数
Vue3 的生命周期API选项式 VS 组合式
选项式API组合式APIbeforeCreate/createdsetupbeforeMountOnBeforeMountmountedonMountedbeforeUpdateonBeforeUpdateupdatedonUpdatedbeforeUnmountonBeforeUnmountunmountedonUnmounted
组合式API —— 父子通信
组合式API下的父传子
父组件中给子组件绑定属性子组件内部通过props选项接收 组合式API下的子传父
父组件中给子组件标签通过绑定事件子组件通过emit方法触发事件
组合式API —— 模板引用 通过ref标识获取真实的dom对象或者组件实例对象 调用ef函数生成一个ref对象通过ref标识绑定ref对象到标签
script setup
import { ref } from vue
// 1.调用ref函数得到ref对象
const h1Ref ref(null)
/scripttemplate
!-- 2.通过ref标识绑定ref对象 --
h1 refh1Ref我是dom标签h1/h1
/templatedefineExpose()
默认情况下在script setup语法糖下组件内部的属性和方法是不开放给父组件访问的可以通过defineExpose编译宏指定哪些属性和方法是允许访问 组合式API —— provide 和 inject 作用和场景顶层组件向任意的底层组件传递数据和方法实现跨层组件通信 跨层传递普通数据
顶层组件通过provide函数提供数据底层组件通过inject函数获取数据 跨层传递响应式数据
在调用provide函数时第二个参数设置为ref对象 跨层传递方法
顶层组件可以向底层组件传递方法底层组件调用方法修改顶层组件中的数据
新特性 —— defineOptions 有 script setup 之前如果要定义 propsemits 可以轻而易举地添加一个与 setup 平级的属性。但是有了 script setup 后就没法这么干了 setup 属性已经没有了自然无法添加与其平级的属性 为了解决这一问题引入了 defineProps 与 defineEmits 这两个宏。但这只解决了 props 与 emits 这两个属性。如果我们要定义组件的 name 或其他自定义的属性还是得回到最原始的用法——再添加一个普通script标签。这样就会存在两个script标签。让人无法接受 所以在Vue 3.3 中引入了 defineOptions 宏。顾名思义主要是用来定义 Options API 的选项。可以用defineOptions 定义任意的选项 propsemitsexposeslots厨卫因为这些可以使用 defineXXX 来做到
script setup
defineOptions({name: Foo,inheritAttrs: false// ... 更多自定义属性
})
/script新特性 —— defineModel 在Vue3中自定义组件上使用v-model相当于传递一个modelValue属性同时触发 update:modelValue 事件 Chile v-modelisVisible
// 相当于
Child :modelValueisVisible update:modelValueisVisible$eventscript setup
const modelValue defineModel()
modelValue.value
/scriptPinia Pinia 是 Vue 的最新 状态管理工具是 Vuex 的代替品 提供更加简单的API去掉了 mutation提供符合组合式风格的API和Vue3新语法统一去掉了 modules 的概念每一个 store 都是要给独立的模板配合 TypeScript 更加友好提供可靠的类型推断
手动添加Pinia到Vue项目 使用 Vite 创建一个空的 Vue3 项目 npm create vuelatest按照官方文档 安装 pinia 到项目中 import {createApp} from vue
import {createPinia} from pinia
import App from ./App.vueconst pinia createPinia() // 创建Pinia实例
const app createApp(App) // 创建根实例
app.use(pinia) // Pinia插件的安装配置
app.mount(#app) // 视图挂载Pinia基础使用 —— 计数器案例 创建一个创库 store/counter.js 定义store import { defineStore } from pinia
import {computed, ref} from vue;// 定义store
// defineStore(仓库的唯一标识, () { ... })export const useCounterStore defineStore(counter, () {// 声明数据 state —— countconst count ref(0)// 声明操作数据的方法 actionsconst addCount (add) count.valueadd// 声明基于数据派生的计算属性 gettersconst double computed(() count.value*2)// 声明数据 state —— msgconst msg ref(hello pinia)return {count,addCount,double,msg}
})组件使用store script setup
import { useCounterStore } from /store/counter
const counterStore useCounterStore() // 声明实例
/scripttemplatediv我是Son1.vue - {{counterStore.count}} - {{counterStore.double}}button clickcounterStore.addCount(5)/button/div/templateaction异步实现
编写方式异步action函数的写法和组件中获取异步数据的写法完全一致
接口地址http://geek.itheima.net/v1_0/channels
需求再Pinia中获取频道列表数据并把数据渲染App组件模板中 创建一个创库 store/channel.js 定义 store import { defineStore } from pinia
import {ref} from vue;
import axios from axios;export const useChannelStore defineStore(channel, () {// 声明数据const channelList ref([])// 声明操作数据的方法const getList async () {const {data: { data }} await axios.get(http://geek.itheima.net/v1_0/channels)channelList.value data.channelsconsole.log(data.channels)}// 声明getters相关return {channelList,getList}
})组件使用store
storeToRefs方法 请注意store 是一个用 reactive 包装的对象这意味着不需要在 getters 后面写 .value就像 setup 中的 props 一样如果你写了我们也不能解构它 为了从 store 中提取属性时保持其响应性你需要使用 storeToRefs()。它将为每一个响应式属性创建引用。当你只使用 store 的状态而不调用任何 action 时它会非常有用。请注意你可以直接从 store 中解构 action因为它们也被绑定到 store 上 注意方法不需要使用storeToRefs方法解构直接解构即可
Pinia持久化插件
官方文档 安装插件 pinia-plugin-persistedstate npm i pinia-plugin-persistedstate在main.js中导入使用 import {createApp} from vue
import App from ./App.vue
import {createPinia} from pinia
// 导入持久化插件
import piniaPluginPersistedstate from pinia-plugin-persistedstateconst pinia createPinia() // 创建Pinia实例
const app createApp(App) // 创建根实例
app.use(pinia.use(piniaPluginPersistedstate)) // Pinia插件的安装配置
app.mount(#app) // 视图挂载store仓库中persist: true开启