【Vue】 使用中的注意事项(深入了解组件):10.组件注册 11.Prop 12.自定义事件名

组件注册

组件名
当直接在 DOM 中使用一个组件 (而不是在字符串模板或单文件组件) 的时候,我们强烈推荐遵循 W3C 规范中的自定义组件名 (字母全小写且必须包含一个连字符例如:vue-my-component)

DOM中使用:kebab-case(短横线分隔)
定义:kebab-case 使用:kebab-case (短横线分隔)
定义:PascalCase 使用:PascalCase(驼峰命名) 和 kebab-case

全局注册:

Vue.component('my-component-name', {
  // ... 选项 ...
})

全局注册的。它们可以在注册之后可以用在任何新创建的 Vue 根实例 (new Vue) 的模板中。始终会包含在最终构建的结果中。这造成了用户下载的 JavaScript 的无谓的增加。

局部注册

import ComponentA from './ComponentA.vue'

export default {
  components: {
    ComponentA  //将导入的组件映射为组件,然后才可用注意在 ES2015+ 中,
               //在对象中放一个类似 ComponentA 的变量名其实是 ComponentA: ComponentA 的缩写
  },
  // ...
}

基础组件的自动化全局注册
可能你的许多组件只是包裹了一个输入框或按钮之类的元素,是相对通用的。我们有时候会把它们称为基础组件,它们会在各个组件中被频繁的用到。所以会导致很多组件里都会有一个包含基础组件的长列表

在应用入口文件 (比如 src/main.js) 中全局导入基础组件的示例代码:

import Vue from 'vue'
import upperFirst from 'lodash/upperFirst'
import camelCase from 'lodash/camelCase'

const requireComponent = require.context(
  // 其组件目录的相对路径
  './components',
  // 是否查询其子目录
  false,
  // 匹配基础组件文件名的正则表达式
  /Base[A-Z]\w+\.(vue|js)$/
)

requireComponent.keys().forEach(fileName => {
  // 获取组件配置
  const componentConfig = requireComponent(fileName)

  // 获取组件的 PascalCase 命名
  const componentName = upperFirst(
    camelCase(
      // 获取和目录深度无关的文件名
      fileName
        .split('/')
        .pop()
        .replace(/\.\w+$/, '')
    )
  )

  // 全局注册组件
  Vue.component(
    componentName,
    // 如果这个组件选项是通过 `export default` 导出的,
    // 那么就会优先使用 `.default`,
    // 否则回退到使用模块的根。
    componentConfig.default || componentConfig
  )
})

全局注册的行为必须在根 Vue 实例 (通过 new Vue) 创建之前发生




Prop

命名
HTML 中的特性名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名
如果你使用字符串模板(即在js中使用时),那么这个限制就不存在了。

类型
以对象形式列出 的prop,这些属性的名称和值分别是 prop 各自的名称和类型

传递静态或动态 Prop

<!-- 即便传入的值静态的,我们仍然需要 `v-bind` 来告诉 Vue -->

传入一个数字
<!-- 即便 `42` 是静态的,我们仍然需要 `v-bind` 来告诉 Vue -->
<!-- 这是一个 JavaScript 表达式而不是一个字符串。-->
<blog-post v-bind:likes="42"></blog-post>

传入一个布尔值
<!-- 包含该 prop 没有值的情况在内,都意味着 `true`-->
<blog-post is-published></blog-post>

传入一个对象的所有属性
下面的模板:
<blog-post v-bind="post"></blog-post>
等价于:
<blog-post
  v-bind:id="post.id"
  v-bind:title="post.title"
></blog-post>

单向数据流
注意在 JavaScript 中对象和数组是通过引用传入的,所以对于一个数组或对象类型的 prop 来说,在子组件中改变这个对象或数组本身将会影响到父组件的状态
每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。

1.这个 prop 用来传递一个初始值;这个子组件接下来希望将其作为一个本地的 prop 数据来使用。在这种情况下,最好定义一个本地的 data 属性并将这个 prop 用作其初始值

2.这个 prop 以一种原始的值传入且需要进行转换。在这种情况下,最好使用这个 prop 的值来定义一个计算属性

Prop 验证

  props: {
    // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
    propA: Number,
    // 多个可能的类型
    propB: [String, Number],
    // 必填的字符串
    propC: {
      type: String,
      required: true
    },
    // 带有默认值的数字
    propD: {
      type: Number,
      default: 100
    },
    // 带有默认值的对象
    propE: {
      type: Object,
      // 对象或数组默认值必须从一个工厂函数获取
      default: function () {
        return { message: 'hello' }
      }
    },
    // 自定义验证函数
    propF: {
      validator: function (value) {
        // 这个值必须匹配下列字符串中的一个
        return ['success', 'warning', 'danger'].indexOf(value) !== -1
      }
    }
  }

