My Little World

一些关于vue的零散笔记

释放内部对象且能防止外部修改的方式

通过创建中间对象挂载到实例上,通过中间对象的set方法进行拦截

1
2
3
4
5
6
7
8
9
10
11
12
function initGlobalAPI (Vue) {
var configDef = {};
configDef.get = function () { return config; }; //config对象是vue对象构建过程的内部对象,存储全局配置项
{
configDef.set = function () {
warn(
'Do not replace the Vue.config object, set individual fields instead.'
);
};
}
Object.defineProperty(Vue, 'config', configDef);
}

Vue.config.optionMergeStrategies 应用中
Vue.config可以get,得到的即内部的config,但如果进行Vue.config = xxxx set操作就会报错
通过Vue.config可以获得内部config,从而可以修改内部config对象上的属性,从而修改到全局配置

关于3.0的思考

如何更快
Object.defineProperty–>Proxy
Virtual Dom重构
更多编译优化:
Slot默认编译为函数
重构vnode factory,统一输入参数,进一步优化编译处理函数(Monomorphic vnode factory)
编译时增加vnode/children 类型信息标识,从而做进一步优化(Compiler-generated flags for vnode/children types)

Function based API 对比Class API 好处
更好的TS类型推导支持
更灵活的逻辑复用能力
Tree-shaking 友好
代码更容易压缩

现有逻辑复用模式
Mixins
高阶组件
基于scoped slots/作用域插槽封装逻辑的组件
存在问题
数据来源不清晰 (Function based API 数据来源清晰)
命名冲突(Function based API 没有命名冲突)
无谓的额外组件的性能消耗 (Function based API 没有额外组件性能消耗)

对比React Hooks
同样的逻辑组合,复用能力更强
只调用一次
符合JS直觉
没有闭包变量问题
没有内存/GC压力
不存在内联回调导致子组件永远更新问题

2.0
mergeOption 选项策略处理
插件开发:以默认配置优先;以用户配置为覆盖
策略:听过JS 增强配置选项的表达力
{}==>function(){} el===根实例

数据劫持vue3.0改用proxy原因
defineProperty只能监听某个属性,不能对全对象监听,使用proxy可以省去for in提升效率
可以监听数组,不用再去单独的对数组做特异性操作

vue2.0 vdom性能瓶颈
虽然能够保证触发更新的组件最小化,但在单个组件内部依然需要遍历该组件的整个Vdom树
vdom的性能跟模板大小正相关,跟动态节点的数量无关。
在一些组件整个模板内只有少量动态节点的情况下,这些遍历都是性能的浪费

编译3步骤

parse:AST
optimize:标记静态节点
generate 生成目标平台所需的代码 将AST转化成render function字符串

修饰符

v-model.lazy 从input事件中转变为在change事件中同步数据
v-model.number 可以将输入转换为Number类型
v-model.trim 可以自动过滤输入的首尾空格

v-for 循环时,key尽量赋值为不变的值,即静态值,如item.id ,否则列表增删时,会更新每一项

当子组件需要向父组件传递数据时,就要用到自定义事件
子组件用$emit来触发事件,父组件用$on()来监听子组件的事件
自定义组件的v-model :一个组件上的v-model 默认会利用名为value的prop和名为input的事件
将原生事件绑定到组件: 使用v-on的.native修饰符监听原生事件
.sync修饰符:父组件监听自定义事件按需更新数据

组件

动态组件:VUE 提供了一个特殊的元素<component>用来动态的挂载不同的组件,使用is特性来选择要挂载的组件, 还可以使用<keep-alive>标签使组件进行缓存

异步组件:VUE允许将组件定义为一个工厂函数,动态地解析组件。VUE只在组件需要渲染时触发工厂函数,并且把结果缓存起来用于后面地再次渲染

组件创建方式

1.调用Vue.extend(),创建名为xx的组件,template定义模板的标签,模板的内容需要写在该标签下

1
2
3
var xx = Vue.extend({
template:'<div>this is a component</div>'
})

2.使用<template>标签创建,需要加上id属性

1
2
3
<template id = 'mycom'>
<div>this is a component</div>
</template>

3.使用<script>标签创建,需要加id属性,同时还得加type=’text/x-template’ 不执行编译里面的代码

