html
html [1990]----> html5 [2008.1.12]
css
css 1.0 1996
css 2.0 1998
css 3.0 2001
EcmaScript
1997年诞生
2015 EcmaScript 2015
2016 EcmaScript 2016 dart语言 vs javascript
随着前端项目的逻辑越来越复杂和难以维护,那么前端这边引进了后端的架构思想( MV* )
M Model 数据层
V View 视图层
C Controller 控制器 ( 业务逻辑 ) MVC
P Presenter 提出者( Controller 改名得来的 ) MVP
VM ViewModel 视图模型( 业务逻辑 VM 是 由 P 改名得来的) MVVM
Backbone.js MVP 2010.10
Angular.js( 1.0 ) MVC 2010.10
Angular.ts ( 2.0 ) MVC -> MVVM 2016 目前已经更新到了 Angular9 ( 也属于angular2.0 版本 )
Vue 1.0 MVVVM 2014/07
Vue 2.0 MVVM 2016/09
React 2012 不太认可前端MVC这种架构思想, 你可以将React单纯看做是MVC中V
github统计量 ( 国际使用量 )不代表大陆地区 单位是: K
angular.js angular.ts vue React
59.6 49.1 146 134
学习难度: Vue < React < Angular( 2.0 )
前端流行
移动 web && hybird app( 混合app )
app
1. native app ( 安卓 ios java ME)
2. webapp ( 应用在浏览器中的app )
3. Hybird app ( 混合app )
1. webapp 嵌入 第三方原生应用库( 可以访问原生设备(手机) 的接口权限,比如:照相机 )
2016年:
1. es6
2. vue2.0
3. angular2.0x
4. 微信小程序 / 微信小游戏
总结表:
[外链图片转存失败(img-DHkj6OLI-1568092342824)(E:\工作文件\2019-三阶段-授课笔记\2\img\前端框架时间图.png)]
前端js框架到底在干嘛! 为什么要用?
js框架帮助开发者写js逻辑代码,在开发应用的时候js的功能划分为如下几点:
渲染数据
[外链图片转存失败(img-faTMGwAX-1568092342826)(E:\工作文件\2019-三阶段-授课笔记\2\img\购物车.png)]
操作DOM
[外链图片转存失败(img-frnMFlmt-1568092342828)(E:\工作文件\2019-三阶段-授课笔记\2\img\2019-01-11-03.gif)]
操作cookie等存储机制api
[外链图片转存失败(img-slQvxbJz-1568092342829)(E:\工作文件\2019-三阶段-授课笔记\2\img\cookie.png)]
在前端开发中
官网地址: 英文官网 中文官网
Vue.js框架项目介绍
作者: 尤雨溪
[外链图片转存失败(img-yGxR6yKH-1568092342830)(E:\工作文件\2019-三阶段-授课笔记\2\img\尤雨溪.jpg)]-
Vue.js是尤雨溪的个人项目
Vue.js也是一个MVVM框架
Vue.js它是一个单项数据流的框架
Vue.js是一个Js渐进式框架
学习Vue的必要性
Vue近几年来特别的受关注,三年前的时候angularJS霸占前端JS框架市场很长时间,接着react框架横空出世,因为它有一个特性是虚拟DOM,从性能上碾轧angularJS,这个时候,vue1.0悄悄的问世了,它的优雅,轻便也吸引了一部分用户,开始收到关注,16年中旬,VUE2.0问世,这个时候vue不管从性能上,还是从成本上都隐隐超过了react,火的一塌糊涂
学习vue是现在前端开发者必须的一个技能
MV*模式图示
书写第一个Vue案例
Vue深入响应式原理图
[外链图片转存失败(img-v7bcVJYh-1568092342831)(E:\工作文件\2019-三阶段-授课笔记\2\img\data.png)]
// Vue 底层原理
// 目的: 使用原生js来实现Vue深入响应式
var box = document.querySelector('.box')
var button = document.querySelector('button')
var data = {
name: 'Jick'
}
// 观察者对象
var observer = {...data}
// es5提供的api方法,这个方法不兼容ie8以及以下
// Object.defineProperty(对象,对象的属性,对象属性的修饰符 )
Object.defineProperty( data,'name',{
// get/set 统称为: '存储器'
get () {
return observer.name // 初始化赋值一个值给name属性
},
set ( val ) {
console.log( val )
box.innerHTML = val
}
})
button.onclick = function () {
data.name = "Rose"
}
box.innerHTML = data.name
mustache 语法中是支持写js的
用法:
内容: 必须加 {{ js语法 }}
属性: 属性中属性值可以直接写js语法,并且属性值中的数据相当于全局变量
给一个标签加一个自定义属性/已有属性
img中的src就是已有属性
//data-index就是自定义属性 , web网页中建议我们使用data-形式来定义自定义属性
思考: Vue现在想要在html中使用自己的属性,并且要和他的语法和数据结合?
咋整?
分析: 如何我能够标识出哪一个属性是具有vue标志的那就好了,也就是属性前加 v
div>
-
研究它js的支持性
- 数据类型
- 市场上js的数据类型分类有两种?
- 第一种
- 初始数据类型: number string null undefine boolean
- 引用数据类型: Object [ function array … ]
- 第二种
- 基础数据类型: number string boolean
- 特殊数据类型: null undefine
- 复杂数据类型; Object [ function array …]
- 输出语法
- console
- alert
- 表达式 / 运算符
- 三元表达式
-
总结;
- null 和 undefined 是不会显示的,其他数据类型都是支持的,可以显示的
- 挂载在window身上的全局属性,我们都不能用的: 比如; console alert
- {{ }} 不写流程控制
- for
- if
- while
- do…while
- {{}} 支持三元表达式,同样也支持运算符
- 短路原则也是支持的
2.2 指令
指令的目的是做什么: 操作DOM
解释 : MVVM vm -> v 数据驱动
所以: 今天开始,我们不想二阶段一样操作dom,改成操作数据,数据要想操控DOM,那么我们需要依赖指令,因为指令是直接绑定在dom身上的
-
v-html 转义输出,也就是可以解析 xml 数据
-
v-text: 非转义输出,也就是无法解析 xml 类型数据
-
v-bind
-
将数据和属性进行单向数据绑定: 将vue中数据赋值给属性值
div>
div>
-
简写形式
<img v-bind:src="src" alt="">
<img :src="src" alt="">
-
类名绑定
-
用法
-
对象形式用法
p>
p>
p>
-
数组形式用法
p>
p>
p>
-
样式绑定
-
用法
-
对象形式用法
p>
p>
-
数组形式用法
p>
p>
2.3 条件渲染
-
v-if
-
v-else-if
-
v-else
-
v-show 条件展示
<h3> 条件渲染 - 单路分支 h3>
A p>
<h3> 条件渲染 - 双路分支 h3>
A p>
<p v-else > B p>
<h3> 条件渲染 - 多路分支 h3>
美食 p>
游戏 p>
<p v-else> 睡觉 p>
<h3> 条件展示 h3>
条件展示 p>
-
思考总结
思考: v-if vs v-show
1. 效果看起来一样
2. why Vue要出两个相似的指令?
v-if控制的是元素的存在与否
v-show控制的是元素的display:none属性
思考? 如果出事条件为假时? v-if v-show 谁的性能损耗较高?
v-show
总结: 项目中如何选择哪一个?
频繁切换用 v-show
如果不是很频繁的切换,那我们用 v-if
2.4 列表渲染
-
v-for 指令
<h3> 数组 h3>
<ul>
-
{{ item }} -- index{{ index }}
li>
ul>
<h3> 对象 h3>
<ul>
-
{{ item }} -- {{ key }} -- {{ index }}
li>
ul>
<h3> json h3>
<ul>
-
<span> 商品名称: {{ item.shop_name }} span>
<span> 商品价格: {{ item.price }} span>
li>
ul>
<h3> 循环嵌套 h3>
<ul>
-
<h3> 商品类型: {{ item.shop_name }} h3>
<ul>
-
<p> 制造商: {{ item.maker }} p>
li>
ul>
li>
ul>
<h3> 循环number / string h3>
{{ item }} p>
{{ item }} p>
-
总结:
-
- 列表渲染参数可以写三个,分别为 item key index
-
- 列表渲染,要在渲染的元素身上加一个key,作为这个元素唯一的标识 ,
- 思考: 这是为什么?
- 这个key最好是id,因为id唯一?思考: 为什么不能是index
-
- 循环嵌套式,参数名称是可以一致的
-
- in / of 都可以使用
2.5 事件处理器
-
v-on
-
key的重要性
给列表渲染的每一层Vdom添加一个唯一标识,以便diff算法进行同层级比较
扩展: 理解key
2.6 表单控件绑定
- v-model
- 双向数据绑定
- VM 改变 V随之改变
- V改变, VM也随之改变
- v-model只用于表单
- 理由: v-model默认绑定value属性
- 技巧: 看到表单直接 v-model
2.7 作业
- 整理好笔记,发送博客
- 用深入响应式原理来解释 双向数据绑定原理 【 思考 】
- 使用单向数据绑定来实现 v-model 效果
- 今天讲的知识点在官网上对一对,看一看,
Vue基础3
3.1 axios && fetch
目的: 是在框架中使用数据请求
回顾:
- 封装ajax
2. jquery 【 . g e t .get .get .post . a j a x .ajax .ajax .load 】
框架:
数据请求
- 使用原生js提供的fetch
- 使用第三方封装库: axios
- Vue中可以统一对axios进行挂载
Vue.prototype.$http = axios
- fetch vs axios
- axios 对已获得的数据进行了一层封装 XSRF
- axios底层自动对数据进行了格式化
- fetch并没有进行封装,拿到就是格式化后的数据
- fetch进行了多一层的格式化
- res.json()
- res.blob() 格式化二进制
- res.text()
Axios总结
1.get方法
A: 无参数
axios.get(url).then(res=>console.log(res).catch(error=>conosle.log(error))
B: 有参数
axios({
url: 'http://xxx',
method: 'get' //默认就是get,这个可以省略,
params: {
key: value
}
})
2.post
注意: axios中post请求如果你直接使用npmjs.com官网文档, 会有坑
解决步骤:
1. 先设置请求头
2. 实例化 URLSearchParams的构造器函数得到params对象
3. 使用params对象身上的append方法进行数据的传参
// 统一设置请求头
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
let params = new URLSearchParams()
// params.append(key,value)
params.append('a',1)
params.append('b',2)
axios({
url: 'http://localhost/post.php',
method: 'post',
data: params,
headers: { //单个请求设置请求头
'Content-Type': "application/x-www-form-urlencoded"
}
})
.then(res => {
console.log( res )
})
.catch( error => {
if( error ){
throw error
}
})
Fetch
1.get
fetch('http://localhost/get.php?a=1&b=2')
.then(res=> res.text()) // 数据格式化 res.json() res.blob()
.then(data => {
console.log( data )
})
.catch(error => {
if( error ){
throw error
}
})
注意事项:
A: fetch 的 get 请求的参数是直接连接在url上的, 我们可以使用Node.js提供的url或是qureystring模块来将
Object --> String
B: fetch 的请求返回的是Promise对象,所以我们可以使用.then().catch(),但是要记住.then()至少要写两个, 第一个then是用来格式化数据的,第二个then是可以拿到格式化后的数据
格式化处理方式有
fetch('./data.json')
.then(res=>{
res.json() //res.text() res.blob()
})
.then( data => console.log(data))
.catch( error => console.log( error ))
2.post
fetch 文档
https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch#%E8%BF%9B%E8%A1%8C_fetch_%E8%AF%B7%E6%B1%82
fetch项目使用的博客
https://blog.csdn.net/hefeng6500/article/details/81456975
- 历史
- Vue1.0
- Vue1.0数据请求我们使用的是一个第三方的封装库,这个封装库叫做 vue-resource
- vue-resource现在已经淘汰了,它的作者也推荐我们使用axios
- vue-resource使用形式和axios一样的
- this.$http.get
- this.$http.post
- this.$http({})
- vue-resource有jsonp方法,而axios是没有的
- Vue2.0
- axios [ 可以说是目前最好的数据请求的封装库 ]
- fetch
3.2 计算属性
computed 是Vue中的一个选项
作用: ?
业务: 如果我想让一个字符串反向,如何实现?
分析: 反向 -> 数组【 reverse 】
3.2.1 侦听属性
watch 是Vue中一个选项
作用: ?
监听数据的变化,当数据发生改变时,我们完成一些操作
业务:
watch: {
firstName ( val ) {
this.fullName = val + this.lastName
},
lastName ( val ) {
this.fullName = this.firstName + val
},
num: {
deep: true, // 深度监听
handler ( val ) {
// 当num发生改变时,触发的方法
console.log( val )
}
}
}
-
总结: methods vs computed vs watch
-
项目中如何使用
-
- 事件处理程序: methods
-
-
watch
有大量数据交互和异步处理时进行
-
- computed
- 有逻辑处理
- V中像全局变量一样使用
3.3 混入 【 青铜 】
minxin
-
混入的形式
- 全局混入 【 不推荐 】
- 局部混入
-
混入的作用:
-
- 将选项中某一个或是多个单独分离出去管理,让职能更加单一高效,符合模块化思想
-
局部混入的使用
选项 minxins
-
全局混入
Vue.mixin({})
3.4 组件 【 王者 】
-
了解前端组件化发展历史
- 前后端耦合
- 前后端不分离项目
-
- 找后台搭建项目开发环境
-
- 寻找项目目录中的静态资源目录
- js
- img
- css
-
- 同步修改css
- 前后端分离
- 前端团队合作项目的出现
- 组件化为了解决多人协作冲突问题
- 复用
-
组件的概念
- 组件是一个html 、 css 、js 、img 等的一个聚合体
-
Vue中的组件属于扩展性功能
-
通过 Vue.extend() 来扩展的
ƒ Vue (options) {
if (!(this instanceof Vue)
) {
warn('Vue is a constructor and should be called with the `new` keyword');
}
this._init(options);
}
ƒ VueComponent (options) {
this._init(options);
}
-
VueComponet这个构造函数我们不进行new实例化,我们希望组件是以标签化的形式展示
<Hello/> --> <div>div>
<Banner>Banner>
-
组件要想合法化,必须注册解析
-
组件的注册 【 创建 】
- 全局注册
- 局部注册
-
组件的规则
-
is属性 - 动态组件 - 动态缓存组件
-
template模板标签
- 直接子元素有且仅有一个
-
组件的嵌套
3.5 作业
- 面试题: ajax 和 fetch 有什么区别? 【 提问率: 60% 】
- 进行数据请求,然后布局一个移动端列表 【 亲亲网 】
- 弹性盒
- rem
- 了解前后端耦合,前后端分离
- 进行页面布局
- 寺库登录页面布局
- 卖座首页布局
Vue基础4
4.0 组件的通信 【 王者 】
为什么要进行组件通信?
组件是一个聚合体,将来项目要合并,那么必然各个组件之间需要建立联系,这个联系就是数据通信
-
分类
-
父子组件通信
-
理解: data选项为什么是一个函数?
- 组件是一个聚合体,也是一个整体,它需要一个独立的作用空间,也就是它的数据需要是独立的,目前js的最大特点是函数式编程,而函数恰好提供了一个独立作用域,所以我们data在出根组件外都是函数
-
理解: 为什么data函数需要返回一个返回值,返回值还是对象,不能是数组吗?
- Vue通过es5的Object.definePerproty属性对一个对象进行getter和setter设置,而data选项是作为Vue深入响应式核心的选项
-
过程
-
父组件将自己的数据同 v-bind 绑定在 子组件身上
-
子组件通过 props属性接收
<template id="father">
<div>
<h3> 这里是father h3>
Son>
div>
template>
<template id="son">
<div>
<h3> 这里是son h3>
<p> 我收到了父亲给的 {{ money }} p>
div>
template>
<script>
Vue.component('Father',{
template: '#father',
data () {
return {
money: 10000
}
}
})
Vue.component('Son',{
template: '#son',
props: ['money']
})
new Vue({
el: '#app'
})
script>
-
props属性数据验证
-
验证数据类型
-
验证数据大小【 判断条件 】
// props: ['money']
// 数据验证
// props: {
// 'money': Number
// }
props: {
'money': {
validator ( val ) { // 验证函数
return val > 2000
}
}
}
-
工作中: 第三方验证
- TypeScript [ TS ]
- 插件 vue-validator 等
-
子父组件通信
-
是通过自定义事件
- 事件的发布
- 通过绑定元素身上实现
- 事件的订阅
- 通过this.$emit触发
// html
<div id="app">
<Father>Father>
div>
<template id="father">
<div>
<h3> 这里是father h3>
<p> 我现在有 {{ gk }} p>
Son>
div>
template>
<template id="son">
<div>
<h3> 这里是son h3>
//js
Vue.component('Father',{
template: '#father',
data ( ) {
return {
gk: 0
}
},
methods: {
fn ( val ) {
this.gk = val
}
}
})
Vue.component('Son',{
template: '#son',
data () {
return {
money: 5000
}
},
methods: {
giveHongbao () {
this.$emit('give',this.money)
}
}
})
new Vue({
el: '#app'
})
-
非父子组件通信
- ref链
[外链图片转存失败(img-fVVjMwc7-1568092342832)(E:\1906\2-Vue.js\note\vue笔记\img\非父子组件通信-ref(1)].png)
-
bus事件总线
var bus = new Vue()
Vue.component('Father',{
template: '#father'
})
Vue.component('Son',{
template: '#son',
data () {
return {
flag: false
}
},
mounted () { // 也是一个选项,表示组件挂载结束 , 也就是说我们可以在View视图中看到这个组件了
// console.log( 'mounted ')
// bus.$on(自定义事件名称,执行的事件处理程序)
var _this = this
bus.$on('cry',function () {
_this.flag = true
})
}
})
Vue.component('Girl',{
template: '#girl',
methods: {
kick () {
bus.$emit('cry')
}
}
})
new Vue({
el: '#app'
})
-
非常规手段进行组件通信 【 不推荐 】
-
兵哥建议: 如果标准方案可以实现,就不要用非常规手段
-
- 可以实现子父通信
- 父组件通过 v-bind 绑定一个方法给子组件
- 子组件通过 props选项接收这个方法,然后直接调用
-
- 父组件 通过 v-bind 绑定 一个对象类型数据 给子组件
- 子组件直接使用,如果更改这个数据,那么父组件数据也更改了
- 原因: 同一个地址
- 非常规在哪里?
- 违背了单向数据流
-
多组件状态共享 【 vuex 】
4.1 slot
slot 插槽
比如: 插卡游戏机
-
分类
-
普通插槽
-
具名插槽
-
给slot加一个name属性
slot>
-
注意: 以上内容是 Vue 2.5.x的版本
-
Vue 2.6.x以上的版本将使用 v-slot指令来代替 2.5.x使用方式
-
v-slot指令
- 作用:
- 可以将组件的数据在组件的内容中使用
4.2 过渡效果
Vue框架使用css3过渡效果或是js动画
Vue内部提供了一个叫做transition的过渡组件
使用transition包裹过渡元素,那么会自动添加 6 个类名 8个钩子函数
- 默认 类名 开头 v
- 如果有name属性,那么使用 这个name属性值作为类名开头
- 实现方式
- 在 CSS 过渡和动画中自动应用 class 【 自己写 】
- 可以配合使用第三方 CSS 动画库,如 Animate.css
- 在过渡钩子函数中使用 JavaScript 直接操作 DOM
- 可以配合使用第三方 JavaScript 动画库,如 Velocity.js
- 第一种 [ 在 CSS 过渡和动画中自动应用 class 【 自己写 】 ]
- 第二种: animate.css 【 推荐 】
- 第三种: Vue提供了8个javascript钩子,我们需要自定义js动画
- 第四种: 使用第三方插件: Velocity.js
4.3 生命周期
4.4 swiper
swiper是一个实现滑动操作的一个第三方库,目前最好的滑动操作库
4.5 自定义指令
业务: 页面开启时自动获得 search 按钮焦点
-
定义形式
-
全局定义
// Vue.directive('focus',{
// // 5个javascript钩子 5个中掌握2个
// bind (el,binding,vnode,oldVnode) { // 当自定义指令和元素绑定时触发
// console.log( 'bind', )
// },
// inserted ( el,binding,vnode,oldVnode ) { // 当自定义指令绑定的元素插入到页面时触发
// console.log( 'el',el)
// console.log( 'binding',binding)
// console.log( 'vnode',vnode)
// console.log( 'oldVnode',oldVnode)
// console.log('inserted')
// if ( binding.modifiers.a ) {
// el.style.background = 'red'
// } else {
// el.style.background = 'blue'
// }
// el.value = binding.expression
// el.focus()
// },
// updated () { // 当自定义指令的元素或是他的子元素发生变化式触发
// },
// componentUpdate () { //当自定义指令的元素或是他的虚拟子节点 发生变化式触发
// },
// unbind () { // 当自定义指令绑定的元素解绑时触发
// }
// })
-
局部定义
new Vue({
el: '#app',
directives: {
'focus': {
bind () {
},
inserted ( el ) {
el.focus()
}
}
}
})
4.6 过滤器
-
- 作用
- 是对已经有的数据做数据格式化
-
-
使用格式
- 已有数据 | 过滤器名称(arg1,arg2)
- | 我们称之为 管道符
-
定义
- 全局定义
- Vue.filter
- 局部定义
- filters选项
全局定义
// Vue.filter('imgFilter',function ( val ) {
// //val就是需要格式化的数据
// // console.log('val',val)
// return val.replace( 'w.h', '128.180')
// })
new Vue({
el: '#app',
data: {
lists: []
},
filters: { // 局部定义
// 过滤器名称:function () {}
'imgFilter': function ( val ) {
return val.replace( 'w.h', '128.180')
}
},
methods: {
getList () {
fetch('./data/list.json')
.then( res => res.json())
.then( data => {
this.lists = data.movieList
})
.catch( error => console.log( error ))
}
}
})
4.7 作业
- 自定义指令实现选项卡
- 预习Vue生命周期 并 试着 实现 将 swiper 应用在 Vue中
- 复习着一周内容
- todolist尝试实现
Vue基础5
5.1 todolist案例
- sui - ui库 + Vue + OOCSS
5.2 虚拟DOM & DIff算法
-
掌握程度: 了解
-
案例
- 操作真实DOM越少越好,尽量的去操作数据
- 所以总结出来虚拟dom,
- 所以Vue利用VDOM的对象模型来模拟DOM结构
- 但是当一个页面很复杂式,DOM结构的模拟就变的很复杂了,所以Vue使用了一个新的语法糖,叫做JSX
-
jsx
-
javascript + xml 让我们可以在js中书写dom结构
<template id="mask">
<div class="mask-box">
<div class="mask-bg">div>
<div class="mask-content">
<p> 您确定要离开吗? p>
-
render
- ( createElement => VNode )
- 将 jsx 通过 render 方法解析为对象模型
-
流程
-
第一次时
-
template模板使用jsx语法进行编辑
-
通过render函数将jsx解析为 vdom 对象模型
-
将VDOM对象模型渲染为真实DOM,然后挂载到页面中
-
当我们的数据发生改变时
-
重新生成VDOM
[外链图片转存失败(img-kSM48PWK-1568092342833)(E:\1906\2-Vue.js\note\vue笔记\img\VDOM.png)]
-
总结:
-
- 为什么Vue中要使用VDOM?
-
- VDOM为什么可以优化Vue ?
-
- VDOM渲染流程
-
- JSX语法
-
- render函数
5.3 生命周期 [ 王者 ]
掌握程度
- 会写
- 会念
- 明白和了解每一个钩子函数的作用和意义
特别注意:
钩子函数不要写成箭头函数,箭头函数可能会改变this指向
-
理解: 为什么要有生命周期 ?
-
Vue为了在一个组件的从创建到销毁的一系列过程中添加一些功能,方便我们更好的去控制组件
-
类比: 人
- 出生 - 哭
- 小学 - 小学
- 中学
- 高中
- 大学 / 专科
- 工作
- 。。。
-
Vue的生命周期分为三个阶段,8个钩子函数
-
初始化
自动执行
研究方向
数据
真实DOM
-
beforeCreate
组件创建前
- 作用: 为整个生命周期做准备工作,初始化事件和自身或是子组件的生命周期做准备
- 类比: 父母为子女的相亲做准备
- 意义:
- 数据拿不到
- 真实dom拿不到
- 项目中
- 不常用
-
created
组件创建结束
- 作用: 初始化注入其他选项 和 激活 选项
- 类比: 我们本人知道了父母准备给我们相亲这件事,父母通知你了
- 意义:
- 数据可以拿到
- 真实dom拿不到
- 项目中:
- 数据请求,也可以修改一次数据
-
beforeMount
组件挂载前
挂载: 组件插入到页面
- 类比:两人初步联系
- 意义:
- 数据可以拿到
- 真实dom没有拿到
- 在项目中
- 数据请求,数据修改
- 建议不要去使用它了,让它完成内部事务,不给加负担
- 内部完成事务
- 判断el选项 - new Vue 是否有 el
- 有,继而判断是否有template选项,证明有子组件
- 有template,那么我们通过render函数将jsx解析为VDOM对象模型
- 无template,那么我们需要通过outerHTML手动渲染
- outerHTML,元素外进行渲染,并且会代替原来的容器盒子,并且template在实例内会被解析,将来不会渲染到页面
- 无: 那么我们需要手动挂载: new Vue().$mount(’#app’)
-
mounted
组件挂载结束,也就是已经插入到页面中了
- 类比: 两人约见面 【 奔现 】
- 意义:
- 数据可以拿到
- 真实DOM也可以拿到
- 项目中
- 数据修改,数据请求
- 真实DOM操作 【 不推荐 】
- 理由: 我们要用数据驱动视图
- 应该做的: 第三方实例化 【 静态数据 】
-
运行中
运行中触发条件是: 数据改变
只要数据改变,就会触发这两个钩子函数
-
beforeUpdate
组件更新前
- 类比: 奔现失败后,再一次在一次进行
- 意义:
- 数据是可以拿到更新后的数据
- 也可以拿到更新后的真实DOM
- 兵哥解析:
- 为在一次的更新准准备工作
- 生成Virtual DOM
- 项目中
- 不常用
-
updated
组件更新结束
- 类比: 两人看对眼了 / 两人看不对眼
- 看对眼: 相亲这件事就有一个结果
- 看不对眼: 相亲这件事继续
- 意义:
- 可以拿到修改后的数据
- 也可以拿到真实DOM
- 在项目中:
- 真实DOM操作 【 不推荐 】
- 第三方库动态实例化 【 动态数据 】
- 内部
- VDOM重新渲染,然后通过render函数解析为VDOM对象模型,在通过Diff进行比对生成patch补丁对象,然后重新渲染为真实DOM
- 只改变变化的部分,其他部分不改变
-
销毁
触发条件:组件被删除
- 外部开关销毁
- 内部调用$destroy()
这两个钩子函数没有太大区别,所以我们统一说
- beforeDestroy
- destroyed
- 外部销毁
- 通过开关完成
- DOM被删除了,组件也被删除了
- 内部销毁
- 通过调用$destroy()来完成
- DOM没有被删除,但是组件被删除了
- Dom需要手动删除
- 项目中如何使用:
- 善后
- 比如: 计时器,比如滚动事件等
5.4 生命周期案例
- Swiper
- 静态数据
- 动态数据
- updated中写式,会有重复实例化问题
- 第一个解决方案: 加判断条件
- 第二个解决方案: setTimout
- 放在主线程后执行,异步队列中,保证真实DOM渲染完成
- 第三种解决方案: 推荐 Vue内部提供的 nextTick
- nextTick表示真实DOM渲染完成之后才执行
- Vue.nextTick( callback )
- this.$nextTick( callback )
[外链图片转存失败(img-TquwQTHV-1568092342834)(E:\1906\2-Vue.js\note\vue笔记\img\lifecycle.png)]
作业:
- todolist
2. VDOM & Diff
二、Vue高级
Vue高级 - cli
vue项目的快速构建工具 cli 【 脚手架 】
底层 webpack
React 第一天
Vue中我们注重应用
在市场上
cli2 【 扩展 】
cli3 【 大纲 】
-
什么是cli?
cli是vue提供的一个用来快速构建项目环境的一个工具,底层使用的是webpack
-
cli目前有哪些版本?
cli2 cli3
cli3对电脑的配置有一定要求
-
cli如何使用?
-
cli的安装 【 推荐使用yarn 】
npm/cnpm/yarn 都可以使用 【 yarn 配置国内镜像 】
$ cnpm i yarn -g
使用国内镜像加速npm和yarn
npm config set registry=https://registry.npm.taobao.org
yarn config set registry https://registry.npm.taobao.org
下载cnpm:npm install -g cnpm –registry=https://registry.npm.taobao.org
-
$ yarn add @vue/cli global
这个是cli3的版本
如果我们还想使用cli2的脚手架,那么我们可以在安装一个包
cli3 @vue/cli
cli2 vue-cli 【 不要安装 】
所以一个电脑只能装一个
问题: 如果我们同时想使用 cli2 和 cli3 怎么办呢?
-
$ yarn add @vue/cli-init global
如果有的同学安装3失败了,
那么你可以使用cnpm继续安装 @vue/cli @vue/cli-init
1. `$ cnpm i @vue/cli -g` 这个是cli3的版本
如果我们还想使用cli2的脚手架,那么我们可以在安装一个包
1. `$ cnpm i @vue/cli-init -g`
如果还有问题:
那么你就不要使用cli3了,你可以单独安装cli2 【 先卸载cli3,重启电脑 】
`$ cnpm i vue-cli -g`
-
验证是否安装成功
命令行输入: $ vue
看是否有东西输出,如果输出命令提示,证明安装成功
-
创建项目
cli3版本创建
-
命令创建 【 推荐 】
$ vue create project
- 手动选择配置
- 如果安装node-sass出问题,如何解决:
- 先切换成npm源 nrm use npm
- 使用cnpm 安装 cnpm i node-sass sass-loader -D
-
图形界面创建
$ vue ui
cli3两种形式创建的结果是一样的
cli2版本创建
- 标准版
$ vue init webpack project
- 简易版
$ vue init webpack-simple project
-
please pick a preset( user arrow keys ) 使用键盘上下键来选择一个配置
-
default 默认配置
-
Manually select features 手动选择配置
配置指的是配置webpack
babel 优雅降级 es6 —> es5
eslint js语法检测
CSS Pre-processors css 预处理语言 less sass/scss stylus
Linter / Formatter eslint / jslint
Unit Testing 单元测试
E2E Testing 端到端的测试
In dedicated config files 将所选的每一个选项用一个文件来保存( 配置 )
PWA (web app ) 在浏览器中使用的app
Save this as a preset for future projects? 将上面所选的配置保存下来,以备将来的项目使用
我们cli3 使用的包管理器器建议 是 yarn 大家一定要记得配置国内镜像源
4.分析几个版本的目录
cli3
目录
- node_modules 项目的依赖包
- cli3 webpack配置放在node_modules中
- public 静态资源目录( 生产环境 )【 这个目录下的静态资源不会被webpack 编译 】
- img
- js
- css
- favicon.ico 项目标题的logo
- index.html 根实例组件的模板,也是整个项目的容器
- src 源代码开发目录( 也是开发者主要开发的目录文件夹 )
- assets 开发环境的静态资源目录 ( 这个目录中的资源会被webpack编译)
- assets中如果图片的大小 > 4k 我们就原样拷贝到dist目录
- assets中如果图片的小小 < 4K 我们就将这个图片转化成 base64
- base64它是我们前端处理图片的一种形式,将图片路径进行编码,它可以减少一次ajax请求,达到前端性能优化的一个方案,但是base64有一个弊端,这个弊端就是会污染html结构
- components 组件存储目录
- xxx.vue文件 单文件组件 一个vue文件就是一个组件
- 组成部分
- template模板( 必须写的 )
- script脚本 ( 可写可不写)
- style样式 ( 可写可不写 )
- scoped 作用是可以减少命名冲突,规定一个样式的作用域
- .gitignore git上传忽略文件配置
- babel.config.js 优雅降级配置文件 用来将es6 --> es5
- package.json 整个项目的依赖配置文件
- README.md 整个项目启动的说明性文件
- yarn.lock 整个项目的依赖性文件的信息
- postcss.config.js 项目css预处理的配置
- .browserslistrc 浏览器版本的支持
cli2 标准版
build webpack配置
config webpack配置
node_modules
src
static 静态资源配置
js
css
img
.babelrc 优雅降级配置文件
.postcssrc css预处理配置文件
.editorconfig 编辑器配置文件
cli2 简易版
src 源代码开发目录
webpack.config.js webpack配置文件
5.学习cli使用
6.cli 它是 webpack + es6模块化来集中实现的
es6模块化
-
模块的定义
const obj = {}
const fn = function(){}
-
模块的导出
// 模块的导出有两种形式
export default //默认导出一个
//export // 批量导出,导出多个
-
模块的引入
// 如果是export default 导出
import xxx from '../xxx.xx'
// 如果是export 导出
improt { xx } from '../xx.xx' || import * as xx from '../xx.xx'
base64找一个博客了解一下
在cli3中创建组件,然后导出组件,然后使用组件
在 vs code编辑器中安装一个插件( Vetur ),可以使用vue文件代码高亮还可以有代码提示
【HMR】 热重载 自动刷新 webpack配置
cli3 将webpack配置放在 node_modules,所以Vue并不希望大家去修改这部分webpack配置
如果我们将来需要更改webpack配置,那么我们需要在 项目 根目录 下创建一个 vue.config.js文件
作业:
- 在cli3/cli2项目中完成todolist
2. cli3
Vue高级 - vue-router
SPA ( single page App ) 单页面应用
- 多页面应用
有多个html文件,通过a标签的连接联通各个页面
- 缺点
- 开发起来太冗余,编译、压缩很耗时间
- 页面之间的跳转速度太慢,这个时候就会出现一个严重的问题,白屏
- 单页面应用
- 不需要刷新页面,因为它就是一个页面
- 这个页面内容在切换
- 单页面内容之间的切换要想实现我们就是用路由了
- 如今我们的app、后台管理系统 主要的开发形式就是spa
vue路由功能
- 实现单页面的切换
- 路由携带参数
- 路由的导航守卫
- 路由进行数据预载(进入组件前就请求获得数据)
vue-router 基础
-
vue 路由的mode(模式)有几种, 分别是什么?在那些环境下运行? 【 黄金 】
- hash: 使用 URL hash 值来作路由。支持所有浏览器,包括不支持 HTML5 History Api 的浏览器。 #/home
- history: 依赖 HTML5 History API 和服务器配置。【需要后端支持】 /home
- abstract: 支持所有 JavaScript 运行环境,如 Node.js 服务器端。如果发现没有浏览器的 API,路由会自动强制进入这个模式。【 这个模式不常用 】
- hash/history 常用于浏览器端,abstract用于服务端
-
路由的使用步骤
-
安装 vue-router yarn add vue-router
-
在src目录下创建一个router目录, 里面创建一个index.js文件 , 这个目录就是router的模块
-
引入第三方的依赖包, 并注册路由
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use( VueRouter ) //使用vue-router这个第三方插件
注意: import这个关键字要放在整个文件的上层
-
创建了一个router对象实例,并且创建路由表
const routes = [
{
path: '/home',
component: Home
}//每一个对象就是一个路由
]
const router = new VueRouter({
routes//路由表 必写的
})
-
导出router实例
export default router
-
入口文件main.js中引入路由实例 router , 然后在根实例中注册
import router from './router/index.js'
new Vue({
router,
render: (h) => App
}).$mount('#app')
-
给路由一个路由展示区域
- 如果是以及路由, 那么我们放在App组件中,用一个 router-view 的组件表示
<router-view />
-
当页面第一次的打开的时候, 需要做一个重定向, 就是要自动跳转到 /home 这个路由上
const routes = [
{ //我们要求这个路由的配置要放在路由表的最上方
path: '/',
redirect: '/home'
}
]
-
业务: 错误路由匹配,
const routes = [
{
path: '/',
redirect: '/home' //重定向
},
{
path: '/home',
component: Home
},
{
path: '/list',
component: List
},
{
path: '/detail',
component: Detail
},
{
path: '/login',
component: Login
},
{
path: '/register',
component: Register
},
{
path: '/user',
component: User
},
{
path: '/shopcar',
component: Shopcar
},
{
path: '/error',
component: Error
},
{ //这个就是错误路由匹配, vue规定这个必须放在最下面,它必须将上面的路由全找一遍,找不到才用当前这个
path: '**',
redirect: '/error'
}
]
-
vue路由模式的确定 mode
- 如果你使用的是 hash , 那么a标签就可以了、
- 如果你使用 history , 那么我们最好将a标签改成 router-link 这个组件
- router-link 这个组件 身上必须要有一个 to 属性
- router-link 这个组件身上加一个 keep-alive属性可以进行浏览器缓存
-
二级路由
const routes = [
{
path: '/shopcar',
component: Shopcar,
children: [
{
path: 'yyb', //不写 /
component: Yyb
}
]
}
]
- 注意: 写好配置之后,不要忘记了, 在对应的一级路由的组件中书写 路由展示区域
-
命名路由
作用: 就是简写路径了
{
path: '/shopcar',
component: Shopcar,
//子路由
children: [
{
path: 'yyb', // 容易犯错点 /yyb X
component: Yyb,
name: 'yyb' //命名路由
},
{
path: 'junge',
component: Junge
}
]
},
-
使用: 单项数据绑定to属性
vue-router 进阶
案例: 移动端
- 【 分类 -》 列表 -》 详情
路由进阶 - 动态路由
核心功能
- 路由传参
- 路由接参
-
动态路由:
- url中路由是改变的,但是改变路由公用一个组件
- 举例:
- localhost:3000/detail/001?a=1&b=2
- localhost:3000/detail/002?a=2&b=3
- detail
-
vue cli3 配置反向代理 20分钟
- 在根目录下面新建一个 vue.config.js
// vue.config.js中可以默认直接使用 http-proxy-middleware
module.exports = {
devServer: {
proxy: {
'/douban': { // /douban 是一个标记
target: 'http://api.douban.com', // 目标源
changeOrigin: true, // 修改源
pathRewrite: {
'^/douban': ''
}
},
'/siku': {
target: 'https://android.secoo.com',
changeOrigin: true,
pathRewrite: {
'^/siku': ''
}
}
}
}
}
/*
注意: 修改了项目配置文件,项目必须重启
*/
- 路由的传参 10分钟
router-link>
-
路由的接参
- 我们发现凡是使用了路由的组件,我们统称为: 路由组件
- 路由组件身上会自动添加一个 $route的数据
id: this.$route.params.id
query: this.$route.query.xxx
-
编程式导航 5分钟
- push
this.$router.push('/home')
- this.$router.push({name,params,query})
- push可以将我们的操作存放到浏览器的历史记录
- replace
- this.$router.replace(’/home’)
- this.$router.replace({name,params,query})
- replace没有将我们的操作存放到浏览器的历史记录, 效果为返回了二级
- push/replace的参数就是to属性的参数
-
业务:
- 按钮的返回
- push
- replace
- back
- go
思考: 有一个业务,当我们点击 /mine的时候,要自动跳转到 /mine/login,这个时候我们发现手段不够用了,生命周期钩子函数也实现不了,这个我们想,如果我们能监听到路由的变化,那该有多好?
思考: 如果用户没有登录,那么我们是无法进入首页的,如果登录了,那就可以进入
解决; vue为了能够监听路由的变化情况,给了一个解决方法: 这个就是导航守卫
路由进阶 – 导航守卫
别名:
- 导航守卫
- 路由守卫
- 路由钩子
- 路由拦截
-
作用: — 类似 【保安】
- 守卫路由
- 进
- 举例: 携带数据进
- 出
- 举例: 事情完成才能出
-
导航守卫一共有三种形式 【 项目三选一 】
-
A: 全局导航守卫
针对的整个项目,也就是管理或是监听整个项目
- 全局前置守卫
router.beforeEach(fn)
- fn中有三个参数
- to: 目标路由
- from: 当前路由
- next: 它是一个拦截,表示是否允许通过
- true/false/’/login’/{ name: ‘login’}/ vm => {}
- 使用场景: 当我们本地存储/cookie中有token,那我们就自动跳转 /mine
- 全局的解析守卫
- 在 2.5.0+ 你可以用 router.beforeResolve 注册一个全局守卫。这和 router.beforeEach 类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。
- 必须保证整个项目的守卫和异步路由组件解析完成
- 全局的后置守卫
- 可以做一些用户友好提示
-
B: 路由独享守卫 ·
路由配置选项中的一个
- 写在路由表中的守卫钩子
- 针对的是和当前路由相关的,那么其他与之不相关的路由,它是无法监听它的变化情况的
- 做路由拦截
- 案例: 权限验证
- 数据库: 用户组
- 普通用户
- 管理员
- 超级管理员
- 我们登录式,后台会返回给我们info信息,通过信息来判断它是哪个类型用户
-
C: 组件内守卫【 王者 】
当前组件
-
组件内的前置守卫 beforeRouteEnter((to,from,next)=>{})
- 导航进入组件时,调用
- this是访问不到的,如果非要访问this ,必须通过 next(vm=>{})访问
- 因为组件此时没有创建,所以没有this
- 案例: 数据预载(进入组件前就获得数据)
next(vm => { //vm指的就是组件
const result = JSON.parse(res.data.slice(7,-1)).rp_result.categorys
vm.$set(vm.category,'categorys',result)
})
-
组件内的后置守卫
- 当离开组件时,调用
- this是可以访问到
- 案例: 注册/内容提交,用户交互提示
-
组件内的更新守卫( 路由传参和路由的接参 )
- 在当前路由改变,但是该组件被复用时调用
- 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
- 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
- 可以访问组件实例
this
-
功能: 导航守卫可以监听路由变化情况,做路由跳转拦截
-
名词
- 前置: 要进入当前路由 — 老师进入教室前
- 后置: 要离开当前路由 — 老师离开教室
-
关于next的使用
-
next() 等价于 next( true ) 表示可以从当前路由跳转到目标路由
-
next( false ) 表示不通过, 表示从当前路由跳转不到目标路由
-
next(’/login’) 等价于 next({path:’/login’}) 跳转指定的路由
-
next(’/login’) 等价于 next({path:’/login’,params,query})
-
next( fn ) 数据预载
next( vm => {})
-
业务: 当我们进入到一个项目的首页时,但是当我们没有注册账号时,它主动跳转到了注册/登录页
router.beforeEach((to,from,next) => {
// next() // 默认true
// next( false )
// next()
// 判断用户是否登录,我们找token值 cookie localStorage
const token = localStorage.getItem('token')
if ( to.path === '/home' ) {
next()
}
if ( to.path == '/aa') {
next()
}
if ( to.path === '/mine/login' ) {
if ( token ) {
// 条件成立,那么我们就可以进行页面跳转了
next('/home')
} else {
// 条件不成立,留在当前页面
next()
}
} else {
next( false )
}
})
- 业务: 当进入mine页面的时候, 要判断用户是否登录,如果没有登录,跳转登录页
- 路由导航守卫
- 3中类型 7个路由监听钩子
- 业务:
- 监听整个项目的路由变化情况 全局的前置守卫
- 监听某个路由的变化情况 路由的独享守卫
- 监听的路由组件的路由变化情况 组件内的导航守卫
-
动效
- animate.css 来实现路由动画
-
路由懒加载
-
Vue异步组件 + Webpack
-
动态缓存
-
router-link 加一个keep-alive属性
router-link>
-
作业:
- 我演示内容要写出来,脱离视频写出来
Vue高级 - Vuex
Vuex称为Vue的状态管理工具,也是多组件状态共享的工具
Vuex相当于是Vue的一个集中式的存储仓库
- 它存储的是数据 【 状态 】
- 存储仓库: 本地存储 cookie 数据库
什么时候用: 打算开发中大型应用
集中式数据管理, 一处修改,多处使用
思维流程:
store.js
this. s t o r e . c o m m i t ( ′ i n c r e m e n t ′ ) − > m u t a t i o n s t h i s . store.commit('increment') -> mutations this. store.commit(′increment′)−>mutationsthis.store.dispatch(‘jia’) -> actions
mapActions() ->actions mapGetters()->getters
学生 代课老师 校长 财务 班主任 学生
(view)component - dispatch > action -> mutation -> state <- getter <- component
发送请求 处理 修改状态
业务逻辑 修改state 读取state
异步
案例: 比如我们报名考科一
- 取号
- 排队
- 窗口
- 走流程
为什么要集中式的车管所 ?
- 统一管理、集中管理
- 数据共享
为什么要走流程?
- 控制执行 , 比如 100000个人同时进入会怎么样?
理解为什么要使用vuex
- 它能够实现状态共享
- 实现流程化,让项目的运行更加流程和优化
市场上出现了一个情况,不知道什么情况下使用vuex?
- 中大型应用
- 当你不确定你是否要使用vuex的时候,那就不要用了 flux作者说的
学习阶段: 必须要用
公司: 可用可不用
1. 什么是状态
我们使用一条数据去管理一个视图,那么这个数据我们就称之为 ‘状态’
2. vuex是做什么的?
Vuex是一个集中式的存储管理中心,vuex中可以用来存储 数据( 状态 )
vuex也是一个状态管理中心,它也可以进行状态的管理
3. 什么是状态管理模式?
我们使用一条数据去管理一个视图,那么这种管理模式就称之为 状态管理
4. 什么时候使用vuex
中大型应用使用 (使用的时间)
当你不确定你是否要使用vuex的时候,那就不要用了
5. vuex的开发流程
[外链图片转存失败(img-SstUeUiD-1568092342836)(E:\1906\2-Vue.js\note\vue笔记\img\vuex.png)]
看图说话:
- Vuex的核心组成部分有三个,分别为: actions 、 state 、 mutations
- actions表示动作的创建者,它的作用是创建动作,然后发送动作, 用于用户交互、后端数据交互
- 距离: 一个用户点击了登陆按钮
- mutations 表示动作的出发者,它的作用是用来修改数据 -更新视图
- state它是数据的存储者,它的作用是定义数据【 状态 】
- 后端数据交互写在actions中
- vuex调试工具主要调试的mutations
- vuex是流程化执行的,符合单向数据流思维
vuex - 基础操作流程
-
安装vuex
$ yarn add vuex
-
在 src / store / index.js,【 数据不分块 】
import Vuex from 'vuex'
import Vue from 'vue'
Vue.use( Vuex )
// 1. 定义store 模块
// const store = new Vuex.Store( options )
const store = new Vuex.Store({
state:{
count: 0
},
actions:
/*
1. actions是一个对象
2. acitons里面放的都是方法
3. 方法的作用是创建动作,发送动作
increment ( store对象,组件发来的实际参数1,参数2 ) {}
*/
increment ( { commit }, val ) {
console.log('increment执行了')
console.log('val', val )
// 动作创建
const action = {
type: INCREMENT,
val
}
// 发送动作
commit( action )
}
},
mutations:{
/*
* 也是一个对象
* 里面存放的也是方法
* 方法名称是actions发送来的动作的类型
* 接收两个参数
* state就是数据 , action就是actions发来的动作
* mutations作用是用来修改数据的
* payload表示从组件传递过来的参数 负载
*/
[ INCREMENT ] ( state,action ) {
console.log('mutations执行了')
console.log( 'state',state)
console.log( 'action',action )
//修改数据
state.count ++
}
},
getters: {}, //getters表示帮助 视图【 组件 】 获得store中的 state
modules // 用来实现数据分块的
/*
数据分块:
一个项目中是有多个功能或是页面的,比如有
home
分类
列表
详情
用户
普通用户
会员
超级会员
底部栏
头部栏
图表数据
一个state管理所有的这些数据,就会变的杂乱,和不好维护,所以我们希望将数据分块,单一管理,一个数据一个模块
*/
})
// 2. 导出store模块
export default store
-
在main.js中注入store
import store from './store'
new Vue({
router, // 在项目中注入路由,让所有的子组件都用于路由属性 $route $router
store, // 在项目中注入store,让所有的子组件拥有一个属性 $store , 用于和vuex进行通信
render: h => h(App),
}).$mount('#app')
-
在组件内使用
vuex - 基础
{{ $store.state.count }}
vuex操作流程 - 【 数据分块 】
-
安装vuex
$ yarn add vuex
-
在 src / store /index.js
import Vuex from 'vuex'
import Vue from 'vue'
import * as todos from '../pages/vuex_basic/store'
Vue.use( Vuex )
const store = new Vuex.Store({
modules: {
//每一个分块出去的数据包
vue_basic: {
state: todos.state,
actions: todos.actions,
mutations: todos.mutations,
getters: todos.getters
}
}
})
export default store
-
在main.js中注册
import store from './store'
new Vue({
store, // 在项目中注入store,让所有的子组件拥有一个属性 $store , 用于和vuex进行通信
render: h => h(App),
}).$mount('#app')
-
在 vue_basic/store.js中打造 state actions mutations getters
/*
核心组成部分是三个 + getters
store 导出的不止一个
*/
import axios from 'axios'
const ADD_TODOS = 'addTodos'
const GET_CATEGORY = 'getCategory'
export const state = {
todos: [
{
id: 1,
task: '任务一'
},
{
id: 2,
task: '任务二'
}
],
category: null
}
export const actions = {
addTodos ({ commit }, val ) {
const action = {
type: ADD_TODOS,
val
}
commit( action )
},
getCategory ( {commit} ) {
axios({
url: '/index.php',
params: {
r: 'class/category',
type: 1
}
}).then( res => {
// 动作创建
const action = {
type: GET_CATEGORY,
payload: res.data.data.data
}
commit( action )
}).catch( error => console.log( error ))
}
}
export const mutations = {
[ ADD_TODOS ] ( state,action ) {
state.todos.push({
id: state.todos.length + 1,
task: action.val
})
},
[ GET_CATEGORY ] ( state,action ) {
state.category = action.payload
}
}
export const getters = {
getTodos ( state ) {
return state.todos
}
}
-
在 vue_basic/index.vue使用
vuex - 数据分块 - todolist增加功能
-
{{ item.task }}
-
{{ item.name }}
四个方案:
1. 前: 标准 后: 标准 √
2. 前: 标准 后: 非标准 √
3. 前: 非标准 后: 非标准
4. 前: 非标准 后: 标准 √
component ---dispatch---> actions ---commit--->mutations---state <----getters----component
思考:
- 数据的获取无论是标准还是非标准,都是很麻烦的,并且有些有些违背关注点分离
- actions或是mutations的通信会出现多个 this. s t o r e . d i s p a t c h / t h i s . store.dispatch / this. store.dispatch/this.store.commit
解决方案: 、
使用vuex辅助工具
6. 辅助工具
mapActions
mapMutations
mapGetters
mapState
export default 默认导出一个
export 叫批量导出,可以导出多个
7. vuex数据分块
将来我们的数据
希望是分块管理的,这样方便我们将来为何和更新
vue是通过一个叫做 module 的模块来管理的
vue项目中 store下的一个目录就是一个数据包
案例: todolist的添加操作
作业:
- 使用vuex实现计数
- 使用vuex实现todolist中添加( 使用数据分块 module )
- vuex实现购物车
三、Webpack
- 了解webpack在前端开发当中的一个重要性
- 了解webpack版本信息
- webpack基本配置
- 如何使用webpack配置项目
- 掌握程度: <= webpack 30%
一、前端工程化工具
也叫: 自动化工具
- grunt
- gulp ( 4.x )
- Browserify ( Webpack 前身 )
- Webpack 【 主流行 】
- rollup.js https://www.rollupjs.com/guide/zh 【 小众 】
- parcel 【 小众 】
- FIS https://fis.baidu.com/ 【 小众 】
二、前端工程化工具的发展历程
- grunt
- gulp ( 4.x ) 流的操作 .pipe()
- Browserify ( Webpack 前身 ) 没有兼容模块化问题( es6 )
- Webpack 【 主流行 】 自动解决模块依赖性问题
- AMD
- CMD
- es Module
- 可以将其他类型文件做转换
三、 Webpack版本的发展过程
官网: https://webpack.js.org/
中文: https://www.webpackjs.com/
webpack1
支持CMD和AMD,同时拥有丰富的plugin和loader,webpack逐渐得到广泛应用。
loader 转化器
webpack2
支持ES Module,分析ESModule之间的依赖关系,
webpack1必须将ES,Module转换成CommonJS模块,2支持tree sharking
webpack3
新的特性大都围绕ES Module提出,如Scope Hoisting和Magic Comment;
webpack3以上基本上都可以解决es6提出的模块化
webpack4
可以解决es6模块化【 export default / export import 】
更多个功能性 pulgin【 插件 】 和 loader 【 转换器 】
前端框架中广泛使用: Angular Vue React 的脚手架都是由webpack来进行开发、管理
学习目标:
- 通过webpack自主构建一个项目 【 手动构建一个项目 】
- webpack基本配置
- webpack高级配置
四、 Webpack涉及到的前端环境问题
- Webpack底层是由 Node.js 来开发的,也就是说Webpack的配置文件都是 Node.js 文件
- Webpack的模块化书写的规范是Common.js规范
- 环境支持: Node.js 8+
- 前端环境: 【 重点 】
- 开发环境 - 无法直接在服务器中去运行
- 生产环境 - 将开发环境下的代码经过 打包 压缩 编译 之后的文件
- 测试环境 - 将开发环境的代码经过 打包 压缩 编译 之后的文件,放在测试环境服务器中运行
- unit test 单元测试 【 mocha Jest 】
- e2e 端到端测试
- 预上线环境: 将开发环境的代码经过 打包 压缩 编译 之后的文件,放到一个局域网中去运行
- 上线环境:将开发环境的代码经过 打包 压缩 编译 之后的文件,放到云服务器或是服务器主机中,可以供任何人访问,使用的一个环境( 这个环境的上线要经过国家审核 )
- 云服务器: 类比: 宾馆 中有很多的单间,每一个云服务器就是其中一个单间
- 主机: 整个酒店
- 核心关注点在:
- 开发环境
- 生产环境
五、Webpack的安装
安装可以使用任何一个包管理器: npm yarn cnpm
yarn > cnpm > npm
举例: 我使用npm安装了一个叫做 node-sass 的包 ,但是出错了 ,这时,我们想卸载,发现卸载报错
解决: 覆盖安装
cnpm || yarn 进行覆盖安装
cnpm 和 yarn 优先级没有那么绝对
版本信息
webpack 4.39.3
webpack-cli 3.3.7
1.全局安装
$ npm install webpack webpack-cli -g
$ cnpm install webpack webpack-cli -g
$ yarn add webpack webpack-cli global
2.局部安装
$ npm install webpack webpack-cli -D
$ cnpm install webpack webpack-cli -D
$ yarn add webpack webpack-cli -D
局部优先级 > 全局
六、Webpack的概念
-
webpack* 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle( 分块束 )
理解:
举例: 我们又两个模块,A模块引用B模块,我们现在使用webpack打包A模块,webpack会自动寻找A和B之间的关系,进而打包B模块
七、Webpack 使用
默认源代码开发目录为: src
默认的入口文件名称为: src/index.js
默认出口目录为: dist
默认出口打包文件名称为: main.js
通过mode来设置是那个环境下打包使用
开发环境打包: 代码不经过压缩、注释不会被删除
eval 这个方法时用来解析字符串,这个字符串里面有js代码 【 性能不太好 】
1.终端命令行使用
-
终端运行 webpack
-
当我们局部安装了webpack webpack-cli后,发现运行webpack报错命名找不到
- 解决: 全局安装webpack webpack-cli
-
默认生成环境打包
-
webpack --mode development/production 开发环境/生产环境打包
2.配置文件使用
- 默认webpack配置性文件名称为 webpack.config.js,这个文件是在根目录下运行的
- 运行 webpack 命令就会自动的去寻找这个 文件
- webpack.config.js文件中我们配置的就是 webpack的参数
3.配置webpack.config.js文件
我们接下来对这个文件进行配置,主要从以下几个方面来着手
1. 基础功能 : 入口 出口 文件配置
2. 转换器: loader
3. 插件: plugin
单页面配置 vs 多页面配置
单页面配置指的只有一个入口一个出口的项目 【 推荐 】
多页面配置指的是有多个入口多个出口的项目
1.单页面配置
1.1 基础功能
/*
webpack配置文件
也是Node.js文件
这个文件也是一个独立的 Common.js 模块
*/
const path = require('path')
// 1. 创建模块
const webpackConfig = {
entry: './src/index.js', //网络路径( 相对路径 )
output: { //出口目录、文件的配置
path: path.join( __dirname,'dist'), // 磁盘路径
filename: 'js/app.js' // 入口文件将来打包到出口目录中的文件的路径和名称
},
mode: 'development'//确定是生产环境还是开发环境的打包
}
// 2. 导出模块
module.exports = webpackConfig
1.2 问题: 验证webpack是否能自动解决模块化依赖问题 可以
- 打造MVC
- index.js 用了 C
- C 里面用 M
- M里面用 V
1.3 loader 转换器 可以将其他类型文件转换为我们想要的类型文件
举例: 实现css的使用
/* ------------------------------- 转换器 ------------------------------ */
// 在webpack.config.js中做如下配置:
module: { //这里用来存放转换器的配置
rules: [
// {} //每一个对象就是一个转换器的配置
{//css的处理
test: /\.css$/, // 整个项目下匹配 .css结尾的文件
use: ['style-loader','css-loader'] //两个顺序是不写反的
// 我们需要使用css-loader将css文件编译为js,然后通过style-loader将js处理插入到html文件中【 style 嵌入模式 】
}
]
},
1.4 配置前端静态服务器
//需要自动刷新: webServer 搭建前端开发服务器
cnpm install webpack-dev-server -g | -D
参数:
命令行
webpack-dev-server --port 8088 --open --mode development
写到webpack.config.js配置文件:
devServer: {//和module同级
port: 8088,
open:true
}
终端运行方式2: webpack-dev-server
把运行命令放到package.json文件: devServer可以不要了
"scripts":{
"dev": "webpack-dev-server --port 8088 --open"
}
终端: npm run dev
1.5 优雅降级配置
-
先安装转换器需要的包
$ cnpm install [email protected] @babel/core @babel/preset-env -D
-
配置webpack.config.js
// 在webpack.config.js的module.rules中进行配置
{// 配置优雅降级
test: /\.js$/,
exclude: /node_modules/, // 排除node_models中的js文件
use: [{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}]
}
1.6 html产出 - 依赖的是插件
-
安装插件需要的第三方包
$ cnpm i html-webpack-plugin -D
const HtmlWebpackPlugin = require('html-webpack-plugin')
//添加一个配置项
plugins:[
new HtmlWebpackPlugin({
template: './public/index.html',
filename: './index.html',//默认到output目录
hash:true,//防止缓存,会给文件后面加入hash
minify:{
removeAttributeQuotes:true//压缩 去掉引号
}
})
]
1.7 css抽离 - 依赖的是插件
将webpack编译过得css文件以 css外部引用的形式引入
-
安装插件
$ cnpm i extract-text-webpack-plugin@next -D
const ExtractTextWebapckPlugin= require("extract-text-webpack-plugin")
//loader配置:
use: ExtractTextWebapckPlugin.extract({
use: 'css-loader'
}) //不再需要style-loader
//pulgin配置
new ExtractTextWebapckPlugin('css/[name][hash:6].css')
1.8 图片打包
yarn add url-loader file-loader --dev
npm I url-loader file-loader --save-dev
//url-loader 存base64 file-loader存文件(woff mp3)
{
test:/\.(png|jpg|gif)/,
use:[{
loader: 'url-loader',
options: {
limit: 5000,//字节少于5000 ——》 base64 超过5000 file
outputPath: 'images/', //5000意思存到images
}
}]
}
//css中引入 | js动态(模块化) 引入
1.9 静态资源拷贝
npm i copy-webpack-plugin -D
const CopyWebpackPlugin = require('copy-webpack-plugin')
//plugin配置
new CopyWebpackPlugin([
{ from: path.resolve(__dirname,'static'), to: path.resolve(__dirname,'build/static') }
])
1.10 配置文件拆分
"dev": "webpack --mode development --config config/webpack.config.dev.js",
"build": "webpack --mode production --config config/webpack.config.prod.js",
"server": "webpack-dev-server --mode development --config config/webpack.config.dev.js"
1.11 错误资源定制
// 在webpack.config.js中添加如下配置项:
devtool: 'source-map'
制定报错信息的源
1.12 后缀名省略
// 配置webpack.config.js
resolve: { //与module同级
extensions: [ '.js', '.css', '.json', '.jsx']
}
require('./style')// 可以省略后缀名
2.多页面配置
2.1 基础功能
/*
webpack配置文件
也是Node.js文件
这个文件也是一个独立的 Common.js 模块
*/
const path = require('path')
// 1. 创建模块
const webpackConfig = {
entry: { // 多页面配置,多个入口文件
'index': './src/index.js',
'main': './src/main.js'
}, //网络路径( 相对路径 )
output: { //出口目录、文件的配置
path: path.join( __dirname,'dist'), // 磁盘路径
filename: 'js/[name].js' // 入口文件将来打包到出口目录中的文件的路径和名称
},
mode: 'development'//确定是生产环境还是开发环境的打包
}
// 2. 导出模块
module.exports = webpackConfig
解释: 为什么我们的文件要跟上hash后缀?
- 目的: 就是为了创建多个版本,便于版本切换
[外链图片转存失败(img-sKf4RZcs-1568092342837)(E:\1905\2-Vuejs\Vue高级\day05\code\为什么webpack会给文件加后缀.png)]
作业:
webpack配置功能完成 2 次
配置sass
配置postcss
组件版的 todolist
复习 【 整理 】
四、Vue项目 与 高级应用