要记住的Vue功能

我们在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采用三个参数:

  1. 要创建的项目。这不仅可以是HTML标记,还可以是组件名称。此参数是必需的;
  2. 有数据的对象。它可能包含类,样式,组件的输入参数,处理事件的方法等的列表。有关更多详细信息,请参见文档。可选参数;
  3. 子虚拟节点。它可以是字符串或数组。在上面的示例中,这是$ 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目录中是合乎逻辑的。

// mixin.js
export default  {
  data () {
    return {
      showEditor: false,
      editor: null
    }
  },
  
  methods: {
    initEditor () {
      this.showEditor = true
      this.editor = new Editor(this.elementName)
    }
  }
}

// TextElement.vue
import mixin from './mixins/mixin'

export default  {
  name: 'TextElement',

  mixins: [mixin]  //  

  data () {
    return {
      elementName: 'Text',
    }
  },
}

// ButtonElement.vue
import mixin from './mixins/mixin'

export default  {
  name: 'ButtonElement',

  mixins: [mixin]

  data () {
    return {
      elementName: 'Button'
    }
  }
}

从示例中可以看到,几乎所有逻辑都迁移到了mixin。在组件内部使用杂质时,它们的所有选项都会合并。在组件中,可以自由调用initEditor()方法,相反,在杂质中,此处使用组件的elementName。在这种情况下,数据对象将被递归合并,并且组件的属性将具有优先权。

因此,杂质的好处显而易见-这是代码重用。但是有一个减号。这个例子是综合的,只有两行。真正的组件(例如Ptah中使用的组件)可以用几百行代码编写。对于没有编写此代码的人来说,这并不总是很清楚,尤其是如果他忽略了向组件中添加mixins。不幸的是,摆脱这个减号是行不通的。我可以建议两件事:在JSDoc中描述组件的操作,并为杂质的属性使用特殊名称(例如,您可以添加前缀,您需要事先与团队同意)。

提供/注入


这对选项始终一起使用,并允许您将数据从父组件传输到其后代的整个层次结构。这些选项主要用于编写插件,官方文档不建议在应用程序中使用它们。在应用程序中,组件之间的通信在Vuex上构建得很好。但是,此功能仍然值得关注。

怎么运行的?


首先,我们需要在父组件中定义数据,然后将其传递给它的后代。

// Parent.vue        
export default {
  provide: {
   device: 'is-desktop'
  }
}

现在,需要将传输的数据嵌入子组件中。

// Child.vue    
export default {
  inject: ['device'],

  created () {
   console.log(this.device) // => "is-desktop"
  }
}

从示例中可以看到,一切都很简单。但是要注意一个重要的减号-默认情况下,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')即可

All Articles