十、vue基础
2022前端知识整理:第十部分、vue基础,仅包含vue2.0相关知识,建议先完成html5、css3和JavaScript ES6之后再学习。
1、webpack
①webpack基本概念
webpack是静态模块打包工具,它可以减少文件数量,缩减代码体积,提高网页打开速度,主要作用是分析压缩和打包代码。
②webpack使用步骤
初始化包环境
yarn init
安装依赖包
yarn add webpack@5.31.2 webpack-cli@4.6.0 -D
配置scripts
"scripts":{
"build":"webpack"
},
打包命令
yarn build
③webpack的配置
配置文档
https://webpack.docschina.org/concepts/#entry
在webpack.config.js中,填入入口和出口配置
const path = require('path')
modules.exports = {
//入口文件名
entry: './src/main.js',
output: {
//出口路径
path: path.resolve(__diename, 'dist'),
//出口文件名
filename:'bundle.js',
}
}
配置插件
自动生成HTML的插件:
下载插件
yarn add html-webpack-plugin@5.3.1 -D
webpack.config.js添加配置
const HtmlWebpackPlugin = require(`html-webpack-plugin')
module.exports ={
plugins:[
new HtmlWebpackPlugin({
templete:'./public/index.html'
})
]
}
处理css文件:
下载插件
yarn add css-loader@5.2.1 style-loader@2.0.0 -D
webpack.config.js添加配置
module.exports = {
mopdule:{
rules:[
{
test:/\.css$/i,
//css-loader:识别.css文件,style-loader:把js内样式插入DOM上
use:["style-loader","css-loader"]
}
]
}
}
处理less文件:
下载插件
yarn add less@4.1.1 less-loader@8.1.0 D
webpack.config.js添加配置
module.exports = {
mopdule:{
rules:[
{
test:/\.css$/i,
//less-loader:识别.less文件,less-loader:把less语法翻译成css
use:["style-loader","css-loader","less-loader"]
}
]
}
}
处理图片文件:
复制assets/图片文件,然后css/index.less小图片做背景,src/main.js大图片img插入到DOM,最后在webpack.config.js添加配置
module.exports = {
mopdule:{
rules:[
{
test:/\.(png|jpg|gif|jpeg)$/i,
type:'asset'
}
]
}
}
图片处理规则:webpack5内置资源模块打包,默认小于8KB的图片会被转为base64字符串,这样可减少网络请求次数,大于8KB的图片仍然复制文件,这样可以避免增大文件体积
处理字体文件:
复制assets/字体文件夹fonts,然后css/main.js引入字体样式inconfont.css,src/main.js中创建i标签使用字体图标,最后在webpack.config.js中配置规则
module.exports = {
mopdule:{
rules:[
{
test:/\.(eot|svg|ttf|woff|woff2)$/,
type:'asset/resource',
generator: {
filename: 'font/[name].[hash:6][ext]'
}
}
]
}
}
字体处理规则:webpack5内置资源模块打包,字体文件会被直接复制到dist目录下,不会打包进js文件中
处理高版本兼容性语法:
为了兼容低版本浏览器,我们可以使用babel-loader加载器来处理,首先在src/main.js – 定义箭头函数, 并打印箭头函数变量 (千万不能调用, 为了让webpack打包函数, 看降级效果);然后下载加载器yarn add babel-loader@8.2.2 @babel/core@7.13.15 @babel/preset-env@7.13.15 -D,再配置到webpack.config.js上,最后打包观察是否降级
module.exports = {
mopdule:{
rules:[
{
test: /\.js$/,
exclude: /(node_moudles|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presents: ['@babel/preset-env']
}
}
}
]
}
}
降级处理规则:下载@babel/core和babel-loader等模块包,@babel/core是js编译器,负责分析代码,@babel/preset-env是babel预设,用来设置降级规则,babel-loader可以让webpack翻译js代码
④webpack开发服务器
搭建webpack开发服务器
搭建webpack开发服务器,可以将处理好的内容放入内存,以后代码有了变化,打包的时候只重新打包变化的代码,并自动更新到页面。
首先下载模块包
yarn add webpack-dev-serve@3.11.2 -D
然后在package.json中自定义webpack开发服务器启动命令serve
"script": {
"build": "webpack",
"serve": "webpack serve"
},
再到终端窗口启动当前工程里的webpack开发服务器
yarn serve
最后重新编写代码,看看控制台是否自动打包,浏览器是否自动更新
配置webpack服务器
想要改变端口号和自动唤起浏览器,在webpack.config.js中添加配置如下
moudle.exports = {
devServer: {
//自定义的端口号
port: 3000,
//配置自动唤起浏览器
open: true
}
}
重新启动webpack开发服务器就能看到效果了
用webpack进行项目打包发布
代码分为线下环境和线上环境,俗称开发环境(devlopment)和生产环境(production),我们在自己的项目终端运行yarn build命令,就可以让webpack生成dist目录,这个就是打包完成凶狠的文件,发给运维部署到服务器上。
2、vue脚手架和基础API
①vue介绍
vue是渐进式javacript框架, 一套拥有自己规则的语法,官网地址: https://cn.vuejs.org/ (作者: 尤雨溪)。所谓渐进式框架,就是按需、逐渐集成功能,vue就是逐步集成了vue-cli、vueRouter、vuex等功能,形成了vue全家桶。所谓框架,就是相对于引入jQuery库这类方法和属性的集合,vue框架拥有自己的语法规则。
vue有两种开发模式,传统开发模式即基于html文件开发Vue,需要自己引入vue.js文件,工程化开发模式即在webpack环境中开发vue,企业常用的开发模式,我们学习的也是这种开发模式。
②vue/cli脚手架
脚手架介绍
脚手架原本指保证各施工过程顺利进行而搭设的工作平台,在Vue里体现出来就是官方提供了一套固定标准的代码结构,即固定的标准文件夹+文件+webpack配置代码,可以实现开箱即用、webpack 零配置。
脚手架安装
全局安装:在终端中输入 yarn global add @vue/cli
检查是否安装成功,在终端中输入@Vue -V,如果返回的是@vue/cli 4.5.12这类版本号就说明安装成功
创建项目并启动服务
假设我们要创建名为vuecli-demo的项目,则在终端中输入vue create vuecli-demo并回车,后面就是选择创建项目的配置:
- 选择Manually select features(自定义特性)
- 空格选中Babel、Router、Vuex、CSS Pre-processors、Linter / Formatter
- 选择版本号为2.x
- 模式输入n(用hash模式不要用history模式)
- 选择Less(目前只学了less,sass以后再学)
- 选择ESLint + Standard config(eslint不要关,帮助养成良好的编码习惯)
- 选择In dedicated config files(把每一个配置文件分开存放,不要全部放在package.json)
- 输入n(不要把这次的配置保存为默认配置)
- 用cd命令cd vuecli-demo 切换到项目文件夹(具体以你的项目在磁盘中的位置来确定)
编译文件启动服务的命令是yarn serve,如果没有自动弹出浏览器,在浏览器中输入给出的地址 http://localhost:8080/ 即可
脚手架目录分析
脚手架中各个文件夹的含义
现在暂时不用全部看懂,只要了解以下几个文件和文件夹的作用就可以了
文件名 作用
node_modules 依赖包
index.html 网页入口
main.js 打包入口
App.vue Vue页面入口
package.json 项目描述信息
脚手架结构分析
main.js和App.vue以及index.html的关系是 App.vue -> main.js -> index.html
脚手架自定义配置
src并列处新建vue.config.js, 填入配置, 重启webpack开发服务器即可
moudle.exports = {
devServer: {
//自定义的端口号
port: 3000,
//配置自动唤起浏览器
open: true
}
}
eslint介绍
eslint是代码检查的工具,如果写代码违反了eslint的规则,就会报错,
解决方法:
- 手动解决掉错误, 以后项目中会讲如何自动解决,或者
- 暂时关闭eslint检查(因为现在主要精力在学习Vue语法上), 在vue.config.js中配置后重启服务
在vue.config.js中设置lintOnSave, 重启服务
单vue文件
- Vue推荐采用.vue文件来开发项目
- 注意事项:template里只能有一个根标签
- 单vue文件的好处:独立作用域,不必担心变量名冲突
- style配合scoped属性, 保证样式只针对当前template内标签生效
- 标签和样式如何显示到页面:vue文件配合webpack, 把他们打包起来插入到index.html
清理欢迎界面
项目创建时,自动生成了很多代码和文件,需要把他们删除掉来开始自己的项目
- assets 和 components 文件夹下的一切都删除掉 (不要默认的欢迎页面)
- src/App.vue默认有很多内容, 可以全部删除留下template和script和style的框
③vue指令
插值表达式
声明式渲染(文本插值),语法为语法: {{ 表达式 }},其中msg和obj是vue数据变量,要在js中data函数里声明
插值表达式就是双大括号, 可以把Vue变量直接显示在标签内。Vue中变量声明在data函数中return对象,而对象里key就是变量名
MVVM设计模式
不同于MVC(Model-View-Controller)设计模式主要使在控制层编写代码,MVVM设计模式转变了思维,用数据来驱动视图改变,操作DOM的事,被vue源码来干了。
MVVM(Model-View-ViewModel)设计模式就是模型,、视图、视图模型,双向关联的设计模式
MVVM的优点是减少DOM操作,提高渲染效率,让程序员专注于数据处理,提高开发效率
v-bind动态属性
v-bind可以给标签设置vue变量的值,语法为v-bind:属性名="vue变量",通常简写为属性名="vue变量"
v-on事件绑定
v-on可以给标签绑定事件,根据是否传参,语法分别为
- v-on:事件名=“methods中的函数名"
- v-on:事件名=“methods中的函数名(实参)"
点击事件触发的方法在methods当中定义
通常将事件简写为 @事件名=“methods中的函数”
v-on事件对象
在vue事件处理函数中,想要拿到事件对象,如果是没有传参,可以直接用第一个形参接收,如果有实参,通过$event指代事件对象传给事件处理函数
v-on事件修饰符
在事件后面加上.修饰符名可以给事件带来更强大的功能,语法为@事件名.修饰符="methods里函数",例如e.prevent可以阻止默认行为,e.stop 可以阻止事件冒泡。
v-on按键修饰符
同样的,也可以给键盘事件添加修饰符,@keyup.enter 可以监测回车按键,@keyup.esc 可以监测返回按键,更多的修饰符可以看vue官网说明 https://cn.vuejs.org/v2/guide/events.html
v-model双向绑定
双向绑定,即把value属性和Vue数据变量双向绑定到一起,这样不论变量变化还是视图变化,都能使对方一起改变,语法为v-model="Vue数据变量",具体写法为:
v-model写在select上, value写在option上, Vue变量关联value属性的值
v-model用在复选框时,非数组关联的是checked属性,数组关联的是value属性
Vue变量初始值会影响表单的默认状态, 因为双向绑定, 互相影响
v-model修饰符
在v-model后面加上.修饰符,可以让v-model实现更强大的功能,语法为 v-model.修饰符="Vue数据变量",如
- .number 以parseFloat转成数字类型
- .trim 去除首尾空白字符
- .lazy 在change时触发而非input时
v-html
v-html可以更新DOM对象的innerHTML,语法为v-html="Vue数据变量"。和innerText、innerHTML一样,Vue指令-v-text和v-html都可以设置标签显示的内容,他们的区别是v-text把值当成普通字符串,而v-html把值当成标签进行解析
注意:会覆盖差值表达式
v-show和v-if
v-show和v-if可以控制标签的隐藏或出现,他们的语法是v-show="true",v-if="true"。二者原理有所不同,v-show 用的css方法display:none隐藏,而v-if 直接从DOM树上移除,因此频繁切换的时候应该使用v-show,v-if每次隐藏再出现都要经历销毁再渲染的过程,对性能影响较大。v-if可以配合v-else使用,满足条件时渲染v-if,不满足时渲染v-else,多个条件判断可使用else-if。
v-for
v-for可以实现列表渲染,v-for所在的标签,可以按照数据数量,循环生成多个,语法如下:
v-for="(值变量, 索引变量) in 目标结构"
v-for="值变量 in 目标结构"
v-for如何循环列表的方法是,先准备目标数据结构,然后遍历数组/对象/数字/字符串,想循环谁, 就把v-for写在谁的身上。
v-for注意事项:值变量和索引不能用到v-for范围以外,而且in的两边必须有空格
3、vue计算属性和侦听器
①v-for更新检测
- 数组变更方法,就会导致v-for更新、页面更新
- 数组非变更方法,返回的是新数组,不会导致v-for更新,可以拿返回的新数组替换旧数组或者this.$set()方法更新某个值
回顾:数组变更方法有push, pop, shift, unshift, splice, sort, reverse,数组非变更方法有filter, concat, slice。
②v-for就地复用
数组改变后新旧更新DOM方式如下
v-for更新时, 是如何操作DOM的? -循环出新的DOM结构, 和旧的DOM结构对比, 尝试就地复用原有标签, 更新内容。
③虚拟DOM
在document对象上, 渲染到浏览器上显示的标签
本质是保存节点信息, 属性和内容的一个JS对象
在内存中比较变化部分, 然后给真实DOM打补丁(更新)
总结:1.虚拟DOM是什么?
本质就是一个JS对象, 保存DOM关键信息
2.虚拟DOM好处是?
提高DOM更新的性能, 不频繁操作真实DOM, 在内存中找到变化部分, 再更新真实DOM相应属性或内容(打补丁)
④key作用
无key发生更新时,从第二个往后更新内容 – 性能不高
无key属性, 图解 - 最大限度尝试就地修改/复用相同类型元素
有key值为索引, 基于key的来比较新旧虚拟DOM, 移除key不存在元素
先产生新旧虚拟DOM, 根据key比较, 还是就地更新
有key, 值为id属性, 基于key的来比较新旧虚拟DOM, 移除key不存在元素
有key, 值为id, 先产生新旧虚拟DOM, 根据key比较
总结:1.子元素或者内容改变会分哪2种情况比较?
无key, 就地更新
有key, 按照key比较
2.key值要求是?
唯一不重复的字符串或者数值
3.key应该怎么用?
有id用id, 无id用索引
4.key的好处?
可以提高更新的性能
⑤动态class
用v-bind给标签class设置动态的值,语法 :class="{类名: 布尔值}",true使用, false不使用
⑥动态style
给标签动态设置style的值,语法为 :style="{css属性名: 值}"
总结:1.给style赋值和class区别是?
:class="{类名: 布尔值}",true使用, false不使用
:style="{css属性名: 值}"
⑦计算属性computed
当变量的值, 需要通过别的变量计算而得来,就需要用到计算属性。计算属性特点是,函数内使用的变量改变, 重新计算结果返回。注意:计算属性也是vue数据变量,所以属性名和data里名字不能重复。
⑧计算属性的缓存
计算属性, 基于依赖项的值进行缓存,依赖的变量不变, 都直接从缓存取结果
1.计算属性好处是,带缓存,依赖项不变, 直接从缓存取,依赖项改变, 函数自动执行并重新缓存值。
2.计算属性使用场景是,当变量值, 依赖其他变量计算而得来才用
⑨计算属性的完整写法
计算属性其实也是变量,可以赋值
总结:1.何时用计算属性完整写法? -给计算属性变量赋值时
2.set函数和get函数什么时候执行? -set接收要被赋予的值,或者get里要返回给这个计算属性具体值使用
⑩watch侦听器
vue中,watch可以侦听data/computed属性值的改变,想要侦听到某个变量值改变呢,可以使用watch配置, key要侦听的data/计算属性名
⑪深度侦听
vue也可以侦听对象和数组等复杂类型,只需要把侦听器写成对象形式, 给handler方法和deep:true
4、vue组件
①封装组件
如果我们在页面中需要使用同一个功能多次,不仅需要重复写三次代码,效率不高,还要担心变量重名。为了解决这个问题,我们可以考虑把这部分重复的代码作为一个组件封装起来,需要使用几次就调用几次。
右侧:将代码封装为Pannel组件,左下:调用Pannel组件
②组件概念
- 组件是可复用的 Vue 实例, 封装标签, 样式和JS代码
- 组件化 :封装的思想,把页面上 可重用的部分 封装为 组件,从而方便项目的 开发 和 维护
- 一个页面, 可以拆分成一个个组件,一个组件就是一个整体, 每个组件可以有自己独立的 结构 样式 和 行为(html, css和js)
③组件基础用法
每个组件都是一个独立的个体, 代码里体现为一个独立的.vue文件
④组件内scoped作用
- 准备: 当前组件内标签都被添加 data-v-hash值 的属性
- 获取: css选择器都被添加 [data-v-hash值] 的属性选择器
总结:1.Vue组件内样式, 只针对当前组件内标签生效如何做?
style上添加scoped
2.原理和过程是什么?
自动给标签添加data-v-hash值属性
所有选择器都加上属性选择器
⑤vue组件通信-父传子
想要从一个组件内, 给另外一个组件传值,可以在组件a内, 定义变量, 准备接收, 然后使用变量,然后组件b内引入组件a, 注册组件, 使用组件, 传值进去,我们先介绍父传子技术。
子组件内, 定义变量, 准备接收, 然后使用变量
父组件(App.vue)内, 要展示封装的子组件(MyProduct.vue)
总结:1.什么时候需要父传子技术?
从一个vue组件里把值传给另一个vue组件(父->子)
2.父传子步骤是什么?
子组件内, props定义变量, 在子组件使用变量
父组件内, 使用子组件, 属性方式给props变量传值
⑥循环使用组件
在上面的案例中,我们可以循环创建组件,并在每次循环创建时向组件传入不同的值
⑦单项数据流
在上面的案例中,子组件内想实现砍价功能, 点一次按钮砍掉价格,但我们发现在子组件内不能能改变父传入的数据,因此我们说,从父到子的数据流向, 叫单向数据流。原因是子组件修改, 不通知父级, 造成数据不一致性,Vue规定了props里的变量, 本身是只读的。
总结:1.为何不建议, 子组件修改父组件传过来的值?
父子数据不一致, 而且子组件是依赖父传入的值
2.什么是单向数据流?
从父到子的数据流向, 叫单向数据流
3.props里定义的变量能修改吗?
不能, props里的变量本身是只读的
⑧vue组件通信-子向父传值
如果想要实现子向父传值,可以让子组件触发父组件的自定义事件方法。
首先在父组件内, 绑定自定义事件和事件处理函数,语法: @自定义事件名="父methods里函数名"
然后在子组件内, 恰当的时机, 触发父给我绑的自定义事件, 导致父methods里事件处理函数执行
总结:1.什么时候使用子传父技术?
当子想要去改变父里的数据
2.子传父如何实现?
父组件内, 给组件@自定义事件="父methods函数"
子组件内, 恰当时机this.$emit('自定义事件名', 值)
5、vue生命周期和axios库
①vue生命周期
从vue实例,创建到销毁的整个过程就是vue的生命周期
②vue钩子函数
vue框架内置钩子函数,随着组件的生命周期阶段,自动执行。
-
作用:可以在特定的时间点,执行特定的操作
-
场景:组件创建完毕后,可以在created生命周期函数中发起Ajax请求,从而初始化data数据
-
分类:4大阶段8个方法
阶段 方法名 方法名
初始化 beforeCreate created
挂载 beforeMount mounted
更新 beforeUpdate updated
销毁 beforeDestroy destroyed
总结:1.如何知道vue生命周期到达了什么阶段:使用钩子函数
2.钩子函数有哪些:初始化(bedoreCreate、created)、挂载(beforeMount、mounted)、更新(beforeUpdate、updated)、销毁(beforeDestroy、destroyed)
③vue初始化阶段
以下来自于vue官方文档
1.new Vue() – Vue实例化(组件也是一个小的Vue实例)
2.Init Events & Lifecycle – 初始化事件和生命周期函数
3.beforeCreate – 生命周期钩子函数被执行
4.Init injections&reactivity – Vue内部添加data和methods等
5.created – 生命周期钩子函数被执行, 实例创建
6.接下来是编译模板阶段 –开始分析
7.Has el option? – 是否有el选项 – 检查要挂到哪里
没有. 调用$mount()方法
有, 继续检查template选项
总结:vue实例从创建到编译模板执行了两个钩子函数,beforeCreate和created。created函数触发时能获取data,但不能获取真实DOM
④vue挂载阶段
1.template选项检查
有 - 编译template返回render渲染函数
无 – 编译el选项对应标签作为template(要渲染的模板)
2.虚拟DOM挂载成真实DOM之前
3.beforeMount – 生命周期钩子函数被执行
4.Create … – 把虚拟DOM和渲染的数据一并挂到真实DOM上
5.真实DOM挂载完毕
6.mounted – 生命周期钩子函数被执行
总结:vue实例从创建到显示经历了四个钩子函数beforeCreate、created、beforeMount、mounted,可以在mounted里面获取真实DOM
⑤vue更新阶段
1.当data里数据改变, 更新DOM之前
2.beforeUpdate – 生命周期钩子函数被执行
3.Virtual DOM…… – 虚拟DOM重新渲染, 打补丁到真实DOM
4.updated – 生命周期钩子函数被执行
5.当有data数据改变 – 重复这个循环
⑥vue销毁阶段
1.当$destroy()被调用 – 比如组件DOM被移除(例v-if)
2.beforeDestroy – 生命周期钩子函数被执行
3.拆卸数据监视器、子组件和事件侦听器
4.实例销毁后, 最后触发一个钩子函数
5.destroyed – 生命周期钩子函数被执行
总结:一般在beforeDestory/destroyed函数里面手动消除计时器、定时器和全局事件
⑦axios基本使用
axios是一个专门用于发送请求的库,官网:http://www.axios-js.com/,特点:
- 支持客户端发送Ajax请求
- 支持服务端Node.js发送请求
- 支持Promise相关用法
- 支持请求和响应的拦截器功能
- 自动转换JSON数据
axios底层还是原生js实现,内部通过Promise封装的。
总结:ajax是 一种前端异步请求后端的技术;ajax原理是浏览器window接口的XMLHttpRequest;axios是基于原生ajax+Promise技术封装通用于前后端的请求库
axios获取数据
以获取图书信息为例,我们通过触发按钮的点击事件,调用后台接口,拿到所有图书信息,然后打印到控制台。注意要先下载axios,引入后才能使用。
总结:1.axios如何发起一次get请求?
在method选项配置为get / 也可以默认不写
2.axios函数调用原地结果是什么?
是一个Promise对象
3.如何拿到Promise里ajax的成功或失败的结果?
then() / catch()
⑧使用get方式传参
以获取指定图书信息为例,获取用户输入框的文本,点击调用后台接口,查询指定的书籍信息,然后打印到控制台。
总结:1.ajax如何给后台传参
- 在url ? 后面拼接 – 查询字符串
- 在url路径上 – 需要后端特殊处理
- 在请求体传参给后台
2.axios哪个配置项会把参数自动写到url?后面
params
⑨使用post方式传参
以新增图书信息为例,点击新增按钮,把用户输入的信息传递给后台,然后把后台返回的结果打印到控制台上。
总结:1.post请求方式, 一般在哪里传递数据给后台?
请求体中
2.axios哪个选项, 可以把参数自动装入到请求体中?
data选项
3.axios默认发给后台请求体数据格式是?
json字符串格式
⑩配置基础地址
在axios中,可以设置基础地址,统一管理,也避免了每次发送请求都需要重复写一次baseURL。
总结:axios如何配置基地址?
axios.defaults.baseURL
6、插槽
①插槽
通过slot标签,让组件内可以接收不同的标签结构显示
- 组件内用
占位 - 使用组件时
夹着的地方, 传入标签替换slot
总结:1.当组件内某一部分标签不确定怎么办?
用插槽技术
2.插槽具体如何使用?
- 先在组件内用slot占位
- 使用组件时, 传入具体标签插入
3.插槽运行效果?
传入的标签会替换掉slot显示
②默认内容
如果外面不给传组件标签,想给个默认显示内容,可以在
总结:不给组件传标签. slot内容原地显示;给组件内传标签, 则slot整体被换掉
③具名插槽
如果组件内有2组以上需要传入外部标签的时候,可以给slot使用name属性区分名字,然后template配合v-slot:名字来分发对应标签。注意:v-slot:可以简化成#
总结:1.具名插槽的使用步骤是什么?
组件内: slot占位, 设置 name 属性用于区分
使用者: template 配合 v-slot:name 指定替换 slot
2,v-slot: 可以简化成什么?
可以简化成#号
④作用域插槽
使用插槽时,想使用组件里的变量,如果直接用另外一个组件里的变量,就会报错
口诀:
- 子组件, 在slot上绑定属性和子组件内的值
- 使用组件, 传入自定义标签, 用template和v-slot="自定义变量名"
- scope变量名自动绑定slot上所有属性和值
scope =
总结:1.作用域插槽什么时候使用?
使用组件插槽技术时, 需要用到子组件内变量
2.作用域插槽使用口诀?
子组件在slot身上添加属性和子组件的值
使用组件处template配合v-slot=“变量名”
收集slot身上的所有属性和值
⑤作用域插槽使用场景
作用域插槽常用于自定义组件标签+内容,可以让组件更加灵活的适用于不同的场景和项目
例子: 我想要给td内显示图片, 需要传入自定义的img标签
- 在MyTable.vue的td中准备
占位, 但是外面需要把图片地址赋予给src属性,所以在slot上把obj数据绑定 - 在UseTable使用MyTable的时候, template上v-slot绑定变量, 传入img组件设置图片地址
⑥自定义指令
有时候vue内置的指令不能满足我们的要求,我们可以自定义一些指令来使用。
全局注册的语法
局部注册的语法
⑦¥refs获取DOM
在mounted生命周期,可以通过两种方式获取原生DOM标签
-
首先,在目标标签添加id/ref
-
然后在恰当的时机,通过id或者ref属性获取目标标签
⑧¥refs获取组件对象
通过ref属性获取组件对象的方法:
-
首先,创建Demo组件,写一个方法
-
然后,在App.vue使用Demo组件,给ref属性,名字随意
-
最后,在恰当的时机,通过ref属性,获取组件对象,可调用组件对象里方法等
总结:1.如何获取组件对象呢?
目标组件添加ref属性
this.$refs.名字 获取组件对象
2.拿到组件对象能做什么?
调用组件里的属性/方法
⑨$nextTick使用
想要data数据改变,获取原生DOM内容,可以通过$nextTick实现
-
首先,创建标签显示数据
-
然后,当点击+1的时候,马上获取原生DOM内容。这个时候会发现,获取到的还是之前的,原因是vue更新DOM是异步的
-
想要解决这个问题,需要等DOM更新后,再触发此方法里的函数体执行。语法为this.$nextTick(函数体)
总结:1.data改变更新DOM是同步还是异步的?
异步
2.我们可以在哪里访问到更新后的DOM呢?
this.$nextTick里的函数体
updated生命周期钩子函数(了解)
⑩$nextTick使用场景
点击按钮后隐藏按钮,并展示为输入框,让输入框处于激活状态
注意: 一定要用v-if来写 (保证DOM异步更新前获取不到输入框, 体现$nextTick价值)
想要优化使用,也可以$nextTick()返回Promise 配合await使用
总结:1.$nextTick函数原地返回什么?
Promise对象
2.如何在JS中主动触发标签的事件呢?
获取到DOM对象, 调用事件方法
⑪v-model的本质
想要用v-model实现数据双向绑定,可以按照如下操作:
-
给value属性赋值
-
接收input事件,把值赋予给变量
-
所以子组件中,就要用props+value接收使用
-
最后用子组件触发input事件传值
7、Vue-Router路由
①vue路由简介
就像路由器是设备跟ip的映射关系一样,Vue的路由是接口和服务的映射关系
或者路径和组件的映射关系
http://localhost:8080/#/home http://localhost:8080/#/comment http://localhost:8080/#/search
总结:1.路由是什么呢?
路由是一种映射关系
2.Vue中的路由是什么?
路径和组件的映射关系
②为什么用路由
有时候我们需要实现网页的局部刷新,用户的操作就像是始终在一个页面上一样,体验非常好,这个时候就需要用路由来实现业务场景切换了,例如网易云音乐lhttps://music.163.com/
- 单页面应用(SPA): 所有功能在一个html页面上实现
- 前端路由作用: 实现业务场景切换
- 优点:
整体不刷新页面,用户体验更好
数据传递容易, 开发效率高
缺点:
开发成本高(需要学习专门知识)
首次加载会比较慢一点。不利于seo
③vue-router介绍
vue-router本质是一个第三方包,官网: https://router.vuejs.org/zh/
vue-router模块包特点:
- 它和 Vue.js 深度集成
- 可以定义 - 视图表(映射规则)
- 模块化的
- 提供2个内置全局组件
- 声明式导航自动激活的 CSS class 的链接
④路由组件分类
路由组件本身没有区别,我们为了方便理解和使用,人为的分为了页面组件和复用组件。
页面组件就是展示出的一整版页面,配合路由来使用,通常放在src/views文件夹;复用组件就是用来展示数据的,常用于重复渲染结构一样的标签,一般放在src/components文件夹
⑤路由的使用
vue-router使用步骤:
- 下载vue-router模块到当前工程
- 在main.js中引入VueRouter函数
- 添加到Vue.use()身上 – 注册全局RouterLink和RouterView组件
- 创建路由规则数组 – 路径和组件名对应关系
- 用规则生成路由对象
- 把路由对象注入到new Vue实例中
- 用router-view作为挂载点, 切换不同的路由页面
注意: 一切都要以url上的hash值为准
总结:1.vue-router本质是什么?
第三方包, 下载后集成到vue项目中
2.vue-router如何使用?
下包/引入/注册/规则/路由对象/注入/挂载点
3.规则如何生效?
切换url上hash值, 开始匹配规则, 对应组件展示到router-view位置
⑥使用声明式导航来跳转
- vue-router提供了一个全局组件 router-link
- router-link实质上最终会渲染成a链接 to属性等价于提供 href属性(to无需#)
- router-link提供了声明式导航高亮的功能(自带类名)
我们可以使用组件router-link来替代a标签
总结:
-
router-link是什么?
VueRouter在全局注册的组件, 本质就是a标签
-
router-link怎么用?
当标签使用, 必须传入to属性, 指定路由路径值
-
router-link好处?
自带激活时的类名, 可以做高亮
⑦使用声明式导航来传参
在跳转路由时,我们想要在跳转链接上传参,可以在router-link上的to属性传值, 语法格式如下
/path?参数名=值
/path/值 – 需要路由对象提前配置 path: “/path/:参数名”
对应页面组件接收传递过来的值
$route.query.参数名
$route.params.参数名
⑧路由重定向
网页第一次打开时,没有默认的页面,可以使用路由重定向,匹配path后, 强制跳转path路径。一般来说,网页打开url默认hash值是/路径,redirect是设置要重定向到哪个路由路径。
当用户访问的路由路径不存在时,可以重定向至404页面,在路由的最后, path匹配*(任意路径)即可,若前面都没有匹配上,那么就会命中最后这个
⑨路由模式设置
路由有两种模式,hash模式和history模式,我们在实例化路由对象时, 传入mode选项和值就可以修改路由模式
hash路由例如: http://localhost:8080/#/home
history路由例如: http://localhost:8080/home (以后上线需要服务器端支持, 否则找的是文件夹)
hash模式和history模式的区别:
- 原理不同。
hash模式的实现原理是通过监听hashChange事件来实现的,前端js把当前hash地址对应的组件渲染到浏览器中。history模式是通过调用 history.pushState方法(或者replaceState) 并且 监听popstate事件来实现的。history.pushState会追加历史记录,并更换地址栏地址信息,但是页面不会刷新,需要手动调用地址变化之后的处理函数,并在处理函数内部决定跳转逻辑;监听popstate事件是为了响应浏览器的前进后退功能。 - 表现不同。
hash模式会在地址栏中有#号,而history模式没有;同时由于history模式的实现原理用到H5的新特性,所以它对浏览器的兼容性有要求(IE >= 10)。 - history模式特点
history模式开发的SPA项目,需要服务器端做额外的配置,否则会出现刷新白屏(链接分享失效)。原因是页面刷新时,浏览器会向服务器真的发出对这个地址的请求,而这个文件资源又不存在,所以就报404。处理方式就由后端做一个保底映射:所有的请求全部拦截到index.html上。
⑩编程式导航
可以通过JS代码来进行跳转,可以使用path或者name任选一个,语法this.$router.push(配置path/name)
⑪编程式导航传参
使用JS跳转路由时,也可以传参,在query和params中任选一个
注意:使用path会忽略params
总结:JS切换路由如何传值, 如何接收值?
- query传, $route.query接
- params传, $route.params接
⑫路由嵌套
页面顶部导航可以视为一级路由,下面的导航入口可以视为二级路由,这种在某一个一级路由中,又有几个路由的情况,就叫路由嵌套。例如网易云的发现音乐下面,又有推荐、排行榜、歌单等二级路由。
我们来模拟写一个路由嵌套结构:
-
创建需要用的所有组件
src/views/Find.vue -- 发现音乐页
src/views/My.vue -- 我的音乐页
src/views/Second/Recommend.vue -- 发现音乐页 / 推荐页面
src/views/Second/Ranking.vue -- 发现音乐页 / 排行榜页面
src/views/Second/SongList.vue -- 发现音乐页 / 歌单页面
-
main.js– 继续配置2级路由
一级路由path从/开始定义
二级路由往后path直接写名字, 无需/开头
嵌套路由在上级路由的children数组里编写路由信息对象
-
说明:
App.vue的router-view负责发现音乐和我的音乐页面, 切换
Find.vue的的router-view负责发现音乐下的, 三个页面, 切换
总结:1. 二级路由如何配置?
创建需要的二级页面组件
路由规则里children中配置二级路由规则对象
一级页面中设置router-view显示二级路由页面
- 二级路由注意什么?
二级路由path一般不写根路径/
跳转时路径要从/开始写全
⑬声明式导航的类名区别
观察路由嵌套导航的样式可以发现:
router-link-exact-active (精确匹配) url中hash值路径, 与href属性值完全相同, 设置此类名
router-link-active (模糊匹配) url中hash值, 包含href属性值这个路径
⑭路由前置守卫
用户在进行页面跳转的时候,如果没有登录,应该把他打回去登录页,这个就叫做权限控制,可以使用全局前置守卫来实现,语法:lrouter.beforeEach((to, from, next) =>{}),注意一定要调next()才会跳转下一页
总结:什么是路由守卫?
路由在真正跳转前, 会执行一次beforeEach函数, next调用则跳转, 也可以强制修改要跳转的路由
⑮组件缓存
针对暂时看不见的组件,最好不要频繁销毁,否则会影响性能,我们可以使用vue内置的keep-alive组件把要缓存的组件包起来
⑯匹配缓存
如果只想缓存某个组件或者不缓存某个组件,可以给keep-alive组件添加include或者exclude属性,Include (包含 – 缓存),exclude(不包含 – 不缓存)
- 先给对应组件设置name属性名
- 再把名字填写到include/exclude位置
⑰缓存状态
想要知道组件是被切走了,还是被切回来了,我们扩展了2个新的生命周期方法
- lactivated – 激活时触发
- deactivated – 失去激活状态触发
8、Vuex
①Vuex介绍
Vuex 是 vue 项目中实现大范围数据共享的技术方案。
作用:能够方便、高效地实现组件之间的数据共享。
使用Vuex的好处:
- 数据的存取一步到位,不需层层传递
- 数据的流动非常清晰
- 存储在 Vuex 中的数据都是响应式的
总结:1. Vuex 的作用是什么?
频繁、大范围的数据共享
- 在项目中使用 Vuex 的 3 个好处是什么?
- 数据的存取一步到位
- 数据的流动非常清晰
- Vuex 的数据是响应式的
②Vuex安装和配置
想要引入Vuex,需要进行如下步骤:
-
安装 Vuex 的依赖包:
使用npm i vuex@3.6.2命令,在把 Vuex 安装为项目的依赖包:
-
封装 Store 模块:
①导入 Vue 和 Vuex 依赖包
②把 Vuex 安装为 Vue 的插件
③创建 store 的实例对象
④向外共享 store 的实例对象
-
导入并挂载 Store 的实例对象
总结:1.调用哪个函数可以把 Vuex 安装为 Vue 的插件?
Vue.use(Vuex)
2.怎么创建 Store 的实例对象?
new Vuex()或new Vuex.Store()
③state的基本使用
概念:State 本质上就是 Object 对象
作用:用来存储全局共享的数据
基本用法:
在每个 Vue 组件中,可以通过 this.$store.state.全局数据名称 访问 Store 中的数据。
也可以通过基于 Vuex 提供的 mapState 辅助函数,把 Store 中指定的数据,映射为当前组件的计算属性。
总结:1.new Vuex.Store() 时,通过哪个选项来定义共享的数据?
new Vuex.Store({
state: { /* 要共享的数据 */ }
})
- 在组件使用 State 中数据的两种方式分别是什么?
this.$store.state.数据项的名字
mapState 辅助函数 + computed 计算属性
④Mutation的基本使用
我们可以在组件中修改Vuex中的state数据,但是不推荐,包括Vuex 官方也禁止我们直接修改,会导致修改来源不明确的问题,不利于调试和后期的维护。
如果想要修改State中的数据,只能调用Mutation方法。Mutation 本质上是 JavaScript 函数,专门用来变更 Store 中的数据。这样做的好处是能够确保修改来源的唯一性,方便调试和后期维护。
总结:State、组件、Mutation之间的关系
State:全局存储共享数据的地方
Vue 组件:使用数据的地方
Mutation:专门负责修改 State 中的数据
想要使用Mutation,可以按照如下步骤:
①在 Vuex 中定义 Mutation 方法
②在组件中调用 Mutation 方法
总结:1.mutation 方法的第一个形参是什么?
永远都是 state 对象
2.在组件中怎样调用 mutation 方法?
this.$store.commit('方法名')
载荷(Payload)
Vuex 中的载荷就是参数的意思,通过载荷可以提高 Mutation 方法的通用性。例如:
提交载荷(Payload)
在组件中,可以通过 this.$store.commit() 方法的第二个参数来提交载荷(参数),示例代码如下:
总结:1.怎样在 Mutation 方法中定义载荷?
方法名(state, 载荷的形参)
其中载荷的形参推荐命名为 payload
2.怎样在调用 Mutation 方法时提交载荷?
this.$store.commit(方法名,载荷的实参)
mapMutations辅助函数
基于 Vuex 提供的 mapMutations 辅助函数,可以方便的把 Store 中指定的方法,映射为当前组件的 methods:
mapMutations辅助函数的用法示例
Mutation必须是同步函数
在项目开发中,为了保证 Store 中状态的每一次变化都是可追踪的,Vuex 规定: Mutation 必须是同步函数。否则,vue-devtools 将无法正常追踪 Store 中数据的变化,这对大型项目的开发调试是灾难性的!
错误示范:
⑤Action的基本使用
因为Mutation只能是同步函数,所以我们引入了Action,Action 本质上是 JavaScript 函数,专门用来处理 Vuex 中的异步操作。Action不能直接修改数据源。想要将Action异步操作得到的数据结果保存到数据源中,Action会把异步操作的结果,转交给Mutation,由Mutation来负责修改数据源。
定义Action方法
调用Action方法
在组件中,通过 this.$store.dispatch('xxx') 方法,即可触发指定名称的 Action 方法。
在Action方法中定义载荷
在 Action 方法中,可以通过第二个形参的位置来定义载荷参数。
调用Action方法时提交载荷
通过 this.$store.dispatch() 方法的第二个参数,即可提交载荷。
mapActions辅助函数
基于 Vuex 提供的 mapActions 辅助函数,可以方便的把 Store 中指定的 Action,映射为当前组件的 methods。
mapActions辅助函数的用法示例
⑥Getter的基本使用
组件中计算属性的复用性比较低,如果有多个组件需要用到此计算属性,我们需要在多个组件之间复制粘贴这个函数。这个时候就可以使用Getter,它是 Vuex 中的计算属性,当 Store 数据源发生变化时,Getter 的返回值会自动更新。Getter 本质上是 JavaScript 函数。
定义Getter方法
访问Getter的第一种方式
在组件中,可以通过 this.$store.getters.xxx 来访问指定 getter 的值。
访问getter的第二种方式
基于 mapGetters 辅助函数,可以把 store 中的 getter 映射为当前组件的计算属性。
⑦Module的基本使用
在下面的示例中,所有的全局数据、方法都集中在了一起,导致 Vuex 的结构混乱,不利于现阶段的开发和后期的维护。所有的全局数据、方法都集中在了一起,导致 Vuex 的结构混乱,不利于现阶段的开发和后期的维护。
这样我们就引入了Module的概念,Vuex 中的 Module 表示按照模块化的开发思想,把不同的数据和方法,按照彼此的关联关系进行封装。
定义模块
每个Module模块都是彼此独立的,都可以拥有自己的 state、mutations、actions、getters 节点:
注册模块
总结:1.模块的 state 是对象还是方法?
方法
2.怎样使用 modules 对象注册模块?
模块的注册名称: 导入的模块对象
namespaced命名空间)
namespaced(命名空间)可以解决不同模块之间成员名称冲突的问题。在实际项目开发中,建议为每个 Module 模块都开启命名空间!
在定义模块时,只需在模块的根节点中声明 namespaced: true 选项,即可为当前模块开启命名空间:
通过模块的注册名称访问模块下的成员
当模块启用了 namespaced: true 选项之后,模块就有了自己的命名空间。此时,模块内的成员需要通过模块的注册名称才可以访问到。示例代码如下:
访问命名空间下的state数据
在组件中访问命名空间下的 state 数据时,建议使用 mapState 函数来简化访问的过程。示例代码如下:
访问命名空间下的mutation方法
在组件中访问命名空间下的 mutation 方法时,建议使用 mapMutations 函数来简化访问的过程:
访问命名空间下的action和getter
建议使用 mapActions 和 mapGetters 函数来简化访问的过程,示例代码如下:
总结:1.如何为模块开启命名空间?
namespaced: true
2.如何基于 map 相关的辅助函数,访问命名空间下的成员?
mapXXX('模块的注册名称', [ /* 要映射的成员名称 */ ])
9、Vue组件库
①vue官方组件库
在之前的vue-cli创建项目时,我们都是使用了默认配置Default([vue 2] babel, eslint),不包含vue-router、vuex等其它功能,我们可以选择自定义特性Manually select features,在项目创建期间,能够选择并安装更多的功能。
推荐选择并安装以下6个功能:Choose Vue version、Babel、Router、Vuex、CSS Pre-processors、Linter/Formatter。可以通过上下箭头进行切换,空格进行选中(git黑窗口中无法选中,建议使用cmd)
然后选择切换到2.x
输入n(用hash模式不要用history模式)
选择Less(目前只学了less,sass以后再学)
选择ESLint + Standard config(eslint不要关,帮助养成良好的编码习惯)
选择默认的Lint on save(即保存时确认代码报错情况)
选择In dedicated config files(把每一个配置文件分开存放,不要全部放在package.json)
输入y(把这次的配置保存为默认配置)
最后给项目起个名字
②Eslint
ESLint 是可组装的 JavaScript 和 JSX 检查工具。通俗理解就是一个用来约束团队成员代码风格的工具。
常见的ESLint规则:
语法规则 错误消息 说明
no-multiple-empty-lines More than 1 blank line not allowed 不允许出现连续的空行
eol-last Newline required at end of file but not found 文件末尾必须包含一个空白行
semi Extra semicolon 需要省略不必要的分号
comma-dangle Unexpected trailing comma 禁止使用拖尾逗号
no-trailing-spaces Trailing spaces not allowed 行末禁止出现多余的空格
indent Expected indentation of 2 spaces but found 4 必须使用两个空格进行缩进
quotes Strings must use singlequote 字符串必须使用单引号表示
space-before-function-paren Missing space before function parentheses 函数形参的 () 之前必须有空格
ESLint官方文档:https://eslint.bootcss.com/docs/rules/
ESlint的规则是我们可以自己修改的,这里以其中一项修改为例。首先找到项目根目录下的 .eslintrc.js 配置文件
然后在 rules 配置选项中,修改默认的语法规则
// 通过 rules 来修改默认规则
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
// 禁止在 function 函数的形参 () 之前出现空格
'space-before-function-paren': ["error", "never"]
}
注意:修改完 .eslintrc.js 配置文件后,必须重新运行 npm run serve 命令,否则修改后的配置不会生效。
实际项目开发中,一般是团队leader和组员约定好一套合适的代码风格,大公司一般有完善的代码规范。
在VS Code中使用ESLint规则
想要在VS Code中使用ESLint规则,可以安装ESLint插件, 让vscode实时告诉我, 我哪里错了。
注意:用vscode打开项目时,将脚手架工程作为vscode根目录, 因为eslint要使用配置文件.eslintrc
我们还要在VS Code中进行一些设置,如图所示五个步骤:
需要填在settings.json里的代码复制粘贴这里的就可以了
{
"eslint.enable": true,
"eslint.run": "onType",
"eslint.options": {
"extensions": [
".js",
".vue",
".jsx",
".tsx"
]
},
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
}
稍微解释下选项,eslint.run 表示运行eslint检验的时刻 (onSave保存) (onType输入时),editor.codeActionsOnSave 表示控制在保存时运行代码操作时修复哪些问题,source.fixAll.eslint 表示所有可自动修复的ESLint错误都将在保存时修复
如果没有生效,可能是”使用...格式化文档“功能不是把”Prettier ESLint“设置为默认值,也有可能是跟Beautify、xxxFormatxxx等美化插件冲突。
③element-ui
常见的Vue技术栈组件库有
- 移动端(Vant, Cube-UI, NutUI )
- PC端 ( element-ui, Ant Design of Vue, iView)
- 小程序: uniapp
我们使用vue-cli脚手架工具创建项目,并在项目中引入elementUI组件库
首先vue create项目,详细过程已经在官方组件库部分讲过了,这里重点说如何安装elementUI组件库,首先输入命令行npm i element-ui -S,其中i是install的简写,表示安装,-S是save的缩写,表示 这个包是生产依赖, 表示项目上线也要使用这个包,如果要安装开发依赖,则使用-D命令。安装后在main.js文件中引入并注册:
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI)
使用组件可以直接参考官方文档的用法,这里以button组件为例:
<template>
<div id="app">
<el-button>默认按钮</el-button>
<el-button type="primary">主要按钮</el-button>
<el-button type="success">成功按钮</el-button>
<el-button type="info">信息按钮</el-button>
<el-button type="warning">警告按钮</el-button>
<el-button type="danger">危险按钮</el-button>
</div>
</template>
注意:
- 组件名前面有el这个关键字
- type属性决定了按钮的样式风格
还有其他一些常见组件也建议学习一下,如table表格组件、pagination翻页组件、Form表单组件、Tree树形组件、Dialog弹框组件、select下拉列表组件等。