十、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并回车,后面就是选择创建项目的配置:

  1. 选择Manually select features(自定义特性)
  2. 空格选中Babel、Router、Vuex、CSS Pre-processors、Linter / Formatter
  3. 选择版本号为2.x
  4. 模式输入n(用hash模式不要用history模式)
  5. 选择Less(目前只学了less,sass以后再学)
  6. 选择ESLint + Standard config(eslint不要关,帮助养成良好的编码习惯)
  7. 选择In dedicated config files(把每一个配置文件分开存放,不要全部放在package.json)
  8. 输入n(不要把这次的配置保存为默认配置)
  9. 用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标签,让组件内可以接收不同的标签结构显示

  1. 组件内用占位
  2. 使用组件时夹着的地方, 传入标签替换slot

总结:1.当组件内某一部分标签不确定怎么办?

用插槽技术

2.插槽具体如何使用?

  1. 先在组件内用slot占位
  2. 使用组件时, 传入具体标签插入

3.插槽运行效果?

传入的标签会替换掉slot显示

②默认内容

如果外面不给传组件标签,想给个默认显示内容,可以在内放置内容, 作为默认显示内容

总结:不给组件传标签. slot内容原地显示;给组件内传标签, 则slot整体被换掉

③具名插槽

如果组件内有2组以上需要传入外部标签的时候,可以给slot使用name属性区分名字,然后template配合v-slot:名字来分发对应标签。注意:v-slot:可以简化成#

总结:1.具名插槽的使用步骤是什么?

组件内: slot占位, 设置 name 属性用于区分

使用者: template 配合 v-slot:name 指定替换 slot

2,v-slot: 可以简化成什么?

可以简化成#号

④作用域插槽

使用插槽时,想使用组件里的变量,如果直接用另外一个组件里的变量,就会报错

口诀:

  1. 子组件, 在slot上绑定属性和子组件内的值
  2. 使用组件, 传入自定义标签, 用template和v-slot="自定义变量名"
  3. 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标签

  1. 首先,在目标标签添加id/ref

  2. 然后在恰当的时机,通过id或者ref属性获取目标标签

⑧¥refs获取组件对象

通过ref属性获取组件对象的方法:

  1. 首先,创建Demo组件,写一个方法

  2. 然后,在App.vue使用Demo组件,给ref属性,名字随意

  3. 最后,在恰当的时机,通过ref属性,获取组件对象,可调用组件对象里方法等

总结:1.如何获取组件对象呢?

目标组件添加ref属性

this.$refs.名字 获取组件对象

2.拿到组件对象能做什么?

调用组件里的属性/方法

⑨$nextTick使用

想要data数据改变,获取原生DOM内容,可以通过$nextTick实现

  1. 首先,创建标签显示数据

  2. 然后,当点击+1的时候,马上获取原生DOM内容。这个时候会发现,获取到的还是之前的,原因是vue更新DOM是异步的

  3. 想要解决这个问题,需要等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实现数据双向绑定,可以按照如下操作:

  1. 给value属性赋值

  2. 接收input事件,把值赋予给变量

  3. 所以子组件中,就要用props+value接收使用

  4. 最后用子组件触发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使用步骤:

  1. 下载vue-router模块到当前工程
  2. 在main.js中引入VueRouter函数
  3. 添加到Vue.use()身上 – 注册全局RouterLink和RouterView组件
  4. 创建路由规则数组 – 路径和组件名对应关系
  5. 用规则生成路由对象
  6. 把路由对象注入到new Vue实例中
  7. 用router-view作为挂载点, 切换不同的路由页面

注意: 一切都要以url上的hash值为准

总结:1.vue-router本质是什么?

第三方包, 下载后集成到vue项目中

2.vue-router如何使用?

下包/引入/注册/规则/路由对象/注入/挂载点

3.规则如何生效?

切换url上hash值, 开始匹配规则, 对应组件展示到router-view位置

⑥使用声明式导航来跳转

  1. vue-router提供了一个全局组件 router-link
  2. router-link实质上最终会渲染成a链接 to属性等价于提供 href属性(to无需#)
  3. router-link提供了声明式导航高亮的功能(自带类名)

我们可以使用组件router-link来替代a标签

总结:

  1. router-link是什么?

    VueRouter在全局注册的组件, 本质就是a标签

  2. router-link怎么用?

    当标签使用, 必须传入to属性, 指定路由路径值

  3. 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模式的区别:

  1. 原理不同。
    hash模式的实现原理是通过监听hashChange事件来实现的,前端js把当前hash地址对应的组件渲染到浏览器中。history模式是通过调用 history.pushState方法(或者replaceState) 并且 监听popstate事件来实现的。history.pushState会追加历史记录,并更换地址栏地址信息,但是页面不会刷新,需要手动调用地址变化之后的处理函数,并在处理函数内部决定跳转逻辑;监听popstate事件是为了响应浏览器的前进后退功能。
  2. 表现不同。
    hash模式会在地址栏中有#号,而history模式没有;同时由于history模式的实现原理用到H5的新特性,所以它对浏览器的兼容性有要求(IE >= 10)。
  3. 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接

⑫路由嵌套

页面顶部导航可以视为一级路由,下面的导航入口可以视为二级路由,这种在某一个一级路由中,又有几个路由的情况,就叫路由嵌套。例如网易云的发现音乐下面,又有推荐、排行榜、歌单等二级路由。

我们来模拟写一个路由嵌套结构:

  1. 创建需要用的所有组件

    src/views/Find.vue -- 发现音乐页

    src/views/My.vue -- 我的音乐页

    src/views/Second/Recommend.vue -- 发现音乐页 / 推荐页面

    src/views/Second/Ranking.vue -- 发现音乐页 / 排行榜页面

    src/views/Second/SongList.vue -- 发现音乐页 / 歌单页面

  2. main.js– 继续配置2级路由

    一级路由path从/开始定义

    二级路由往后path直接写名字, 无需/开头

    嵌套路由在上级路由的children数组里编写路由信息对象

  3. 说明:

    App.vue的router-view负责发现音乐和我的音乐页面, 切换

    Find.vue的的router-view负责发现音乐下的, 三个页面, 切换

总结:1. 二级路由如何配置?
创建需要的二级页面组件
路由规则里children中配置二级路由规则对象
一级页面中设置router-view显示二级路由页面

  1. 二级路由注意什么?
    二级路由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 的作用是什么?

频繁、大范围的数据共享

  1. 在项目中使用 Vuex 的 3 个好处是什么?
  • 数据的存取一步到位
  • 数据的流动非常清晰
  • Vuex 的数据是响应式的

②Vuex安装和配置

想要引入Vuex,需要进行如下步骤:

  1. 安装 Vuex 的依赖包:

    使用npm i vuex@3.6.2命令,在把 Vuex 安装为项目的依赖包:

  2. 封装 Store 模块:

    ①导入 Vue 和 Vuex 依赖包

    ②把 Vuex 安装为 Vue 的插件

    ③创建 store 的实例对象

    ④向外共享 store 的实例对象

  3. 导入并挂载 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: { /* 要共享的数据 */ }

})

  1. 在组件使用 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>

注意:

  1. 组件名前面有el这个关键字
  2. type属性决定了按钮的样式风格

还有其他一些常见组件也建议学习一下,如table表格组件、pagination翻页组件、Form表单组件、Tree树形组件、Dialog弹框组件、select下拉列表组件等。