1

习以为常却被忽略的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。


逺方小鎭
1.3k 声望165 粉丝