snabbdom, jsx学习

createVnode

  • snabbdom创建vnode比较简单, 就是遍历创建对象
  • 相当于Vue里的 vm.$createElement(自己写render的时候调用,alwaysNormalize是true)或vm._c
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    function h(sel, data, children) {
    // option adapter
    // ...
    if (is.array(children)) {
    for (i = 0; i < children.length; ++i) {
    if (is.primitive(children[i]))
    children[i] = vnode_1.vnode(undefined, undefined, undefined, children[i]);
    }
    }
    return vnode_1.vnode(sel, data, children, text, undefined);
    }
    function vnode(sel, data, children, text, elm) {
    var key = data === undefined ? undefined : data.key;
    return { sel: sel, data: data, children: children,
    text: text, elm: elm, key: key };
    }

patch

  • patch时和Vue是相似的, 第一次patch 对于根节点old vnode是要挂载的dom(组件的话会是undefined), 之后便是vnode的对比
  • 第一次patch就是为vnode创建node, 然后替换掉el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var vnode = h('div#container.two.classes', {on: {click: someFn}}, [
h('span', {style: {fontWeight: 'bold'}}, 'This is bold'),
' and this is just normal text',
h('a', {props: {href: '/foo'}}, 'I\'ll take you places!')
]);
// Patch into empty DOM element – this modifies the DOM as a side effect
patch(container, vnode);
var newVnode = h('div#container.two.classes', {on: {click: anotherEventHandler}}, [
h('span', {style: {fontWeight: 'normal', fontStyle: 'italic'}}, 'This is now italic type'),
' and this is still just normal text',
h('a', {props: {href: '/bar'}}, 'I\'ll take you places!')
]);
// Second `patch` invocation
patch(vnode, newVnode); // Snabbdom efficiently updates the old view to the new state
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var isRealElement = isDef(oldVnode.nodeType);
if (!isRealElement && sameVnode(oldVnode, vnode)) {
// patch existing root node
patchVnode(oldVnode, vnode, insertedVnodeQueue, null, null,removeOnly);
} else {
if (isRealElement) {
oldVnode = emptyNodeAt(oldVnode);
}
// create new node for new vnode
createElm(...)
// destroy old node
if (isDef(parentElm)) {
removeVnodes(parentElm, [oldVnode], 0, 0);
} else if (isDef(oldVnode.tag)) {
invokeDestroyHook(oldVnode);
}
}
// new vnode 的 dom插入后回调
invokeInsertHook(vnode, insertedVnodeQueue, isInitialPatch);
return vnode.elm

hooks

  • create
  • insert

    vue里的vnode hooks

    1
    2
    3
    4
    - 0: "init"
    - 1: "prepatch"
    - 2: "insert" 组件vm的mount在这里触发 callHook(componentInstance, 'mounted');
    - 3: "destroy"

jsx

babel7

  • https://github.com/vuejs/jsx#installation
    1
    2
    3
    4
    5
    6
    7
    8
    Install the preset with:
    npm install @vue/babel-preset-jsx @vue/babel-helper-vue-jsx-merge-props
    Then add the preset to .babelrc:
    {
    "presets": ["@vue/babel-preset-jsx"]
    }

babel6

依赖

1
2
3
4
babel-plugin-syntax-jsx\
babel-plugin-transform-vue-jsx\
babel-helper-vue-jsx-merge-props\
babel-preset-env\

写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Vue.component('jsx-example', {
render () { // h will be injected
return <div id="foo">bar</div>
},
myMethod: function () { // h will not be injected
return <div id="foo">bar</div>
},
someOtherMethod: () => { // h will not be injected
return <div id="foo">bar</div>
}
})
@Component
class App extends Vue {
get computed () { // h will be injected
return <div id="foo">bar</div>
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
Vue.component('jsx-example', {
data() {
return {
text: 'xxx'
}
},
methods: {
clickHandler : function(e) {
console.log('clickHandler ', e);
},
nativeClickHandler(e) {
console.log('nativeClickHandler ', e);
},
},
render (h) {
const data = {
class: ['b', 'c']
}
const vnode = <div class="a" {...data}/>
console.log(vnode)
return (
<div
// normal attributes or component props.
id="foo"
// DOM properties are prefixed with `domProps`
domPropsInnerHTML="bar"
// event listeners are prefixed with `on` or `nativeOn`
onClick={this.clickHandler}
nativeOnClick={this.nativeClickHandler}
// other special top-level properties
class={{ foo: true, bar: false }}
style={{ color: 'red', fontSize: '14px' }}
key="key"
ref="ref"
// assign the `ref` is used on elements/components with v-for
refInFor
slot="slot">
</div>
)
}
})