共计 7052 个字符,预计需要花费 18 分钟才能阅读完成。
数据驱动:将数据和视图相关联,当数据发生变化时,能够自动更新视图。
单页利用 VS 多用利用
1) 多页利用:
长处:首屏工夫快,SEO 成果好
毛病:页面切换慢
2) 单页利用:
长处:页面切换快
毛病:首屏工夫稍慢,SEO 差
计算属性
依赖条件不变的前提下,第一次计算的后果会被缓存起来,前面再应用时间接应用第一次计算的后果。
计算属性当其依赖属性的值发生变化时,这个属性的值会自动更新,与之相干的 DOM 局部也会同步自动更新。
1)计算属性两种模式
- 函数模式
-
对象模式,具备 get()和 set()办法
computed: { url: {get() {return `${this.protocol}//${this.host}`; }, set(val) {const tmp = val.split('//'); if (tmp.length > 1) {this.protocol = tmp[0]; this.host = tmp[1]; } } } }
2)计算属性利用闭包传参
computed: {url() {return function(hash) {return `${this.protocol}//${this.host}#${hash}`;
}
}
}
侦听器
1. 函数模式
2. 对象模式
watch: {
location: {
immediate: true, // 在初始化时执行
deep: true, // 递归 (深度) 遍历
handler(newVal, oldVal) {this.url = `${newVal.protocol}//${newVal.host}`;
}
}
}
computed 和 watch 的区别
计算属性和侦听器的本质都是 Watcher 的实例。
computed 基于响应式依赖进行缓存,只在相干响应式依赖产生扭转时才会从新求值。
在依赖不变的状况下,计算属性应用缓存的上次的计算结果,而不会反复执行
watch 当须要在数据变动时执行异步或开销较大的操作时,应用 watch。
v-if 和 v -show
v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
v-if 动静增删节点 (DOM),v-show 管制 CSS 属性(display) 进行切换;
v-if 是惰性的,初始条件为 false 时不会参加模板编译;v-show 会始终参加渲染;
v-if 会缓存编译后果,当 v -if 条件为 true 时,vue 会编译为虚构 DOM 并缓存,待下一次条件渲染间接应用。
v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因而,如果须要十分频繁地切换,则应用 v-show 较好;如果在运行时条件很少扭转,则应用 v-if 较好。
v-if 中的 key
Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。
给元素增加一个具备惟一值的 key attribute,示意元素是齐全独立的,不要复用它们。
<template v-if="loginType ==='username'">
<label>Username</label>
<input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address" key="email-input">
</template>
v-if 和 v -for
同一元素上,v-for 优先级高于 v -if,即先执行遍历,再执行判断。
若条件呈现在循环外部,可通过计算属性 computed 提前过滤掉那些不须要显示的项。
v-for 中的 key 值的作用:作为同级元素的标识,进步更新效率。
key 值的作用先要理解 vue 更新 DOM 的机制,即 Diff 算法。该算法有三个假如, 其中一个是同级元素能够通过惟一 id 值辨别,而 key 值的作用即作为这个 id 值,使更新(包含插入,删除,新增,替换等等)时,vue 可能甄别到底是哪些虚构 DOM 产生了变动,而不是抽象的批量更新。
应用 of 作为分隔符,因为它更靠近 JavaScript 迭代器的语法:
<div v-for="item of items" :key="item.id"></div>
变异办法和非变异办法
变异办法:Vue 将被侦听的数组的变更办法进行了改写,会变更原始数组
push()、pop()、unshift()、shift()、splice()、reverse()、sort()
非变异办法:不会变更原始数组,而总是返回一个新数组
filter()、concat() 和 slice()
当应用非变更办法时,能够用新数组替换旧数组
事件
<button @click="add(step, $event)"></button>
methods: {add(step, event) {
this.count += step;
console.log(event); // 拜访原生事件对象
}
}
事件修饰符:
.stop // 阻止事件冒泡
.prevent // 阻止浏览器默认行为
.self // 当触发事件的对象 (event.target) 是本身才执行
.capture // 监听器采纳事件捕捉模型
.once // 监听器触发一次后移除
.passive // 通知浏览器该监听器是“被动的”,不会阻止浏览器默认行为,让滑动更顺畅。尤其可能晋升挪动端的性能。
数据双向绑定(v-model)
v-model 指令用来在 input、select、text、checkbox、radio 等表单控件元素上创立双向数据绑定。
v-model 是语法糖,在用户输出事件中更新数据。
v-model 增加.lazy 修饰符将监听 change 事件.native
修饰符用于在一个组件的根元素上监听原生事件 // 给组件绑定原生事件
vue-validator 表单校验插件
组件化开发
指标:为了可重用性高,缩小重复性的开发,即一处开发,多处应用。
单向数据流:父组件向子组件传值
1) is 属性, 在 table、ul、ol、select 中应用
有些 HTML 元素,诸如 <ul>、<ol>、<table> 和 <select>,对于哪些元素能够呈现在其外部是有严格限度的。而有些元素,诸如 <li>、<tr> 和 <option>,只能呈现在其它某些特定的元素外部。
<table>
<tbody>
<tr is="row"></tr> // row 组件
</tbody>
</table>
2) 子组件中 data 必须是一个函数,且返回一个对象
data() {
return {list: []
}
}
vue 组件可能会有很多个实例,采纳函数返回一个全新 data 模式,使每个实例对象的数据不会受到其余实例对象数据的净化。
- 根实例对象 data 能够是对象也能够是函数(根实例是单例),不会产生数据净化状况。
- 组件实例对象 data 必须为函数,目标是为了避免多个组件实例对象之间共用一个 data,产生数据净化。采纳函数的模式,initData 时会将其作为工厂函数都会返回全新 data 对象。
3) 动静组件
在不同组件之间进行动静切换
<component :is="type"></component> // type 为组件名变量
组件间通信
1) 父子组件通信:props 和 $emit
2) 兄弟组件通信:事件总线 (EventBus)
$emit 触发事件,$on 监听,$off() 用来删除事件监听器
非父子组件间传值(Bus | 总线 | 公布订阅模式 | 观察者模式)
// eventBus.js
Vue.prototype.eventBus = new Vue();
// 组件 A
this.eventBus.$emit('send', text); // 触发
// 组件 B
this.eventBus.$on('send', (text) => { // 监听
this.text = text;
});
3) Vuex:状态管理工具
集中式状态治理,对全局共享状态数据进行治理和操作。应用场景:
1)多个 view 依赖同一个状态(state)
2)多个 view 要扭转同一个状态(state)
store 是管理器
state:状态
mutations:更改 Vuex 的 store 中的状态的惟一办法,同步
actions:异步
getters:相似于计算属性
组件不容许间接批改 store 里的 state,用 commit 函数提交 mutation 办法来批改数据。
插槽
<slot>
作为咱们想要插入内容的占位符
1) slot
<div>
<h1>title</h1>
<slot></slot>
<p> 说点啥 </p>
</div>
2) 具名插槽
// page 组件
<div class="page">
<slot name="header"></slot>
<slot>default content</slot>
<slot name="footer"></slot>
</div>
// 应用 page 组件
<page>
<page-header slot="header"></page-header>
<main class="page__main">page content……</main>
<page-footer slot="footer"></page-footer>
</page>
3) 作用域插槽 (带数据的插槽) // 罕用于表格
有时让插槽内容可能拜访子组件中才有的数据是很有用的。当一个组件被用来渲染一个我的项目数组时,这是一个常见的状况,咱们心愿可能自定义每个我的项目的渲染形式。
<slot :list="list"></slot>
// 应用作用域插槽
<template slot-scope="scope">
<p v-for="item of scope.list" :key="item.id">{{item.name}}</p>
</template>
可参考 iView 组件库
自定义指令
残缺的指令:v-name:foo.a=”expression”
其中 name: 指令名称,foo:参数,a:修饰符,expression:表达式。
1) 全局注册
-
回调函数模式
Vue.directive('test', function(el, bindings, vnode) {console.log(el, bindings); })
-
对象模式 — 钩子函数
Vue.directive('test', {bind(el, bindings, vnode) { // 初始化数据 console.log('bind') }, inserted(el, bindings, vnode) { // 获取父级的 DOM 元素 console.log('inserted') }, update(el, bindings, vnode) { // 监听绑定的组件的变动 console.log('update'); }, componentUpdated(el, bindings, vnode) { // 监听绑定的组件的变动 console.log('componentUpdated'); }, unbind(el, bindings, vnode) { // 组件销毁时触发 console.log('unbind'); }, })
2) 部分注册
directives: { test: {// 同上} }
3) 长按指令
// 长按指令定义 Vue.directive('long-press', function(el, bindings) { let timer = null; const value = bindings.value; const duration = value.duration || 700; // 长按工夫 const fn = value.callback; // 回调函数 const _this = this; el.addEventListener('touchstart', run); el.addEventListener('touchend', stop); el.addEventListener('touchmove', stop); function run() {if (timer === null) {timer = setTimeout(() => {fn && fn.call(_this, el, value); clearTimeout(timer); }, duration); } } function stop() { // 勾销 -- 革除定时器 clearTimeout(timer); timer = null; } }) // 长按指令应用 // 用 value 作为对象的形式给 long-press 指令传参 <ul> <li v-for="item of list" :key="item.id" v-long-press="{ callback: handleLongPress, item: item, duration: 500 }" ></li> </ul> handleLongPress(el, value) {console.log(value); // do sth }
生命周期
一个事物从诞生,到倒退,继续,直至最初销毁的过程,叫它的生命周期。
实例创立 => 挂载 => 数据变动 => 更新视图 => 销毁
1) $nextTick([callback]) 设置一个回调,在下次 DOM 更新之后执行数据变动后,视图不会立刻更新。
2) $forceUpdate() 使实例从新渲染,更新视图。
3) 生命周期钩子:
beforeCreate:组件实例还未创立
created:实例创立实现,初始化数据($data),实现配置,罕用于异步数据获取
beforeMount:render 函数渲染,未执行渲染、更新,dom 未创立
mounted:挂载实现,dom 已创立,可用于获取拜访数据和 dom 元素。利用:eg: 上报页面拜访人数
beforeUpdate 时,虚构 DOM 曾经生成
updated:该实例更新实现 // 若心愿子组件等更新实现,在 $nextTick([callback])中解决
beforeDestroy:销毁之前,可用于一些定时器或订阅的勾销
destroyed:销毁实现
渲染
1) el 挂载
2) template 模板
3) 自定义 render
无论哪种渲染写法在执行 $mount 时都是将生成 render 函数。
Render 函数调用_render => 虚构 DOM 调用_update => 实在 DOM
模板编译的过程:
parse 生成 AST 语法树,optimize 优化,generate 生成 render 函数 code。// AST 形象语法树
parse 的作用是把模板内容转化成 AST 语法树,不便程序剖析;
optimize 的作用是优化语法树,通过标记动态节点的形式;
generate 生成 render 函数的 code,是字符串类型。
模板编译是为了生成 render 函数,并不会执行 render 函数,render 生成的是虚构 DOM。
DOM 更新:
渲染 watcher 的回调函数 updateComponent 实现了 DOM 更新
_render 生成虚构 DOM
_update 通过比拟虚构 DOM 更新实在 DOM
数据变动时才可能触发渲染 watcher 执行更新
Vue-Router
- 扭转 URL 不向服务器发送申请
- 前端监听 URL 变动
- 解析 URL 并执行相应操作
三种模式:hash、history、abstract
abstract:实用于所有 JavaScript 环境,例如服务器端应用 Node.js。若没有浏览器 API,路由器将主动被强制进入此模式。
1) hash
window.location.assign()
window.location.replace()
window.onhashchange // hashchange 事件
2) history
window.history.pushState()
window.history.replaceState()
window.onpopstate // pushState 和 replaceState 不会触发 popstate 事件
history.pushState/history.replaceState 不会触发 popstate 事件,只扭转 url 和历史记录
history 模式采纳的是实在路由,须要服务器重定向到主页,否则刷新浏览器还是会向服务器发送申请,报 404
3) hash 与 history 的区别
hash:丑(#),hash 会占用锚点性能,兼容性较好
history:路由与后端无异,IE10 及以上,须要后端反对
4)Router API
$router 办法:
$router.push()
$router.replace()
$router.go()
$router.forward()
$router.back()
router.push/router.replace 在不同模式下调用的底层 API 不同,一个扭转实在 url 门路,一个只扭转 hash。
$route 参数:
$route.params -- 动静路由匹配的参数
$route.query -- 查问参数
$route.hash -- url 的 hash 值
$route.fullPath -- url 全门路
$route.meta -- 与页面关联的元信息
5)parse location
parseLocation(location) {const { path, query, hash} = location;
return `${path}?${parseQuery(query)}#${hash}`;
}
parseQuery(query) {return Object.keys(query).map(key => {return `${key}=${query[key]}`;
}).join('&');
}