在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
一、节点、树以及虚拟 DOM<div> <h1>My title</h1> Some text content <!-- TODO: Add tagline --> </div> 每个元素都是一个节点。每段文字也是一个节点。甚至注释也都是节点。一个节点就是页面的一个部分。就像家谱树一样,每个节点都可以有孩子节点 (也就是说每个部分可以包含其它的一些部分)。 高效地更新所有这些节点会是比较困难的,不过所幸你不必手动完成这个工作。你只需要告诉 Vue 你希望页面上的 HTML 是什么,这可以是在一个模板里: <h1>{{ blogTitle }}</h1> 或者一个渲染函数里: render: function (createElement) { return createElement('h1', this.blogTitle) } 在这两种情况下,Vue 都会自动保持页面的更新,即便 blogTitle 发生了改变。 二、虚拟 DOMVue 通过建立一个虚拟 DOM 来追踪自己要如何改变真实 DOM。请仔细看这行代码: return createElement('h1', this.blogTitle)
// @returns {VNode} createElement( // {String | Object | Function} // 一个 HTML 标签名、组件选项对象,或者 // resolve 了上述任何一种的一个 async 函数。必填项。 'div', // {Object} // 一个与模板中 attribute 对应的数据对象。可选。 { // (详情见下一节) }, // {String | Array} // 子级虚拟节点 (VNodes),由 `createElement()` 构建而成, // 也可以使用字符串来生成“文本虚拟节点”。可选。 [ '先写一些文字', createElement('h1', '一则头条'), createElement(MyComponent, { props: { someProp: 'foobar' } }) ] ) 2.1 深入数据对象在渲染函数中,一些模板属性会在Vnode数据对象中有顶层字段,同时对象也允许绑定普通的属性,也允许绑定如 { // 与 `v-bind:class` 的 API 相同, // 接受一个字符串、对象或字符串和对象组成的数组 'class': { foo: true, bar: false }, // 与 `v-bind:style` 的 API 相同, // 接受一个字符串、对象,或对象组成的数组 style: { color: 'red', fontSize: '14px' }, // 普通的 HTML attribute attrs: { id: 'foo' }, // 组件 prop props: { myProp: 'bar' }, // DOM property domProps: { innerHTML: 'baz' }, // 事件监听器在 `on` 内, // 但不再支持如 `v-on:keyup.enter` 这样的修饰器。 // 需要在处理函数中手动检查 keyCode。 on: { click: this.clickHandler }, // 仅用于组件,用于监听原生事件,而不是组件内部使用 // `vm.$emit` 触发的事件。 nativeOn: { click: this.nativeClickHandler }, // 自定义指令。注意,你无法对 `binding` 中的 `oldValue` // 赋值,因为 Vue 已经自动为你进行了同步。 directives: [ { name: 'my-custom-directive', value: '2', expression: '1 + 1', arg: 'foo', modifiers: { bar: true } } ], // 作用域插槽的格式为 // { name: props => VNode | Array<VNode> } scopedSlots: { default: props => createElement('span', props.text) }, // 如果组件是其它组件的子组件,需为插槽指定名称 slot: 'name-of-slot', // 其它特殊顶层 property key: 'myKey', ref: 'myRef', // 如果你在渲染函数中给多个元素都应用了相同的 ref 名, // 那么 `$refs.myRef` 会变成一个数组。 refInFor: true } 2.2 约束VNode 必须唯一 组件树中的所有 render: function (createElement) { var myParagraphVNode = createElement('p', 'hi') return createElement('div', [ // 错误 - 重复的 VNode myParagraphVNode, myParagraphVNode ]) } 如果你真的需要重复很多次的元素/组件,你可以使用工厂函数来实现。例如,下面这渲染函数用完全合法的方式渲染了 20 个相同的段落: render: function (createElement) { return createElement('div', Array.apply(null, { length: 20 }).map(function () { return createElement('p', 'hi') }) ) } 三、在Render函数中的模板功能3.1 v-if 和 v-for只要在原生的 <ul v-if="items.length"> <li v-for="item in items">{{ item.name }}</li> </ul> <p v-else>No items found.</p> 这些都可以在渲染函数中用 props: ['items'], render: function (createElement) { if (this.items.length) { return createElement('ul', this.items.map(function (item) { return createElement('li', item.name) })) } else { return createElement('p', 'No items found.') } } 3.2 v-model渲染函数中没有与 props: ['value'], render: function (createElement) { var self = this return createElement('input', { domProps: { value: self.value }, on: { input: function (event) { self.$emit('input', event.target.value) } } }) } 这就是深入底层的代价,但与 3.3 事件 & 按键修饰符对于 . 例如: on: { '!click': this.doThisInCapturingMode, '~keyup': this.doThisOnce, '~!mouseover': this.doThisOnceInCapturingMode } 对于所有其它的修饰符,私有前缀都不是必须的,因为你可以在事件处理函数中使用事件方法:
这里是一个使用所有修饰符的例子: on: { keyup: function (event) { // 如果触发事件的元素不是事件绑定的元素 // 则返回 if (event.target !== event.currentTarget) return // 如果按下去的不是 enter 键或者 // 没有同时按下 shift 键 // 则返回 if (!event.shiftKey || event.keyCode !== 13) return // 阻止 事件冒泡 event.stopPropagation() // 阻止该元素默认的 keyup 事件 event.preventDefault() // ... } } 3.4 插槽你可以通过 render: function (createElement) { // `<div><slot></slot></div>` return createElement('div', this.$slots.default) } 也可以通过 props: ['message'], render: function (createElement) { // `<div><slot :text="message"></slot></div>` return createElement('div', [ this.$scopedSlots.default({ text: this.message }) ]) } 如果要用渲染函数向子组件中传递作用域插槽,可以利用 render: function (createElement) { // `<div><child v-slot="props"><span>{{ props.text }}</span></child></div>` return createElement('div', [ createElement('child', { // 在数据对象中传递 `scopedSlots` // 格式为 { name: props => VNode | Array<VNode> } scopedSlots: { default: function (props) { return createElement('span', props.text) } } }) ]) } 3.5 例子import { CreateElement, RenderContext } from 'vue/types/umd' export default { functional: true, props: { row: Object, render: Function, index: Number, column: { type: Object, default: null } }, render: (h: CreateElement, ctx: RenderContext) => { const params: any = { row: ctx.props.row, index: ctx.props.index } if (ctx.props.column) params.column = ctx.props.column return ctx.props.render(h, params) } } 到此这篇关于 |
请发表评论