习以为常却被忽略的vue小知识
root element
父模板中调用组件的元素将会被组件本身的模板取代。因此,如果组件的模板包含多个顶级元素:
Vue.component('example', {
template:
'<div>A</div>' +
'<div>B</div>'
})
或者模板只包含文本:
Vue.component('example', {
template: 'Hello world'
})
在这两个情况下,实例将变成一个片段实例 (fragment instance),也即没有根元素的实例。它的 $el 指向一个锚节点(普通模式下是空的文本节点,debug 模式下是注释节点)。更重要的是,父模板组件元素上的指令、过渡效果和属性绑定(props 除外)将无效,因为生成的实例并没有根元素供它们绑定
<!-- 指令不生效,因为没有根元素用来绑定 -->
<example v-show="ok" v-transition="fade"></example>
<!-- props 还是能够正常生效 -->
<example prop="{{someData}}"></example>
拓展:Web Components – 面向未来的组件标准
组件中的data必须是函数
当一个组件被定义, data 必须声明为返回一个初始数据对象的函数,因为组件可能被用来创建多个实例。如果 data 仍然是一个纯粹的对象,则所有的实例将共享引用同一个数据对象!通过提供 data 函数,每次创建一个新实例后,我们能够调用 data 函数,从而返回初始数据的一个全新副本数据对象。
如果需要,可以通过将 vm.$data 传入 JSON.parse(JSON.stringify(…)) 得到深拷贝的原始数据对象。
复杂类型=>指针 简单类型=>值
Vue.nextTick()
Vue 的 DOM 更新是异步执行,当侦测到数据变化时,Vue 会打开一个队列,然后把在同一个事件循环 (event loop) 当中观察到数据变化的 watcher 推送进这个队列。假如一个 watcher 在一个事件循环中被触发了多次,它只会被推送到队列中一次。
然后,在进入下一次的事件循环时, Vue 会清空队列并进行必要的 DOM 更新。(microtasks和macrotasks)
if (typeof MutationObserver !== 'undefined' && !hasMutationObserverBug) {
var counter = 1
// 创建一个MutationObserver,observer监听到dom改动之后后执行回调nextTickHandler
var observer = new MutationObserver(nextTickHandler)
var textNode = document.createTextNode(counter)
// 调用MutationObserver的接口,观测文本节点的字符内容
observer.observe(textNode, {
characterData: true
})
// 每次执行timerFunc都会让文本节点的内容在0/1之间切换,
// 不用true/false可能是有的浏览器对于文本节点设置内容为true/false有bug?
// 切换之后将新值赋值到那个我们MutationObserver观测的文本节点上去
timerFunc = function() {
counter = (counter + 1) % 2
textNode.data = counter
}
} else {
// webpack attempts to inject a shim for setImmediate
// if it is used as a global, so we have to work around that to
// avoid bundling unnecessary code.
// webpack默认会在代码中插入setImmediate的垫片
// 没有MutationObserver就优先用setImmediate,不行再用setTimeout
const context = inBrowser ?
window :
typeof global !== 'undefined' ? global : {}
timerFunc = context.setImmediate || setTimeout
}
MO和Promise.resolve().then(nextTickHandler)
// 文档示例
var vm = new Vue({
el: '#example',
data: {
msg: '123'
}
})
vm.msg = 'new message' // change data
vm.$el.textContent === 'new message' // false
Vue.nextTick(function() {
vm.$el.textContent === 'new message' // true
})
css scoped
data-v-079ce416属性
app[data-v-079ce416]
跟随作用域,webpack loader处理,加上'[hash:base64]’属性
h => h(App)
h是createElement(),传入{},返回vNode;
模板到DOM大致流程:
template模板经过parse处理后返回AST
获得一棵AST后再经过generate()生成渲染函数
执行渲染函数后会获得一个VNode,即虚拟DOM
patch函数,负责把虚拟DOM变为真正DOM。