1
2
3
<script type='text/x-template' id = 'mycom'>
<div>this is a component</div>
</script>

组件全局注册方式

1.调用Vue.extend(),创建名为myCom的组件全局注册

1
Vue.component('my-com',myCom)

2.template及script标签构建的组件全局注册

1
2
3
Vue.component('my-comp',{
template:'#mycom'
})

组件局部注册

1.调用Vue.extend(),创建名为myCom的组件局部注册(只能在注册该组件的实例中使用,一处注册,一处使用)

1
2
3
4
5
6
var app = new Vue({
el:'#app',
components:{
'my-com':myCom
}
})

2.template及script构建的组件局部注册

1
2
3
4
5
6
7
8
var app = new Vue({
el:'#app'
componnets:{
'my-com':{
template:'#myCom'
}
}
})

组件化处理边界情况

1.访问根实例 this.$root.xxx
2.访问父组件实例:this.$parent.xxx
3.访问子组件实例或子元素:<child ref=’xxx’></child > =>this.$refs.xxx
4.依赖注入:

1
2
3
4
5
6
provide:function(){ //父组件
return{
getMap:this.getMap
}
}
inject:[getMap]//子组件

然而,依赖注入还是有负面影响的。它将你应用程序中的组件与它们当前的组织方式耦合起来,使重构变得更加困难。同时所提供的属性是非响应式的。这是出于设计的考虑,因为使用它们来创建一个中心化规模化的数据跟使用 $root做这件事都是不够好的。如果你想要共享的这个属性是你的应用特有的,而不是通用化的,或者如果你想在祖先组件中更新所提供的数据,那么这意味着你可能需要换用一个像 Vuex 这样真正的状态管理方案了

5.统一处理事件侦听器时,在组件卸载前,统一清除监听器
6.组件循环引用,Vue.component注册的组件允许,但是模块化导入的不允许
7.模板定义的替代品:
A:内联模板:当inline-template这个特殊的特性出现在一个子组件上时,这个组件将会使用其里面的内容作为模板
而不是将其作为被分发的内容

1
<myCom inline-template><div><p>these are compiled as the component's own template</p></div></myCom>

B:x-template
在script标签里使用text/x-template,并且指定id,将这个id赋值给template

1
2
3
4
5
6
<script type='text/x-template' id = 'mycom'>
<div>this is a component</div>
</script>
Vue.component('my-comp',{
template:'#mycom'
})

8.强制更新
A:使用this.$forceUpdate
B:使用v-once创建低开销静态组件,组件包含大量静态内容可以在根元素上添加v-once特性以确保这些内容只计算一次然后缓存起来

组件通信类型

父子组件通信
1.使用props和$emit父子组件相互通信
2.父组件用$children或者利用ref操作子组件
3.子组件$parent访问父组件

非父子组件通信
1.使用中央事件总线(eventbus来处理非父子组件间的通信)
2.祖先元素通过provide提供数据,后代通过inject获取该数据
3.使用$attrs和$listeners实现祖孙组件通信
4.$root直接访问根组件

Vue.use

Vue.use(myPlugin)本质上是调用myPlugin.install(VUE)
使用插件必须在new vue()启动应用之前完成,实例化之前就要配置好
使用Vue.use多次注册相同插件,那只会注册成功一次
一个测试案例

1
2
3
4
5
6
7
8
9
10
11
12
13
import Vue from 'vue'
import {expect} from 'chai'
import Counter from '@/counter.vue'

describe('测试Counter.vue',()=>{
const Constructor = Vue.extend(Counter)
const vm = new Constructor().$mount()
const button = vm.$el.querySelector('button')
const clickE = new window.Event('click')
button.dispatchEvent(clickE)
vm._watcher.run()
expect(Number(vm.$el.querySelector('span').textContent)).to.equal(1)
})

vuex

默认的五种基本对象
state:存储状态(对象)
getters:对数据获取之前的再次编译,可以理解为state的计算属性,对state的数据进行筛选,过滤
mutations:同步修改状态,并且是同步的。在组件中使用$store.commit(‘’,params)
actions:异步修改状态,在组件中使用是$store.dispatch(‘’)
modules:store的子模块,为了开发大型项目,方便状态管理而使用的