# Vue.js style guide

> 原文：[https://docs.gitlab.com/ee/development/fe_guide/style/vue.html](https://docs.gitlab.com/ee/development/fe_guide/style/vue.html)

*   [Linting](#linting)
*   [Basic Rules](#basic-rules)
*   [Naming](#naming)
*   [Alignment](#alignment)
*   [Quotes](#quotes)
*   [Props](#props)
*   [Data](#data)
*   [Directives](#directives)
*   [Closing tags](#closing-tags)
*   [Component usage within templates](#component-usage-within-templates)
*   [Ordering](#ordering)
*   [`:key`](#key)
*   [Vue and Bootstrap](#vue-and-bootstrap)
*   [The JavaScript/Vue Accord](#the-javascriptvue-accord)

# Vue.js style guide[](#vuejs-style-guide "Permalink")

## Linting[](#linting "Permalink")

我们默认为[eslint-vue-plugin](https://github.com/vuejs/eslint-plugin-vue) ，其`plugin:vue/recommended` . 请检查此[规则](https://github.com/vuejs/eslint-plugin-vue#bulb-rules)以获取更多文档.

## Basic Rules[](#basic-rules "Permalink")

1.  该服务具有自己的文件
2.  商店有自己的文件
3.  使用捆绑文件中的函数实例化 Vue 组件：

    ```
    // bad
    class {
      init() {
        new Component({})
      }
    }

    // good
    document.addEventListener('DOMContentLoaded', () => new Vue({
      el: '#element',
      components: {
        componentName
      },
      render: createElement => createElement('component-name'),
    })); 
    ```

4.  不要将单例用于服务或商店

    ```
    // bad
    class Store {
      constructor() {
        if (!this.prototype.singleton) {
          // do something
        }
      }
    }

    // good
    class Store {
      constructor() {
        // do something
      }
    } 
    ```

5.  将`.vue`用于 Vue 模板. 不要在 HAML 中使用`%template` .

## Naming[](#naming "Permalink")

1.  **扩展名** ：对 Vue 组件使用`.vue`扩展名. 不要将`.js`用作文件扩展名（ [＃34371](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/34371) ）.
2.  **参考命名** ：将 PascalCase 用于其实例：

    ```
    // bad
    import cardBoard from 'cardBoard.vue'

    components: {
      cardBoard,
    };

    // good
    import CardBoard from 'cardBoard.vue'

    components: {
      CardBoard,
    }; 
    ```

3.  **道具命名：**避免使用 DOM 组件道具名称.
4.  **道具命名：**使用 kebab-case 代替 camelCase 在模板中提供道具.

    ```
    // bad
    <component class="btn">

    // good
    <component css-class="btn">

    // bad
    <component myProp="prop" />

    // good
    <component my-prop="prop" /> 
    ```

## Alignment[](#alignment "Permalink")

1.  对于模板方法，请遵循以下对齐方式：

    1.  具有多个属性，所有属性都应换行：

        ```
        // bad
        <component v-if="bar"
            param="baz" />

        <button class="btn">Click me</button>

        // good
        <component
          v-if="bar"
          param="baz"
        />

        <button class="btn">
          Click me
        </button> 
        ```

    2.  如果只有一个属性，则标签可以是内联的：

        ```
        // good
          <component bar="bar" />

        // good
          <component
            bar="bar"
            />

        // bad
         <component
            bar="bar" /> 
        ```

## Quotes[](#quotes "Permalink")

1.  对于所有其他 JS，请始终在模板内使用双引号`"`在模板内使用单引号`'` .

    ```
    // bad
    template: `
      <button :class='style'>Button</button>
    `

    // good
    template: `
      <button :class="style">Button</button>
    ` 
    ```

## Props[](#props "Permalink")

1.  道具应声明为对象

    ```
    // bad
    props: ['foo']

    // good
    props: {
      foo: {
        type: String,
        required: false,
        default: 'bar'
      }
    } 
    ```

2.  声明道具时应始终提供必需的钥匙

    ```
    // bad
    props: {
      foo: {
        type: String,
      }
    }

    // good
    props: {
      foo: {
        type: String,
        required: false,
        default: 'bar'
      }
    } 
    ```

3.  如果不需要道具，则应提供默认密钥. *注意：*在某些情况下，我们需要检查属性的存在. 在这些上，不应提供默认密钥.

    ```
    // good
    props: {
      foo: {
        type: String,
        required: false,
      }
    }

    // good
    props: {
      foo: {
        type: String,
        required: false,
        default: 'bar'
      }
    }

    // good
    props: {
      foo: {
        type: String,
        required: true
      }
    } 
    ```

## Data[](#data "Permalink")

1.  `data`方法应始终是一个函数

    ```
    // bad
    data: {
      foo: 'foo'
    }

    // good
    data() {
      return {
        foo: 'foo'
      };
    } 
    ```

## Directives[](#directives "Permalink")

1.  速记`@`优先于`v-on`

    ```
    // bad
    <component v-on:click="eventHandler"/>

    // good
    <component @click="eventHandler"/> 
    ```

2.  速记`:`优于`v-bind`

    ```
    // bad
    <component v-bind:class="btn"/>

    // good
    <component :class="btn"/> 
    ```

3.  Shorthand `#` is preferable over `v-slot`

    ```
    // bad
    <template v-slot:header></template>

    // good
    <template #header></template> 
    ```

## Closing tags[](#closing-tags "Permalink")

1.  首选自闭合组件标签

    ```
    // bad
    <component></component>

    // good
    <component /> 
    ```

## Component usage within templates[](#component-usage-within-templates "Permalink")

1.  在模板中使用组件时，将组件的 kebab 命名的名称优先于其他样式

    ```
    // bad
    <MyComponent />

    // good
    <my-component /> 
    ```

## Ordering[](#ordering "Permalink")

1.  `.vue`文件中的标记顺序

    ```
    <script>
      // ...
    </script>

    <template>
      // ...
    </template>

    // We don't use scoped styles but there are few instances of this
    <style>
      // ...
    </style> 
    ```

2.  Vue 组件中[的属性](https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/order-in-components.md) ：检查[组件 rule 中的属性顺序](https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/order-in-components.md) .

## `:key`[](#key "Permalink")

使用`v-for`您需要为每个项目提供*唯一的* `:key`属性.

1.  如果要迭代的数组元素具有唯一的`id` ，则建议使用它：

    ```
    <div
      v-for="item in items"
      :key="item.id"
    >
      <!-- content -->
    </div> 
    ```

2.  当要迭代的元素没有唯一 ID 时，可以将数组索引用作`:key`属性

    ```
    <div
      v-for="(item, index) in items"
      :key="index"
    >
      <!-- content -->
    </div> 
    ```

3.  当将`v-for`与`template`并且有多个子元素时， `:key`值必须唯一. 建议使用`kebab-case`名称空间.

    ```
    <template v-for="(item, index) in items">
      <span :key="`span-${index}`"></span>
      <button :key="`button-${index}`"></button>
    </template> 
    ```

4.  处理嵌套`v-for`使用与上述相同的准则.

    ```
    <div
      v-for="item in items"
      :key="item.id"
    >
      <span
        v-for="element in array"
        :key="element.id"
      >
        <!-- content -->
      </span>
    </div> 
    ```

有用的链接：

1.  [`key`](https://vuejs.org/v2/guide/list.html#key)
2.  [Vue Style Guide: Keyed v-for](https://vuejs.org/v2/style-guide/#Keyed-v-for-essential)

## Vue and Bootstrap[](#vue-and-bootstrap "Permalink")

1.  工具提示：请勿依赖 Vue 组件的`has-tooltip`类名称

    ```
    // bad
    <span
      class="has-tooltip"
      title="Some tooltip text">
      Text
    </span>

    // good
    <span
      v-tooltip
      title="Some tooltip text">
      Text
    </span> 
    ```

2.  工具提示：使用工具提示时，请包含工具提示指令`./app/assets/javascripts/vue_shared/directives/tooltip.js`

3.  不要更改`data-original-title` .

    ```
    // bad
    <span data-original-title="tooltip text">Foo</span>

    // good
    <span title="tooltip text">Foo</span>

    $('span').tooltip('_fixTitle'); 
    ```

## The JavaScript/Vue Accord[](#the-javascriptvue-accord "Permalink")

该协议的目的是确保我们都在同一页面上.

1.  编写 Vue 时，您可能无法在应用程序中使用 jQuery.
    1.  如果您需要从 DOM 抓取数据，则可以在引导应用程序以使用`dataset`抓取数据属性时查询 DOM 1 次. 您可以在没有 jQuery 的情况下执行此操作.
    2.  您可以[按照 docs 中的此示例](https://vuejs.org/v2/examples/select2.html)在 Vue.js 中使用 jQuery 依赖关系.
    3.  如果需要在 Vue 应用程序内部侦听外部 jQuery 事件，则可以使用 jQuery 事件侦听器.
    4.  我们将避免在不需要时添加新的 jQuery 事件. 与其添加新的 jQuery 事件，不如看看[执行相同任务的不同方法](https://vuejs.org/v2/api/#vm-emit) .
2.  您可以一次引导`window`对象，同时引导您的应用程序以获取应用程序特定的数据（例如， `scrollTo`可以随时访问）. 在应用程序引导期间执行此访问.
3.  您可能会临时需要立即但不符合我们标准的代码来编写技术债，以备以后重构. 维护人员首先要对技术债务保持满意. 应该为该技术债务创建一个问题，以便对其进行进一步评估和讨论. 在接下来的几个月中，您应该解决该技术债务，其优先级由维护者确定.
4.  在产生技术债务时，您必须事先为该代码编写测试，并且这些测试可能不会被重写. 例如，将 jQuery 测试重写为 Vue 测试.
5.  您可以选择将 VueX 用作集中式状态管理. 如果选择不使用 VueX，则必须使用可以在[Vue.js 文档中](https://vuejs.org/v2/guide/state-management.html#Simple-State-Management-from-Scratch)找到的*存储模式* .
6.  选择集中式状态管理解决方案后，必须将其用于整个应用程序. 即不要混淆并匹配您的状态管理解决方案.