Vue
简介
vue 渐进式JavaScript框架
课程介绍
- 1 Vue基础知识
- 2 Vue全家桶(vue/vue-router/vuex/axios)
- 3 组件化开发
- 4 webpack - 前端模块化打包构建工具
- 5 ES6 - ECMAScript 6 入门
- 6 Vue项目
介绍
- vue 中文网
- vue github
- Vue.js (读音 /vjuː/,类似于 view) 是一套构建用户界面(UI)的渐进式JavaScript框架
- 要求:通读一遍Vue官网教程中的基础内容
库和框架的区别
- 写在前面:JavaScript从最开始的表单验证,到现在轻松实现复杂的大型应用
无所不能
,没有一个框架怎么行? - 我们所说的前端框架与库的区别?
Library
库,本质上是一些函数的集合。每次调用函数,实现一个特定的功能,接着把
控制权
交给使用者
- 代表:jQuery
- jQuery这个库的核心:DOM操作,即:封装DOM操作,简化DOM操作
Framework
框架,是一套完整的解决方案,使用框架的时候,需要把你的代码放到框架合适的地方,框架会在合适的时机调用你的代码
- 框架规定了自己的编程方式,是一套完整的解决方案
- 使用框架的时候,由框架控制一切,我们只需要按照规则写代码
主要区别
- You call Library, Framework calls you
- 核心点:控制反转(谁起到主导作用)
- 框架中控制整个流程的是框架
- 使用库,由开发人员决定如何调用库中提供的方法(辅助)
- 好莱坞原则:Don’t call us, we’ll call you.
MVVM
- MVVM,一种更好的UI模式解决方案
- 从Script到Code Blocks、Code Behind到MVC、MVP、MVVM - 科普
MVC
- MVC是一种软件架构模式,也有人叫做设计模式
- M: Model 数据模型(专门用来操作数据,数据的CRUD)
- V:View 视图(对于前端来说,就是页面)
- C:Controller 控制器(是视图和数据模型沟通的桥梁,用于处理业务逻辑)
MVVM
- MVVM ===> M / V / VM
- M:model数据模型
- V:view视图
- VM:ViewModel 视图模型
优势
- MVC模式,将应用程序划分为三大部分,实现了职责分离
- 但是,在前端中经常要通过JS代码来进行一些逻辑操作,最终还要把这些逻辑操作的结果展示在页面中。也就是需要频繁的操作DOM
- MVVM通过
数据双向绑定
让数据自动地双向同步- V(修改视图) -> M
- M(修改数据) -> V
- 数据驱动视图的思想,数据是核心
Vue中的MVVM
- 注意:不推荐直接手动操作DOM!!!
虽然没有完全遵循 MVVM 模型,Vue 的设计无疑受到了它的启发。因此在文档中经常会使用 vm (ViewModel 的简称) 这个变量名表示 Vue 实例
学习Vue要转化思想
数据驱动视图
:不要在想着怎么操作DOM,而是想着如何操作数据!!!
vue起步
安装:
1 | npm install vue |
开发的时候使用未压缩版,有提示信息。
1 | <div id="app">{{ msg }}</div> |
构造函数new出来的实例,需要传递参数,参数是一个对象:
- el :指定页面上的vue实例能够作用的边界,值是一个选择器;
- $el :是vue管理的边界对应的DOM对象;
- data :提供数据的对象;
vue实例
【Vue是一个构造函数,所以需要new一个实例,构造函数的首字母大写。】
需要的数据在实例的参数中,data对象提供数据;
1 | var vm = new Vue({ |
Vue 代码
1 | <body> |
数据
data数据使用注意
- 先在data中声明,然后在使用数据;
- 没有先声明的数据,动态添加的数据是非响应式的;
- 在data中声明的数据,会被vue处理,遍历这个data数据对象,内部使用
Object.defineProperty()
方法处理之后,返回给new Vue的实例对象,所以实例对象可以直接使用this来调用data数据对象的属性; - 所以动态添加的新属性数据,没有被处理过,所以是非响应式的数据;
- 在data中声明的数据,会被vue处理,遍历这个data数据对象,内部使用
在某些特殊的时候,需要给vm实例动态添加新的属性和数据,并且希望是响应式的;
需要使用Vue提供的$set()
方法来设置;
vm.$set(obj.user, 'name', 'jack')
- 第一个参数:给哪一个对象添加属性
- 第二个参数:添加的属性的名称,字符串
- 第三个参数:添加的新的属性的值
1 | var obj = { |
数据绑定
语法:{{ msg }}
Mustache语法,插值表达式;– 小胡子语法;
- 解释:使用
{{}}
(Mustache)从data
中获取数据,并展示在模板中; - 说明:数据对象的属性值发生了改变,插值处的内容都会更新;
- 说明:
{{}}
中只能出现JavaScript表达式,不能出现语句,例如if语句for语句; - 注意:Mustache 语法不能作用在 HTML 元素的属性上;
1 | <h1>Hello, {{ msg }}.</h1> |
vue数据双向绑定
- 双向数据绑定:将DOM与Vue实例的data数据绑定到一起,彼此之间相互影响
- 数据的改变会引起DOM的改变
- DOM的改变也会引起数据的变化
- 原理:数据劫持,
Object.defineProperty
中的get
和set
方法getter
和setter
:访问器- 作用:指定
读取或设置
对象属性值的时候,执行的操作
- 注意:
Object.defineProperty
方法是ES5中提供的,IE8浏览器不支持这个方法。因此,Vue支持IE8及其以下版本浏览器; - Vue - 深入响应式原理
- MDN - Object.defineProperty()
补充说明:
- Vue双向数据绑定的原理:
Object.defineProperty()
; - 只有经过
Object.defineProperty()
处理后的数据,才会有get/set - Vue内部遍历了 data 中的数据,将其使用
Object.defineProperty()
来修改为 get/set 的形式 Object.defineProperty(vm, 'msg', {})
1 | /* |
Vue双向绑定的极简实现
1 | <div id="app"> |
【实现原理就是,给obj.txt设置值得时候会被Object.defineProperty()
监听劫持,不会被设置到obj.txt属性;通过劫持到的数据设置给data,用来实现双向绑定;由于obj.txt不会被设置成功,所以一般用第三个变量来接收;】
Vue中异步DOM更新的说明
在数据改变之后,vue并不是立即更新DOM,而是将更新延后了,在vue确认当前阶段数据不在变化之后,才会去更新DOM;(例如:点击事件改变了数据);
为了提高Vue的渲染性能,减少不必要的DOM更新;
1 | const vm = new Vue({ |
需要获取DOM更新后的内容:
使用vm.$nextTick(() => {});
在这个回调函数内部可以获取到DOM更新后的数据;
1 | const vm = new Vue({ |
vue数据更新特点
当动态数据发生改变的时候,页面内的所有指令和表达式都会重新计算一次;
- 前提:必须是页面中存在的;
- 事件除外
【如果数据是复杂类型的,只是修改了复杂类型数据的属性,而不是修改了引用地址,是不会触发 DOM 更新的;】
指令
指令:就是一种特殊的标记,用来给 HTML 元素添加一个特殊的行为(功能);
vue中的指令都是以 v-
开头的;
v-model
v-model指令:
- 只能在表单元素中使用;
- 用来实现数据双向绑定;给表单元素添加了 v-model ,就能实现表单元素的值和数据双向绑定的功能;
- 改变文本框的值,对应的数据txt会自动改变
- 改变数据txt的值,对应的文本框的值也会自动改变
- v-momdel 在不同的表单元素对应的值也不一样;
1 | <input type="text" v-model="txt"> |
v-model的第二种用法
- v-model用于表单数据的双向绑定,其实它就是一个语法糖,这个背后就做了两个操作:
- 父组件向子组件绑定v-model属性;
- 子组件使用
props: ['value']
接收,value
固定写法,用value
来接收父组件传递过来的数据; - 子组件内部通过调用
this.$emit("input", "在子组件中修改了绑定的数据")
input
方法是固定的,通过调用这个方法来修改父组件的数据,达到同步效果;
1 | <!-- 父组件的数据 --> |
v-text 和 v-html
v-text指令:
- 作用相当于操作DOM的innerText,会覆盖原来的文本内容
v-html指令:
- 作用相当于操作DOM的innerHtml,会覆盖原来的所有子元素
1 | <div id="app"> |
v-on
v-on指令:
- 作用:绑定事件
- 语法:
v-on:click="say"
orv-on:click="say('参数', $event)"
- 说明:绑定的事件从
methods
中获取
1 | <!-- 完整语法 --> |
推荐使用简写方式;
1 | <body> |
methods
methods
对象是专门用来设置v-on
事件的执行函数;
【注意:在Vue构造函数new出来的实例中,methods
对象内的事件执行函数内部可以直接使用this,this指向当前new出来的实例对象,可以通过this直接调用实例对象内部的参数;】
事件修饰符
.prevent 阻止默认行为,调用 event.preventDefault()
1 | <button type="submit" class="btn btn-default" @click.prevent="add">添加</button> |
v-bind
v-bind指令:
- 作用:专门用来给标签设置属性的指令,用来给标签属性绑定动态数据;
- 作用:当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM;
- 语法:
v-bind:title="msg"
- 简写:
:title="msg"
1 | <!-- 完整语法 --> |
样式操作
v-bind:class="{}"
or v-bind:class="{}"
- 作用:专门用来操作样式的指令,添加类名或者行内样式;主要操作类名;
- 样式生效和css一致;
1 | <!-- 1 --> |
v-for
v-for指令:
- 根据数组数据多次渲染页面元素
1 | <body> |
key属性
vue中为了提高DOM渲染的性能,默认采用了“就地复用”策略;
数据改变的时候,vue会对比数据修改前后的结构,发现元素结构相同时,优先复用元素,
在没有key属性的时候,按照新的数据复用元素,会按照新的数据依次修改元素的内容(元素机构相同,只修改内容);如果新的数据顺序被改变,则会依次修改;
如果有key属性,vue通过辨识key属性来确定带有key属性的元素直接使用,根据新的数据来确认修改、新建还是删除元素;所以会极大减少对DOM的操作,以提升性能;不管数据顺序有没有改变,保留带有key属性的元素,对照新的数据来确定是否更改;
【下标是数组自动按照内容产生的,所以是会变动的;】
在某些用到临时状态(复选框、文本框输入的内容)的表单元素中,如果当前勾选了复选框,在原数据前插入了新的数据,自动更新了页面后,选中的状态给加到新增加的数据上,此时需要一个key属性来确定原来的状态;
key属性是唯一的,和数据是一一对应的,不能变化的,比如id,不能选择下标来作为key属性,因为下标会在数组中自动重排,所以下标和数据不能对应了;会把新增的属性当成原来的属性;
【所以在使用时最佳建议:添加key属性,并且用id来对应数据】
1 | <body> |
v-cloak
v-cloak指令:
- 作用:用来解决{{}}==> 编译后的数据 页面闪烁的问题;
- 语法:在标签内存在这个指令,没有值;
<h1 v-cloak>{{ msg }}</h1>
- 在vue还没有渲染页面的时候,默认为这个元素增加行内样式
display: none
,在页面上隐藏;vue处理数据后渲染页面时候移除这个行内样式,重新显示在页面上;
vue处理数据渲染页面的时候有一定的延时,JavaScript在页面渲染后才执行vue语句,所以{{ txt }}
会被原文输出;vue处理完数据渲染页面后显示处理后的内容,页面会闪烁一下;
解决方法:
- 在标签内使用
v-text
代替标签内{{ }}
- 使用
v-cloak
如果只是几个标签的数据,使用v-text
;
如果有大量的标签需要使用vue来渲染页面,直接给父元素添加v-cloak
;
v-if 和 v-show
v-if指令:
- 写在标签上:值为true时显示此标签,值为false时隐藏此标签;
- 如果隐藏时,这个标签会从页面上删除;
- 切换显示/隐藏时,创建/删除这个标签;浪费性能;
- 只需要切换一次状态,例如:许愿墙删除某个留言;
v-show指令:
- 写在标签上:值为true时显示此标签,值为false时隐藏此标签;
- 如果隐藏时,这个标签会添加行内样式
display: none;
,在页面上隐藏; - 切换显示/隐藏时,通过css来操作这个标签;性能高,不需要创建和删除;
- 需要频繁的切换元素显示/隐藏时,使用
v-show
1 | <h1 v-if="isShow">您能看到我</h1> |
v-else-if 和 v-else
分支语句,用来根据条件判断来显示哪一个标签;
v-else
限制:前一兄弟元素必须有 v-if
或 v-else-if
。
v-else-if
限制:前一兄弟元素必须有 v-if
或 v-else-if
。
1 | <div v-if="type === 'A'"> |
v-once 和 v-pre
v-once指令:
- vue只会解析处理带有
v-once
指令的标签一次,后续数据更新也不会再次来解析处理这个标签的内容;
v-pre指令:
- vue不会解析带有
v-pre
指令的元素,一次都不会,直接忽略掉; - 一般应用于没有表达式和指令的元素,例如:内容是大量的文章内容,会提升Vue渲染整个页面的性能;
过滤器
过滤器的作用:数据格式化(数据按照某个格式输出展示)
在Vue中使用filter()
方法来格式化数据输出格式;
- 第一个参数:表示过滤器的名称
- 第二个参数:是一个回调函数,当使用该过滤器的时候,这个回调函数就会执行。格式化数据的代码逻辑就放在这个回调函数中;
- 回调函数的第一个参数:需要格式化的数据,在标签内使用过滤器时,自动把数据传递到回调函数中;
- 通过回调函数的返回值来决定格式化后要展示的内容;
|
也被称为:管道符号
1 | <h1>{{ time | date }}</h1> |
回调函数内可以传递多个参数;
- 在元素内第一个参数不需要写,默认自动传递,只需要在回调函数内使用形参来接收就可以;
- 在ES6中形参默认值可以直接在小括号内设置,
val1 = 'YYYY-MM-DD HH:mm:ss'
:如果传递了就使用传递的参数,如果没有传递就是用”=”后面的默认参数;
1 | <p>{{ time | date('YYYY-MM-DD', 123) }}</p> |
局部过滤器
1 | const vm = new Vue({ |
【过滤器可以直接在new Vue()实例对象的参数内部,表示是这个实例对象的过滤器;如果有多个实例对象,建议在全局使用;】
【一定要在vm实例对象之前使用,注意代码的执行顺序;】
日期格式化 - 第三方包
安装:
1 | npm i moment |
使用:
- 通过
<script src="./moment.js">
来引入; - 直接使用
moment().format()
就可以了;- moment() 函数的参数为:要格式化的日期对象;
- format() 对日期进行格式化,参数表示:格式
1 | Vue.filter('date', function (input, val1 = 'YYYY-MM-DD HH:mm:ss', val2) { |
Vue生命周期
- 所有的 Vue 组件都是 Vue 实例,并且接受相同的选项对象即可 (一些根实例特有的选项除外)。
- 实例生命周期也叫做:组件生命周期
- 挂载阶段
- 更新阶段
- 卸载极端
生命周期介绍
- vue生命周期钩子函数
- 简单说:一个组件从开始到最后消亡所经历的各种状态,就是一个组件的生命周期
生命周期钩子函数的定义:从组件被创建,到组件挂载到页面上运行,再到页面关闭组件被卸载,这三个阶段总是伴随着组件各种各样的事件,这些事件,统称为组件的生命周期函数!
- 注意:Vue在执行过程中会自动调用
生命周期钩子函数
,我们只需要提供这些钩子函数即可 - 注意:钩子函数的名称都是Vue中规定好的!
钩子函数
钩子函数 - beforeCreate()
- 说明:在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用
- 注意:此时,无法获取 data中的数据、methods中的方法
钩子函数 - created()
- 注意:这是一个常用的生命周期,可以调用methods中的方法、改变data中的数据
- vue实例生命周期 参考1
- vue实例生命周期 参考2
- 使用场景:发送请求获取数据
钩子函数 - beforeMounted()
- 说明:在挂载开始之前被调用
钩子函数 - mounted()
- 说明:此时,vue实例已经挂载到页面中,可以获取到el中的DOM元素,进行DOM操作
钩子函数 - beforeUpdated()
- 说明:数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。你可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程。
- 注意:此处获取的数据是更新后的数据,但是获取页面中的DOM元素是更新之前的
钩子函数 - updated()
- 说明:组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。
钩子函数 - beforeDestroy()
- 说明:实例销毁之前调用。在这一步,实例仍然完全可用。
- 使用场景:实例销毁之前,执行清理任务,比如:清除定时器等
钩子函数 - destroyed()
- 说明:Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
axios
- 以Promise为基础的HTTP客户端,适用于:浏览器和node.js
- 封装ajax,用来发送请求,异步获取数据;
安装:
1 | npm install axios |
使用:
1 | <script> |
通过.then((res) => {})
中的回调函数来获取返回的数据,res
来接收返回的数据,这个数据是axios已经处理好的;
json-server
json-server 包的作用:
- 能够根据一个json文件,快速生成针对于这个json文件的 增删改查 接口
- 使用这个工具,可以很方便的作为接口来测试功能
场景:我们写了一个demo,但是,不会写服务端代码,这个时候,只需要通过json-server就可以生成所有 CRUD 的接口了
使用:
- 全局安装 npm i -g json-server
- 创建一个json文件
- 在json文件所在目录中打开终端(命令工具)
- 指定命令: json-server ./brand.json
并且会设置好跨域的问题;
获取数据:axios.get(url).then((res) => {})
url:地址
添加数据:axios.post(url, data).then((res) => {})
data:添加的数据
删除数据:axios.delete(url + id).then((res) => {})
id:需要删除的数据对应id
按键修饰符
键盘事件:keydown keypress keyup
在监听键盘事件时,我们经常需要检查常见的键值。Vue 允许为 v-on 在监听键盘事件时添加按键修饰符:
1 | <!-- 只有在 `keyCode` 是 13 时调用 `vm.submit()` --> |
记住所有的 keyCode 比较困难,所以 Vue 为最常用的按键提供了别名:
全部的按键别名:
- .enter
- .tab
- .delete (捕获“删除”和“退格”键)
- .esc
- .space
- .up
- .down
- .left
- .right
1 | <!-- 同上 --> |
可以通过全局 config.keyCodes
对象自定义按键修饰符别名:
1 | // 可以使用 `v-on:keyup.f1` |
【在某些情况下,按键修饰符不会生效,需要使用 .native
使事件生效;】
例如
1 | <input v-on:keyup.enter.native="submit"> |
监视数据
在 Vue 中提供了监听数据变化的方法,可以通过 watch:{}
对象来设置对那些数据进行变化监听;
为需要监听的数据设置方法,每当数据发生变化时就会触发这个方法(函数);
对简单类型数据和复杂类型数据监听;
- 简单类型数据监听可以看成是复杂类型数据监听方法的简写;
- 简单数据类型也可以使用复杂类型数据监听方法;
1 | <div id="app"> |
计算属性
- Vue 处理页面,当动态数据发生改变的时候,页面内的所有指令和表达式都会重新计算一次;在某些情况下,当其中一部分数据发生改变时,也会引起另一部分数据变化,所以某些使用动态数据渲染的页面会频繁更新,会带来极大的性能问题;
使用计算属性 computed:{}
来解决这一问题:
在模板中不直接使用a数据,使用计算属性内c数据来渲染模板,c数据依赖a数据,只有当a数据发生改变c数据才会重新计算;
计算属性采用的是缓存机制,计算后的数据存在缓存中,可以直接多次调用,而不用重复计算;
1 | <div id="app"> |
- 模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。
1 | <div id="example"> |
在这个地方,模板不再是简单的声明式逻辑。你必须看一段时间才能意识到,这里是想要显示变量 message 的翻转字符串。当你想要在模板中多次引用此处的翻转字符串时,就会更加难以处理。
所以,对于任何复杂逻辑,你都应当使用计算属性。
1 | <div id="example"> |
组件化开发
因为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。
你可以将组件进行任意次数的复用;并且维护方便;
全局组件
全局组件,可以任意使用,嵌套关系之间没有限制;
使用 Vue.component()
来创建组件
1 | <div id="app"> |
【注意:template 配置模板,HTML结构只能有一个根元素;不能有多个根元素否则会报错;】
组件的数据和其他配置项
Vue 数据
定义一个组件,内部的数据 data 不是一个对象而是一个函数,通过这个函数内部 return 一个对象来使用数据;
1 | Vue.component('hello', { |
组件的通讯
【每一个组件都是一个封闭的个体,不能直接使用外部的数据;需要使用 组件通讯 策略;】
【注意:HTML标签内部不支持大写,在使用驼峰命名法的饿时候一定要注意;】
父级组件向子组件传递数据
- 父级组件内准备需要向子组件传递的数据,
data () {return {parentMsg: '撩妹',money: 100000000000000}}
- 在子组件的标签上设置属性
<child v-bind:skill="parentMsg" :money="money"></child>
- 子组件中通过
props: ['skill', 'money']
来接收父级组件传递来的数据 - 子组件中就可以使用这些数据了;
- props 接收的数据是直读属性,不支持修改,修改会报错;动态传递的,父级数据修改后,会自动同步;】
1 | <div id="app"> |
子组件向父级组件传递数据
- 父级组件提供一个方法
- 在子组件标签上设置自定义事件
- 子组件调用这个方法,将需要的传递的数据作为参数传递
- 父级组件通过这个方法接收到子组件传递过来的数据,设置给动态数据
1 | <div id="app"> |
非父子组件数据传输
一种通用的组件通讯,用于组件之间的数据传递,可以是父子组件(嵌套),也可以是兄弟,也可以是多层级之间的组件通讯;
- 创建一个空的 Vue 实例,
const bus = new Vue()
专业名称:事件总线; - 需要传递数据的两个组件通过在 bus(事件总线) 上注册方法 / 调用方法来传递数据;
- 需要接收数据的A组件在 bus(事件总线)注册一个方法;
- 传递数据的B组件通过调用A组件在 bus(事件总线) 注册的方法,将数据作为参数传递过去;
- A组件就可以通过B组件调用这个方法获得数据了;
1 | <body> |
局部组件
局部组件是在一个 Vue 实例内部的组件,只有父子级关系才能使用嵌套关系,否则会报错;只有父子级关系才能是嵌套(不能跨代,不能同级)。
Vue 实例内部和组件内部都可以创建局部组件,使用限制:局部组件只能在内部被使用;
组件是独立的个体,不能是外部数据,嵌套关系也不能使用;
1 | <body> |
slot 内容分发插槽
<slot></slot>
元素作为组件模板之中的内容分发插槽。<slot></slot>
元素自身将被替换。
在页面中使用组件时,组件标签内部的内容不会被识别(元素或者字符串);HTML标签内的内容替换掉这个标签 <slot></slot>
;
1 | <body> |
具名插槽
- 模板中根据name属性对应slot标签,进行内容替换;
- 不具名的slot对应没有name属性的节点;没有slot则被忽略掉,没有节点内容则不解析;
- 与HTML标签内的顺序无关,只和组件中模板的顺序有关;
- 不要混写具名和不具名的内容节点;
1 | <body> |
SPA -单页应用程序
- 单页Web应用(Single Page Application,SPA),就是只有一个Web页面的应用,是加载单个HTML页面,并在用户与应用程序交互时动态更新该页面的Web应用程序。
- 对于传统的多页面应用程序来说, 每次请求服务器返回的都是一个完整的页面;
- 对于单页应用程序来说, 只有第一次会加载页面, 以后的每次请求, 仅仅是获取必要的数据.然后, 由页面中js解析获取的数据, 展示在页面中
优势:
- 减少了请求体积,加快页面响应速度,降低了对服务器的压力
- 更好的用户体验,让用户在web app感受native app的流畅
主要技术点
- ajax 请求数据
- 哈希值(锚点)的使用(window.location.hash #)
- 哈希值 URL中#后的数据值;通过
location.hash
可以获取到带#的哈希值;
- 哈希值 URL中#后的数据值;通过
- hashchange 事件
- 当URL的片段标识符更改时,将触发hashchange事件 (跟在#符号后面的URL部分,包括#符号)
实现思路
- a标签的锚点跳转
- 监听锚点值变化的事件,根据不同的锚点值,请求相应的数据
- 1 锚点(#)原本用作页面内部进行跳转,定位并展示相应的内容
- 2 SPA中,锚点被用作请求不同资源的标识,请求数据并展示内容
1 | http-server 包的使用: |
路由
路由即:浏览器URL中的哈希值(# hash)与展示视图内容(template)之间的对应规则
vue中的路由是:hash 和 component的对应关系,一个哈希值对应一个组件
- 在 Web app 中,通过一个页面来展示和管理整个应用的功能。
- SPA往往是功能复杂的应用,为了有效管理所有视图内容,前端路由 应运而生!
- 简单来说,路由就是一套映射规则(一对一的对应规则),由开发人员制定规则。
- 当URL中的哈希值(# hash)发生改变后,路由会根据制定好的规则,展示对应的视图内容
Vue Router 基本使用
Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。
包含的功能有:
- 嵌套的路由/视图表
- 模块化的、基于组件的路由配置
- 路由参数、查询、通配符
- 基于 Vue.js 过渡系统的视图过渡效果
- 细粒度的导航控制
- 带有自动激活的 CSS class 的链接
- HTML5 历史模式或 hash 模式,在 IE9 中自动降级
- 自定义的滚动条行为
使用步骤:
- 引入 Vue.js 和 vue-router.js 文件
- 创建路由规则(Vue 内部根据 URL 中哈希值来处理)
routes: []
用来配置路由规则- path 是路由规则,用来与浏览器地址栏中的哈希值进行匹配
- component 用来值该规则匹配后,要展示到页面中的组件内容
- 默认的路由为 /,所以,进入页面就匹配该路由规则
- redirect 跳转到对应的哈希值,相当于重定向
- 创建路由规则对应的组件
- 将 路由 关联到 Vue 的实例
- 指定路由出口,在HTML页面中的位置
- 在HTML页面中使用
<router-view></router-view>
指定路由出口的位置
- 在HTML页面中使用
- 指定路由入口,相当于导航菜单
- 在HTML页面中使用
<router-link to="home">黄河</router-link>
指定路由入口 to="home"
会自动为在当前URL后再次添加此哈希值,并跳转到锚点;不删除原来的值,如果当前本页面哈希值末尾部分与本次哈希值相同则不再添加本次哈希值to="/home"
会把当前URL地址#后的哈希值都删除掉,重新添加此哈希值,并跳转到锚点;会删除原来的值- 内部处理了slot,页面中可以识别标签内部的节点内容
- 在HTML页面中使用
【注意:添加哈希值时带 / (会删除掉原来#后面的值)和不带 / (不会删除原来#后面的值,在原来的值后面添加这个哈希值)】
1 | <body> |
Vue 路由菜单的两个类
Vue路由的入口,也就是在页面中显示的导航菜单,Vue 内部添加了两个类,这两个类会在点击了对应的菜单的导航上添加,其余的菜单会被移除;
可以通过这两个类在css中添加被选中后的样式;
1 | /* 精确匹配的类名: */ |
如果路由规则中设置的是 path: "/"
将会被 .router-link-active
模糊匹配到,也会被添加这个类,如果这个类设置了样式,这个导航就会和选中的效果一样;
可以在这个路由入口上添加 exact
属性,就会被精确匹配;
1 | <router-link to="/" exact>首页</router-link> |
Vue 嵌套路由
可以在路由中嵌套子路由,当我们需要在多层路由的时候,可以将路由添加在子组件的模板中;
子级路由配置,要写在父级路由的配置对象中;
【嵌套路由中,如果子路由规则匹配项没有带 / 则表示相对路径会在匹配项中会默认把父路由哈希值自动拼在前面,带 / 则表示绝对路径,就匹配以子路由的绝对路径哈希值;在路由入口中,设置跳转锚点哈希值时一定要注意与匹配规则对应;】
1 | <body> |
Vue 路由参数
如果类似新闻页面,多个新闻内容不同,页面结构相同,可以通过路由参数来设置路由规则;
设置了路由参数的规则,是动态路由,可以匹配所有符合这个规则但是参数不同的哈希值;
1 | const router = new VueRouter({ |
/newsinfo/:page
路由参数page
可以自定义;- 能够匹配的哈希值为:
/newsinfo/01 /newsinfo/02 /newsinfo/03
/newsinfo/a /newsinfo/xiaoming
- 但是无法匹配以下形式的哈希值:
/newsinfo/
/newsinfo
/newsinfo/01/abc
/newsinfo1
【/newsinfo/:page?
?
表示路由参数可选,可以有路由参数也可以没有路由参数;】
- 能够匹配的哈希值为:
/newsinfo/
/newsinfo
/newsinfo/01 /newsinfo/02 /newsinfo/03
/newsinfo/a /newsinfo/xiaoming
【this.$route
可以获取到路由参数】
可以通过 this.$route.params.page
来获取到这个动态的路由参数;
1 | // 在钩子函数内获取这个值的时候,如果在本页面改变了动态路由参数,Vue 会复用结构,这个钩子函数不会被执行 |
Webpack
bundle [ˈbʌndl]
捆绑,收集,归拢,把…塞入
- webpack 将带有依赖项的各个模块打包处理后,变成了独立的浏览器能够识别的文件
- webpack 合并以及解析带有依赖项的模块
概述
- webpack的两个特点:1 模块化 2 打包
webpack 是一个现代 JavaScript 应用程序的模块打包器(module bundler)
webpack 是一个模块化方案(预编译)
webpack 获取具有依赖关系的模块,并生成表示这些模块的静态资源
- 四个核心概念:入口(entry)、输出(output)、加载器loader、插件(plugins)
- webpack 与 模块化
1 | 模块化方案: webpack 和 requirejs(通过编写代码的方式将前端的功能,划分成独立的模块) |
- 一般项目上线的时候,会对项目进行打包
- 打包做什么??? js压缩、css压缩、less转css、HTML压缩 等
- 比如 .vue(Vue中的单文件组件) 需要经过webpack打包处理后,才能在浏览器中运行
- 比如 使用的ES6语法,浏览器不支持,但是,经过webpack打包处理后,浏览器就认识了
- 比如 修改代码后,浏览器自动刷新,也是webpack提供的功能+
- webpack 是基于 Node 的
- 但是,node.js中的代码几乎没有,用到: node模块化
webpack起源
- webpack解决了现存模块打包器的两个痛点:
- 1 Code Spliting - 代码分离
- 2 静态资源的模块化处理方案
webpack与模块
- 前端模块系统的演进
- 在webpack看来:所有的静态资源都是模块
- webpack 模块能够识别以下等形式的模块之间的依赖:
- JS的模块化规范:
- ES2015
import
export
- CommonJS
require()
module.exports
- AMD
define
和require
- ES2015
- 非JS等静态资源:
- css/sass/less 文件中的
@import
- 图片连接,比如:样式
url(...)
或 HTML<img src=...>
- 字体 等
- css/sass/less 文件中的
webpack文档和资源
安装webpack
安装:webpack模块 和 webpack命令行
1 | npm install -D webpack webpack-cli |
使用:
- 在 package.json 文件的 scripts 配置中配置:
"dev": "webpack ./src/main.js"
开发阶段使用默认 dev 命令 - 在项目的根目录中,打开终端,并且运行:
npm run dev
命令;webpack 打包生成的内容被自动生成到:dist目录中
main.js 打包入口文件,导入模块
1 | // 导入jquery,安装了 jQuery 包后 通过 import { } from "module" 导入 |
注意:浏览器不能识别 import 这个语法,因此,无法直接在浏览器中使用该js文件
解决方式:使用 webpack 对该文件进行打包处理,在页面中使用打包后的js文件
配置文件 package.json 文件的 scripts 配置:"dev": "webpack ./src/main.js --mode development --watch"
./src/main.js
指定了webpack打包的入口文件--mode development
表示:指定webpack的模式为开发模式(代码不压缩)--watch
参数来监视文件变化,当js文件内容改变后,webpack 会自动对其进行打包处理
webpack中有两种运行模式;
- development(开发模式) 代码未压缩
- production(生产模式) 代码压缩
webpack 的配置文件 webpack.config.js
使用说明
项目的根目录中创建 webpack 的配置文件;名称约定为 webpack.config.js
配置文件 package.json 文件的 scripts 配置:"dev": "webpack"
webpack 的配置文件是运行在 Node 环境中的,因此,需要按照 node 的方式来写配置
【注意:在 webpack.config.js 配置文件中不要使用 import !!!因为 node 也不能处理 import 关键字!!!】
只要使用 webpack,不管是 命令行 还是 配置文件,都要:在index.html页面中,手动引入 <script src="../dist/main.js"></script>
1 | // 导入path模块(内置模块) |
webpack-dev-server
在开发期间会使用webpack的一个辅助包: webpack-dev-server;
- 自动搭建开发环境
- 自动开启HTTP服务
- 自动打开浏览器(以HTTP协议的方式)
- 自动监视文件变化
- …
安装:
1 | npm i -D webpack-dev-server |
修改 scripts 中的dev命令为: webpack-dev-server
ebpack-dev-server 不会帮我们生成一个 dist 目录
对比 webpack 和 webpack-dev-server 两个命令:
- webpack 会在磁盘中生成一个 dist 目录
- webpack-dev-server 不会往磁盘中生成dist目录,而是放在内存中了
- 往内存中存内容,要比往磁盘中存内容,快得多
配置文件 package.json 文件的 scripts 配置:"dev": "webpack-dev-server ./src/main.js --mode development --open --contentBase ./src"
./src/main.js
指定了webpack打包的入口文件--mode development
表示:指定webpack的模式为开发模式(代码不压缩)--open
自动打开浏览器--contentBase ./src
表示:默认打开哪个文件中的 index.html 页面--port 9999
修改默认端口号为 9999--hot
热更新,修改了哪个地方将来就只会更新修改的内容
webpack-dev-server 的配置文件 webpack.config.js
使用说明
配置文件 package.json 文件的 scripts 配置:"dev": "webpack-dev-server"
【命令行可以和配置文件一起来使用;比如:webpack-dev-server --hot
,表示:通过命令行的方式开启热更新,而其他的配置项从配置文件中读取】
【注意:只要配置文件的内容修改了,就需要重启 npm run dev
命令,那么,配置才会生效】
html-webpack-plugin插件
作用:能够自动帮我们引入 js/css 等文件,在内存中根据模板生成一个页面的页面
该插件根据我们指定的模板路径,在内存中根据这个模板生成了一个页面;在生成的页面中自动引入了js文件。并且,在浏览器中打开的就是这个自动生成并且自动引入js文件的页面
安装:
1 | npm i -D html-webpack-plugin |
在 webpack.config.js 文件中配置该插件
- 导入 html-webpack-plugin 包
- 在 plugins 中
new HtmlWebpackPlugin()
- 指定模板路径
template: path.join(__dirname, './src/index.html')
处理 css / less 文件
非 JavaScript 文件处理:webpack 自身只能处理js文件,所以,对于 非JS 文件来说,需要专门的 loader 来进行响应的处理!!!
处理 css 文件
安装:
1 | npm i -D style-loader css-loader |
在 webpack.config.js 文件中配置 loader 来处理css文件
- 通过 module 配置 loader,处理 非JS 文件
- 通过 rules 来配置处理 非JS 文件的规则
- use 中配置的loader是有顺序的!先配置 style-loader 再配置 css-loader
- use 执行的顺序是:从右往左,也就是:先调用 css-loader,在调用 style-loader
- css-loader 读取css文件的内容,并且根据这个css内容,来创建一个模块(node)
- style-loader 根据模块内容,创建一个style标签,然后,插入页面中
处理 less 文件
安装:
1 | npm i -D less less-loader |
less-loader 需要 style-loader css-loader
less-loader 依赖于 less 包;less 包就是用来将 less 语法转化为 css 语法的
1 | // 引入less文件 |
- 通过 less-loader 用来将 less 转化为css文件,之后再按照处理 css 文件的方式处理
- use 中配置的loader是有顺序的!先配置 style-loader 再配置 css-loader 再配置 less-loader
- use 执行的顺序是:从右往左,也就是:先调用 less-loader,再调用 css-loader,再调用 style-loader
处理图片和字体文件
安装:
1 | npm i -D file-loader url-loader |
在 webpack.config.js 的 module 中配置一个 rule 规则
这两个包可以单独使用;如果使用 url-loader 那么,需要依赖于 file-loader
file-loader
- 会文件名称进行重命名操作,这样可以避免文件重复加载的问题
- 文件名是经过 MD5(特征码提取) 处理后, 得到一个32位的字符串: d5e6826816c62eb9aeb62dd4fb36d525
- 相同的内容, 不管经过MD5处理多少次, 得到字符串都是相同的(复制的图片,名字改了内容一样)
在程序中, 经常会使用 MD5 对密码进行加密:1 ===> MD5 ( 32位 ) + ‘随机字符串’ ===> MD5;先对密码进行 MD5加密处理, 然后, 将该结果拼接一个随机字符串, 再进行一次MD5加密, 将这个结果存储到数据库中
url-loader
- 会对图片文件进行 base64 编码处理,处理后,就变成了一种 base64 格式的图片字符串
- 浏览器能够解析这个字符串,所以,在浏览器中能够看到图片
- 精灵图:解决了小图片发送多次请求,有了精灵图以后,只需要发送一次请求
- 字体图标(font-awesome):将一些小图标集成到字体文件中,减少了网络请求
- base64 直接将小图标内嵌在 css 样式文件中,减少了网络请求
- 只有很小的图标,才应该使用 base64 的方式。
- 如果图片很大,反而会影响 网站加载 速度
base64 格式的图片字符串,相当于把图片转码成字符,可以内嵌在网页中;
字体图标的处理和图片一样;
babel的使用说明
babel是一个 JS 的编译器,能够将下一代的JS语法编译为浏览器能够识别的 ES5 的语法;通过babel,就可以在今天使用下一代的JS语法
如何使用:
- 安装:
npm i -D babel-core babel-loader babel-preset-env
- 在 webpack.config.js 中添加一个 rule 规则
- 在项目根目录中创建 babel 的配置文件叫: .babelrc
- 在配置文件中,配置babel
1 | { |
模块的作用
- babel-core 是babel的核心包
- babel-loader 用来加载js文件
- babel-preset-env 表示要让babel解析什么版本的JS,
- env: ES2015/ES2016/ES2017 的结合体
1 | ES6 ---> ES2015 |
1 | // 1 使用配置文件的方式来演示 webpack 和 webpack-dev-server 的使用 |
脚手架 vue-cli
在工作中开发 Vue 都是基于 webpack 来开发的,但是 webpack 很难用,配置项太多,导致用户放弃使用 Vue,Vue 的作者提供了一个脚手架命令 vue-cli
,通过这个命令行工具可以非常方便的生成一个配置好的完整 Vue 项目目录;
全局安装:
1 | npm i -g vue-cli |
使用:
1 | vue init webpack 项目名称 |
在需要使用的目录上级运行命令;可以生成这个 项目名称 文件夹,里面包含配置好的 webpack;
- 目录不要带有中文路径,项目名称不能大写,项目名称不要使用关键字 vue / vue-cli;
Vue 单文件组件
- vue-loader
- single-file components(单文件组件)
- 后缀名:
.vue
,该文件需要被预编译后才能在浏览器中使用 - 注意:单文件组件依赖于两个包 vue-loader / vue-template-compiler
安装:
1 | npm i -D vue-loader vue-template-compiler |
Vue 单文件组件使用
- 1 安装:
npm i -D vue-loader vue-template-compiler
- 2 在
webpack.config.js
中配置.vue
文件的loader{ test: /\.vue$/, use: 'vue-loader' }
- 3 在
webpack.config.js
中添加plugins
:const VueLoaderPlugin = require('vue-loader/lib/plugin')
new VueLoaderPlugin()
- 4 创建
App.vue
单文件组件,注意:App可以是任意名称 - 5 在
main.js
入口文件中,导入vue
和App.vue
组件,通过 render 将组件与实例挂到一起
App.vue
组件已经通过 render 将组件与实例挂到一起,相当于根组件了
1 | <!-- App.vue 示例代码: --> |
1 | // webpack.config.js 配置: |
1 | /* main.js */ |
Vuex
- 前提:只有在必要的情况下才使用Vuex工具,如果不需要Vuex,那就别用它
- 使用 Vuex 之后,会附加更多框架的概念进来,会增加项目的复杂度!!!
Vuex 是什么
- Vuex 是一个Vue的状态管理工具
- 状态,即:数据(组件、实例中的data)
- 状态管理,就是管理Vue项目中的数据
Vuex 能做什么
- 用来解决:组件通讯问题
- 优势:采用集中式,管理Vue项目中用到的所有数据
为什么需要使用 Vuex
- 问题:为什么需要使用 Vuex 来管理Vue项目中的数据?
1 | 在大型项目中,组件之间的通讯会变得混乱,为了更好的管理组件之间的通讯,也为了更容易的管理和 |
状态管理的介绍
- 最早的状态管理概念是在 React 中给提出的,Flux
Vuex 的使用
- 1 安装:
npm install vuex --save
- 2 先引入 Vue,再引入 vuex
- 因为 Vuex 是依赖于 Vue 的
1 | <body> |
Vuex 中的核心概念
- store:数据仓库
- 1 提供了 state
- 2 提供了操作 state 的方法(mutations)
- state:状态,也就是 数据(相当于data)
- mutations:操作数据的方法
- 只要修改state,就要通过 mutations 来修改!!!
- actions:异步操作数据
- 1 包含异步操作
- 2 最终,还是通过 mutations 来修改state
- getters:Vuex的计算属性
- 如果需要从现有的state中派生出一些状态,那就使用 getters
- 比如: 未完成任务数量 状态就可以从 任务列表(todoList) 中派生出来
store
store 是 Vuex 提供的数据仓库,所有的需要共享通讯的数据都放在这个数据仓库中;
1 | const store = new Vuex.Store({ |
state
state 就是状态,实例或者是组件中的数据(data);
【在实例或者组件中通过 this.$store.state
来获取到这个数据对象;】
实例或者组件可以通过 mapState
辅助函数来映射数据到自己的计算属性中;
mapState(['count'])
是一个对象可以通过对象解构语法展开;
mapState(['count', 'data1', 'data2'])
也可以同时映射多个数据;
1 | const store = new Vuex.Store({ |
就可以直接使用这个数据;
1 | <!-- 1 简写映射 2 箭头函数映射 --> |
mutations
实例或者组件通过 this.$store.state
可以读取到数据仓库中的数据,但是如果需要修改数据,就需要使用 mutations
操作数据;
【如果数据是复杂类型的,可以直接修改复杂类型的属性,前提是不能修改引用地址;简单类型修改数据就是重新赋值了;】
在 mutations
对象中提供需要操作数据的方法,实例或者组件通过 this.$store.commit(handler, Payload)
来调用这个方法来修改数据;
- 在
mutations
对象声明的方法,有两个参数;- 参数:state 表示 Vuex 中的数据,通过这个参数可以直接操作
$store.state
这个数据对象; - 参数:Payload 表示传递的修改数据的参数对象;
- 参数:state 表示 Vuex 中的数据,通过这个参数可以直接操作
this.$store.commit(handler, Payload)
- 参数:handler 表示在
mutations
对象中声明的方法,是一个字符串方法名; - 参数:Payload 表示需要修改数据的参数
- 参数:handler 表示在
1 | <body> |
Vue 电商管理后台项目
项目前言
Vue的两种构建版本:
- 完整版:编译器+运行时
- 运行时版本:文件体积更小,运行速度更快
脚手架中使用的:完整版
默认通过 import Vue from 'vue'
导入的是运行时版本
脚手架中,通过一个配置,让默认导入的版本为:完整版
1 | alias: { |
在导入完整版Vue后,需要使用以下方式来处理组件
1 | import App from './App' |
初始化项目
- 将
src
目录中原来默认生成的内容,全部删除
1 | 源码全部放在 src 目录,只要修改 src 目录中的内容即可: |
关闭ESLint
- 在
/config/index.js
中useEslint:false
如何开一个新功能
- 1 在
components
目录中创建组件 - 2 在
router/index.js
中配置路由
Element-UI的使用
- 1 安装:
npm i element-ui -S
- 2 在
main.js
文件中导入element-ui的js和样式,并且安装称为插件
1 | import Vue from 'vue' |
- 3 打开element-ui的文档,从左侧菜单中找到对应的组件,参考示例代码,复制到自己页面中使用即可
axios发送请求
- 1 安装:
npm i -S axios
- 2 导入:
import axios from 'axios'
- 3 使用:
axios.post(接口地址, 参数).then(成功).catch(失败)
vue-router 编程式导航
- 通过JS代码来实现跳转:
this.$router.push('/home')
session说明
HTTP协议是:无状态
对于服务器来说,服务器是不会记忆两次请求是不是同一个浏览器发送过来的
但是,服务器不知道这两次请求是同一个人发送过来的,因此,登录功能就无法实现了;
状态保持:为了让服务器知道两次请求是同一个人发送过来的;
对于 状态保持 来说,第一次登录成功了,服务器会给我们分配一个唯一不会重复的 sessionid,并且,以后的每次请求,都会携带这个 sessionid ,这样,服务器就可以根据这个 sessionid 来判断你是否登录过了;
注意:两个不同的人登录,会得到不同的 sessionid
session 机制,是服务器默认就支持的一种状态保持机制,seesion 一般都会配合 cookie 使用
对于使用 token 机制的服务器来说:
- 在登录成功后,获取到 token
- 并且,以后的每次请求中,都需要手动将 token 传递给服务器,那么,服务器才知道你登录了
- 并且,才能根据token值来区分是哪个用户
简单来看,sessionid+cookie 和 token 机制,就是实现的相同的功能
token 验证机制
样式写在哪
- 说明:全局样式写在
index.css
中,组件的样式写在自己组件的style中
在组件中使用预编译CSS
- 直接安装loader的包:
npm i -D less-loader less
就可以使用 Less 了 <style lang="less"></style>
标签内可以以直接写 less 语法
抽离单文件组件的内容
- 说明:如果将所有的template、script、style都放在 .vue 文件中,那么,这个文件会变的非常臃肿。可以将 不同的内容,抽离到单独的文件中
1 | <!-- 将 模板 抽离到,当前目录下的:template.html文件中 --> |
如果需要使用 less 在 <style src="./style.less" lang="less"></style>
标签中加入 lang="less"
,并且引入的是less文件即可;
带token请求接口
- 说明:除了登录接口以外,其他接口都需要 token 才能够成功获取数据
1 | axios |
Vue 中使用 .sync
修饰符
在有些情况下,我们可能需要对一个 prop 进行“双向绑定”。不幸的是,真正的双向绑定会带来维护上的问题,因为子组件可以修改父组件,且在父组件和子组件都没有明显的改动来源。
通过使用 .sync
修饰符来修改数据,其实现原理是:父组件传递数据给子组件,子组件使用 prop 接收,不支持子组件直接修改 prop 中的数据,如果需要修同步数据,则使用子组件向父组件传递数据,通过父组件中提前声明的方法来修改父组件传递给子组件的数据,以达到同步数据的问题;
通过父组件提供方法,由子组件调用,并传递新的数据给父组件,然后父组件来修改数据;可以通过 .sync
修饰符来简写这一过程,Vue 提供了这个方法。
.sync
对应的方法就是 update:title
;
1 | // 创建父组件: |
配置 axios
在入口文件中引入 axios;把 axios 添加到 Vue 的原型中;
组件可以看成是 Vue 的实例,组件可以通过使用构造函数的原型的方法来使用 axios;
1 | import axios from 'axios' |
axios 公共的接口地址
只要配置该基础地址后,axios 会在每次发送请求的时候,将 baseUrl 和 当前请求的接口 合并到一起
比如:当前请求接口为:/login
,那么 axios 会将 baseUrl + login
得到:http://localhost:8888/api/private/v1/login
最终的完整接口地址了
会自动解析接口开头是否带有 /
1 | axios.defaults.baseURL = 'http://localhost:8888/api/private/v1/' |
axios 拦截器
axios 提供请求和响应拦截器,在发送请求之前,和接收响应数据之后,可已通过拦截器对这些数据操作;
【回调函数的接收这些请求或者相应数据参数就是这些数据,操作完数据之后需要返回新的数据,return config
】
1 | // Add a request interceptor |
数据修改和DOM更新的问题
- 问题描述:
1 | 因为 权限对话框 一开始隐藏的, 所以 Vue 是不会渲染该对话框的DOM内容的 |
- 解决问题:
1 | // 在修改数据后, 可以在 $nextTick() 的回调函数中, 获取到更新后的DOM内容 |
element-tree-grid
- 1 安装:
npm i -S element-tree-grid
- 2 在 main.js 中,注册全局组件:
1 | import ElTreeGrid from 'element-tree-grid' |
1 | <!-- |
用户管理 - 分配角色
- 1 点击分配角色按钮,展示对话框
- 2 展示用户名以及所有的角色列表
- Select 选择器 组件
- 3 选中当前用户的角色
- 4 获取到当前选中的角色,给当前用户分配角色
- 查看接口,需要什么样的数据,就获取什么数据,然后,发送请求
左侧菜单的展示
- 权限 和 菜单 是关联在一起的,也就是说:具有这个权限才会有对应的菜单
- 不同的用户具有不同的角色,而不同的角色具有不同的权限,也就是:具有不同菜单
- 问题:在获取左侧菜单的时候,没有传递 userId 这样能区分不同用户的信息,但是每个用户登录后,左侧菜单还是不同的,内部是如何区分不同用户的呢?
- 答案:服务端通过 token 来区分不同用户,说明 token 中包含了 userId 这样区分用户id的数据
quill-editor
- 安装:
npm i -S vue-quill-editor
- vue-quill-editor
1 | <quill-editor |
按需加载
- 1 修改
router/index.js
中导入组件的语法
1 | // 使用: |
- 2 (该步可省略)修改
/build/webpack.prod.conf.js
中的chunkFilename
1 | { |
使用CDN
- 开源项目 CDN 加速服务
- 1 在
index.html
中引入CDN提供的JS文件 - 2 在
/build/webpack.base.conf.js
中(resolve前面)添加配置 externals - 注意:通过CDN引入 element-ui 的样式文件后,就不需要在 main.js 中导入 element-ui 的CSS文件了。所以,直接注释掉 main.js 中的导入 element-ui 样式即可
externals
配置:
1 | externals: { |
常用包CDN
- vue
- vue-router
- axios
- element-ui JS
- element-ui CSS
- 说明:
- 1 先在官方文档查找提供的CDN
- 2 如果没有,在
https://www.bootcdn.cn/
或其他 CDN提供商 查找
缓存和保留组件状态
- keep-alive
- 解决方式:使用
keep-alive
,步骤如下:
1 | 1 在需要被缓存组件的路由中添加 meta 属性 |
启用路由的 History 模式
- 通过在路由中添加
mode: 'history'
可以去掉 浏览器地址栏中的 # - 在开发期间,只需要添加这个配置即可
- 但是,在项目打包以后,就会出现问题
1 | // 去掉 # 后,地址变为: |
后端的处理方式
- 1 优先处理静态资源
- 2 对于非静态资源的请求,全部统一处理返回 index.html
- 3 当浏览器打开 index.html 就会加载 路由的js 文件,那么路由就会解析 URL 中的 /login 这种去掉#的路径了