Введение
При использовании Vue для разработки в большинстве случаев для разработки используется шаблон, использование шаблона простое, удобное и быстрое, но иногда не очень подходит использование шаблона в особых сценариях. Итак, чтобы эффективно использовать функцию рендеринга, я решил копнуть немного глубже. Если вы считаете, что следующее неверно, пожалуйста, укажите, что ваше взаимодействие со мной является самой большой мотивацией для написания. Началось в:Vue render заглядывает глубоко в тайну
Сцены
Сценарий, описанный на официальном сайте Когда мы начинаем писать компонент, динамически генерирующий теги заголовков через level prop, вы можете быстро подумать об этом:
<script type="text/x-template" id="anchored-heading-template">
<h1 v-if="level === 1">
<slot></slot>
</h1>
<h2 v-else-if="level === 2">
<slot></slot>
</h2>
<h3 v-else-if="level === 3">
<slot></slot>
</h3>
<h4 v-else-if="level === 4">
<slot></slot>
</h4>
<h5 v-else-if="level === 5">
<slot></slot>
</h5>
<h6 v-else-if="level === 6">
<slot></slot>
</h6>
</script>
Vue.component('anchored-heading', {
template: '#anchored-heading-template',
props: {
level: {
type: Number,
required: true
}
}
})
Использование шаблона в этом случае не лучший вариант: во-первых, код многословный, чтобы вставить элементы привязки в разные уровни заголовков, нам нужно использовать его многократно.
Хотя шаблоны отлично работают в большинстве компонентов, здесь они не очень кратки. Итак, давайте попробуем переписать приведенный выше пример, используя функцию рендеринга:
Vue.component('anchored-heading', {
render: function (createElement) {
return createElement(
'h' + this.level, // tag name 标签名称
this.$slots.default // 子组件中的阵列
)
},
props: {
level: {
type: Number,
required: true
}
}
})
Намного проще и понятнее! Короче говоря, этот код намного проще, но требует хорошего знакомства со свойствами экземпляра Vue. В этом примере вам нужно знать, что когда вы передаете контент в компонент без использования атрибута слота, такого как Hello world!, в заголовке с привязкой, эти дочерние элементы сохраняются в $slots.default в экземпляре компонента.
Введение параметра createElement
Следующее, с чем вам нужно ознакомиться, это как генерировать шаблоны в функции createElement. Вот параметры, которые принимает createElement:
createElement(
// {String | Object | Function}
// 一个 HTML 标签字符串,组件选项对象,或者
// 解析上述任何一种的一个 async 异步函数,必要参数。
'div',
// {Object}
// 一个包含模板相关属性的数据对象
// 这样,您可以在 template 中使用这些属性。可选参数。
{
// (详情见下一节)
},
// {String | Array}
// 子节点 (VNodes),由 `createElement()` 构建而成,
// 或使用字符串来生成“文本节点”。可选参数。
[
'先写一些文字',
createElement('h1', '一则头条'),
createElement(MyComponent, {
props: {
someProp: 'foobar'
}
})
]
)
Детализация объекта данных
Одно замечание: как и в синтаксисе шаблона, v-bind:class и v-bind:style обрабатываются особым образом, в объектах данных VNode следующие имена свойств являются полями самого высокого уровня. Этот объект также позволяет привязывать общие свойства HTML, такие как свойства DOM, такие как innerHTML (это заменяет директиву v-html).
{
// 和`v-bind:class`一样的 API
'class': {
foo: true,
bar: false
},
// 和`v-bind:style`一样的 API
style: {
color: 'red',
fontSize: '14px'
},
// 正常的 HTML 特性
attrs: {
id: 'foo'
},
// 组件 props
props: {
myProp: 'bar'
},
// DOM 属性
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
}
}
],
// Scoped slots in the form of
// { name: props => VNode | Array<VNode> }
scopedSlots: {
default: props => createElement('span', props.text)
},
// 如果组件是其他组件的子组件,需为插槽指定名称
slot: 'name-of-slot',
// 其他特殊顶层属性
key: 'myKey',
ref: 'myRef'
}
условный рендеринг
Теперь, когда мы знакомы с вышеупомянутыми API, давайте взглянем на реальный бой. писал это раньше
//HTML
<div id="app">
<vv-isshow :show="isShow"></vv-isshow>
</div>
//js
//组件形式
Vue.component('vv-isshow', {
props:['show'],
template:'<div v-if="show">我被你发现啦2!!!</div>',
});
var vm = new Vue({
el: "#app",
data: {
isShow:true
}
});
рендер пиши вот так
//HTML
<div id="app">
<vv-isshow :show="isShow"><slot>我被你发现啦3!!!</slot></vv-isshow>
</div>
//js
//组件形式
Vue.component('vv-isshow', {
props:{
show:{
type: Boolean,
default: true
}
},
render:function(h){
if(this.show ) return h('div',this.$slots.default);
},
});
var vm = new Vue({
el: "#app",
data: {
isShow:true
}
});
Рендеринг списка
Это было написано так раньше, и шаблон должен быть обернут меткой, когда используется v-for
//HTML
<div id="app">
<vv-aside v-bind:list="list"></vv-aside>
</div>
//js
//组件形式
Vue.component('vv-aside', {
props:['list'],
methods:{
handelClick(item){
console.log(item);
}
},
template:'<div>\
<div v-for="item in list" @click="handelClick(item)" :class="{odd:item.odd}">{{item.txt}}</div>\
</div>',
//template:'<div v-for="item in list" @click="handelClick(item)" :class="{odd:item.odd}">{{item.txt}}</div>',错误
});
var vm = new Vue({
el: "#app",
data: {
list: [{
id: 1,
txt: 'javaScript',
odd: true
}, {
id: 2,
txt: 'Vue',
odd: false
}, {
id: 3,
txt: 'React',
odd: true
}]
}
});
рендер пиши вот так
//HTML
<div id="app">
<vv-aside v-bind:list="list"></vv-aside>
</div>
//js
//侧边栏
Vue.component('vv-aside', {
render: function(h) {
var _this = this,
ayy = this.list.map((v) => {
return h('div', {
'class': {
odd: v.odd
},
attrs: {
title: v.txt
},
on: {
click: function() {
return _this.handelClick(v);
}
}
}, v.txt);
});
return h('div', ayy);
},
props: {
list: {
type: Array,
default: () => {
return this.list || [];
}
}
},
methods: {
handelClick: function(item) {
console.log(item, "item");
}
}
});
var vm = new Vue({
el: "#app",
data: {
list: [{
id: 1,
txt: 'javaScript',
odd: true
}, {
id: 2,
txt: 'Vue',
odd: false
}, {
id: 3,
txt: 'React',
odd: true
}]
}
});
v-model
предыдущее написание
//HTML
<div id="app">
<vv-models v-model="txt" :txt="txt"></vv-models>
</div>
//js
//input
Vue.component('vv-models', {
props: ['txt'],
template: '<div>\
<p>看官你输入的是:{{txtcout}}</p>\
<input v-model="txtcout" type="text" />\
</div>',
computed: {
txtcout:{
get(){
return this.txt;
},
set(val){
this.$emit('input', val);
}
}
}
});
var vm = new Vue({
el: "#app",
data: {
txt: '',
}
});
рендер пиши вот так
//HTML
<div id="app">
<vv-models v-model="txt" :txt="txt"></vv-models>
</div>
//js
//input
Vue.component('vv-models', {
props: {
txt: {
type: String,
default: ''
}
},
render: function(h) {
var self=this;
return h('div',[h('p','你猜我输入的是啥:'+this.txt),h('input',{
on:{
input(event){
self.$emit('input', event.target.value);
}
}
})] );
},
});
var vm = new Vue({
el: "#app",
data: {
txt: '',
}
});
Суммировать
Функция рендеринга использует все программные возможности JavaScript, что имеет абсолютное преимущество в производительности, редактор просто анализирует его. Что касается фактического проекта, способ рендеринга, который вы выберете, по-прежнему зависит от вашего проекта и реальной ситуации.