注意那些 prop 会在一个组件实例创建之前进行验证,所以实例的属性 (如 data、computed 等) 在 default 或 validator 函数中是不可用的。

type 还可以是一个自定义的构造函数,并且Vue内部通过 instanceof 来进行检查确认。

非 Prop 的特性
一个非 prop 特性是指传向一个组件,但是该组件并没有相应 prop 定义的特性。
组件可以接受任意的特性,而这些特性会被添加到这个组件的根元素上。

替换/合并已有的特性
class 和 style 特性会稍微智能一些,他会把从父级传入的和模板内置的,即两边的值会被合并起来,从而得到最终的值

禁用特性继承
有了 inheritAttrs: false$attrs,你就可以手动决定这些特性会被赋予哪个元素。在撰写基础组件的时候是常会用到的:

Vue.component('base-input', {
  inheritAttrs: false,  //禁用特性继承
  props: ['label', 'value'],
  template: `
    <label>
      {{ label }}
      <input
        v-bind="$attrs"  //外界传入的属性会被作用在input上而非根元素
        v-bind:value="value"
        v-on:input="$emit('input', $event.target.value)"
      >
    </label>
  `
})



自定义事件

事件名
v-on 事件监听器在 DOM 模板中会被自动转换为全小写 (因为 HTML 是大小写不敏感的),所以 v-on:myEvent 将会变成 v-on:myevent——导致 myEvent 不可能被监听到。
推荐始终使用 kebab-case 的事件名

自定义组件的 v-model
组件的model选项可以用来自定义地设置v-model传入的属性值和触发时的事件
注意你仍然需要在组件的 props 选项里声明 model选项中自定义的v-model传入的属性名这个 prop。

将原生事件绑定到组件的特定元素
Vue 提供了一个 $listeners 属性,它是一个对象,里面包含了作用在这个组件上的所有监听器。例如:

{
  focus: function (event) { /* ... */ }
  input: function (value) { /* ... */ },
}

有了这个 $listeners 属性,你就可以配合 v-on="$listeners" 将所有的事件监听器指向这个组件的某个特定的子元素。对于类似 <input> 的你希望它也可以配合 v-model 工作的组件来说,为这些监听器创建一个类似下述 inputListeners 的计算属性通常是非常有用的:

Vue.component('base-input', {
  inheritAttrs: false,
  props: ['label', 'value'],
  computed: {
    inputListeners: function () {
      var vm = this
      // `Object.assign` 将所有的对象合并为一个新对象
      return Object.assign({},
        // 我们从父级添加所有的监听器
        this.$listeners,
        // 然后我们添加自定义监听器,
        // 或覆写一些监听器的行为
        {
          // 这里确保组件配合 `v-model` 的工作
          input: function (event) {
            vm.$emit('input', event.target.value)
          }
        }
      )
    }
  },
  template: `
    <label>
      {{ label }}
      <input
        v-bind="$attrs"
        v-bind:value="value"
        v-on="inputListeners"
      >
    </label>
  `
})

.sync 修饰符
当子组件想要改变父组件中传来的数据时

子组件:
this.$emit('update:title', newTitle)

然后父组件可以监听那个事件并根据需要更新一个本地的数据属性。例如:

父组件
<text-document
  v-bind:title="doc.title"
  v-on:update:title="doc.title = $event"
></text-document>

为了方便起见,我们为这种模式提供一个缩写,即 .sync 修饰符:

父组件的简写
<text-document v-bind:title.sync="doc.title"></text-document>

注意带有 .sync 修饰符的 v-bind 不能和表达式一起使用 (例如 v-bind:title.sync=”doc.title + ‘!’” 是无效的)。取而代之的是,你只能提供你想要绑定的属性名

doc是一个对象时

<text-document v-bind.sync="doc"></text-document>

这样会把 doc 对象中的每一个属性 (如 title) 都作为一个独立的 prop 传进去,然后各自添加用于更新的 v-on 监听器。

v-bind.sync 用在一个字面量的对象上,例如 v-bind.sync=”{ title: doc.title }”,是无法正常工作的,因为在解析一个像这样的复杂表达式的时候,有很多边缘情况需要考虑。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值