我们在Ptah团队决定比一般的SPA走得更远,并尝试使用Vue作为目标网页设计师。现在,我们想分享我们的部分经验。本文主要针对刚开始使用Vue并希望更好地了解其特性和功能的用户。在这里,我想谈一谈框架的某些功能,而新手开发人员常常会忘记这些功能。渲染功能
组件模板是开发人员喜欢Vue的目的之一。它们简单且合乎逻辑,这要归功于该框架的入门门槛低。在90%的情况下,模板语法足以编写逻辑优美的代码。但是,如果剩下的10%不能编写紧凑的组件怎么办?渲染功能将为您提供帮助。让我们使用文档中的示例查看它的含义:Vue.component('anchored-heading', {
render: function (createElement) {
return createElement(
'h' + this.level,
this.$slots.default
)
},
props: {
level: {
type: Number,
required: true
}
}
})
锚定标题
组件接受level属性并绘制标题标签。因此记录<anchored-heading :level="1">, !</anchored-heading>
将转换为<h1>, !</h1>
如果使用标准模板描述了此组件,则它将包含多达6个v-if条件,这些条件描述了不同级别的标题:<h1 v-if="level === 1">
<slot></slot>
</h1>
<h2 v-if="level === 2">
<slot></slot>
</h2>
<h3 v-if="level === 3">
<slot></slot>
</h3>
<h4 v-if="level === 4">
<slot></slot>
</h4>
<h5 v-if="level === 5">
<slot></slot>
</h5>
<h6 v-if="level === 6">
<slot></slot>
</h6>
怎么运行的?
render方法有两个参数。createElement的第一个参数是描述应该创建哪个Vue元素的函数。在社区中,习惯上将createElement缩写为一个字母-h。第二个参数是context,用于访问上下文数据。createElement采用三个参数:- 要创建的项目。这不仅可以是HTML标记,还可以是组件名称。此参数是必需的;
- 有数据的对象。它可能包含类,样式,组件的输入参数,处理事件的方法等的列表。有关更多详细信息,请参见文档。可选参数;
- 子虚拟节点。它可以是字符串或数组。在上面的示例中,这是$ Slots.default。
渲染功能可以在最意外的情况下提供帮助。例如,在Ptah中,我们经常需要使用页面内的样式标签来使某些设计器元素正常工作。但是,Vue禁止在模板组件内部使用此标签。借助一个小的包装器,可以轻松绕过此限制:Vue.component('v-style', {
render: function (h) {
return h('style', this.$slots.default)
}
})
现在,在模板内部,您可以使用v-style而不是style标签。
因此,一旦您开始觉得Vue模板的标准功能还不够,请考虑一下Render函数。乍一看它们看起来很复杂,但是您可以使用JS提供的所有功能。混合蛋白
您是否有几个具有重复代码的类似组件?混合蛋白或杂质将有助于遵守DRY原理-混合蛋白的功能可一次用于多个组件。让我们举个例子。假设我们有2个具有相似逻辑的组件:export default {
name: 'TextElement',
data () {
return {
elementName: 'Text',
showEditor: false,
editor: null
}
},
methods: {
initEditor () {
this.showEditor = true
this.editor = new Editor(this.elementName)
}
}
}
export default {
name: 'ButtonElement',
data () {
return {
elementName: 'Button',
showEditor: false,
editor: null
}
},
methods: {
initEditor () {
this.showEditor = true
this.editor = new Editor(this.elementName)
}
}
}
组件不同,但逻辑相同。为此,您需要创建一个常规的js文件。将其放置在组件旁边的mixins目录中是合乎逻辑的。
export default {
data () {
return {
showEditor: false,
editor: null
}
},
methods: {
initEditor () {
this.showEditor = true
this.editor = new Editor(this.elementName)
}
}
}
import mixin from './mixins/mixin'
export default {
name: 'TextElement',
mixins: [mixin]
data () {
return {
elementName: 'Text',
}
},
}
import mixin from './mixins/mixin'
export default {
name: 'ButtonElement',
mixins: [mixin]
data () {
return {
elementName: 'Button'
}
}
}
从示例中可以看到,几乎所有逻辑都迁移到了mixin。在组件内部使用杂质时,它们的所有选项都会合并。在组件中,可以自由调用initEditor()方法,相反,在杂质中,此处使用组件的elementName。在这种情况下,数据对象将被递归合并,并且组件的属性将具有优先权。因此,杂质的好处显而易见-这是代码重用。但是有一个减号。这个例子是综合的,只有两行。真正的组件(例如Ptah中使用的组件)可以用几百行代码编写。对于没有编写此代码的人来说,这并不总是很清楚,尤其是如果他忽略了向组件中添加mixins。不幸的是,摆脱这个减号是行不通的。我可以建议两件事:在JSDoc中描述组件的操作,并为杂质的属性使用特殊名称(例如,您可以添加前缀,您需要事先与团队同意)。提供/注入
这对选项始终一起使用,并允许您将数据从父组件传输到其后代的整个层次结构。这些选项主要用于编写插件,官方文档不建议在应用程序中使用它们。在应用程序中,组件之间的通信在Vuex上构建得很好。但是,此功能仍然值得关注。怎么运行的?
首先,我们需要在父组件中定义数据,然后将其传递给它的后代。
export default {
provide: {
device: 'is-desktop'
}
}
现在,需要将传输的数据嵌入子组件中。
export default {
inject: ['device'],
created () {
console.log(this.device)
}
}
从示例中可以看到,一切都很简单。但是要注意一个重要的减号-默认情况下,provide / ject捆绑包中的数据不是反应性的!但是,使用Object.defineProperty可以轻松克服此缺点:provide () {
let device = {}
Object.defineProperty(device, 'type', { enumerable: true, get: () => this.device })
return { device }
},
data () {
return {
device: 'is-desktop'
}
}
现在在父级中更改this.device将在后代中更改它。组件元
在某些情况下,事先不知道将在代码中使用哪个组件。考虑我们的编辑器中的示例。任务如下:在FirstScreen的条件部分中,显示Text,Logo,Button元素,然后将SocialIcons添加到这些元素。因此,很明显,我们将拥有一个section组件,该组件将充当元素的容器,并充当元素本身的4个组件。结构大致如下:/ sections
-- FirstScreen.vue
/ elements
-- Text.vue
-- Logo.vue
-- Button.vue
-- SocialIcons.vue
一次将元素的所有组件添加到FirstScreen模板,然后使用条件进行切换是非常不明智的决定。有一个简单而出色的工具可以执行以下任务:<component :is="%componentName%"/>
带有:is属性
的component元素仅写组件的名称。多亏了他,我们的任务才得以解决:<script>
export default {
name: 'FirstScreen',
data () {
return {
elements: [
'Text',
'Logo',
'Button',
],
}
}
}
</script>
<template>
<div class="first-screen">
<component v-for="element in elements" :is="element"/>
</div>
</template>
在elements数组中,我们编写了组件的名称,然后在FirstScreen模板内部的循环中简单地输出了这些组件。现在,为了在我们的部分中添加带有社交网络图标的元素,我们只需要执行this.elements.push('SocialIcons')即可。