Javascript

【vue】深入理解组件

本文主要是介绍【vue】深入理解组件,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

1、组件名规范

  • 有两种方式引入,(PascalCase)大驼峰命名法、(kebab-case)短横线命名法;
  • 使用也是上述两种,不过在html中大小写不敏感,会自动解释为小写,kebab-case方式;而在字符串模板或单文件组件.vue文件中两种都可以;
  • 注意:以短横线方式引入的,必须以短横线方式使用;
  • 最终推荐:引入和使用都是用kebab-case命名方式

2、注册组件

  • 全局注册:只有一种方式,Vue.component('component-a',{组件的选项对象}|组件构造器);

组件构造器:作用一:用于给Vue.component()创建注册组件;作用二:用于new 创建组件实例;

// 注册组件,传入一个扩展过的构造器
Vue.component('my-component', Vue.extend({ /* ... */ }))

// 注册组件,传入一个选项对象 (自动调用 Vue.extend)
Vue.component('my-component', { /* ... */ })

例子:const cpn = Vue.extend({
      template:`
      <div>
        <p>我是父组件</p>
      </div>
      `
    })//创建组件构造器
Vue.component('cpn1',cpn);//注册全局组件,
    --------------
构造器的另一个用途:
    import Toast from './Toast'  // 导入组件选项对象
    const toastConstructor = Vue.extend({Toast})//生成组件构造器
    const toast = new toastConstructor()/创建实例,组件对象,生命周期开始
	toast.$mount(document.createElement('div'))/手动挂载(完全替换)到一个新元素上,此时新元素还不在页面上
	/相当于子组件执行完了mounted钩子函数
	document.body.appendChild(toast.$el)/最后将新元素添加到body元素
  • 局部注册:也是一种,思想就是在new创建当前组件实例时将注册的子组件通过组件的选项对象传进去;
  • 局部注册方式一:new Vue({...,components:{component-a:{子组件的选项对象}}})
  • 局部注册方式二:
import ComponentA from './ComponentA.vue'

export default {
  components: {
    ComponentA
  },
  // ...
}

3、快速自动化全局注册

用于自动化全局注册多个公共组件;
使用基于webpack的require.context方法;
全局注册的行为必须在根 Vue 实例 (通过 new Vue) 创建之前发生。
require.context返回值类似: {
“./A.js”: Module,
“./B.js”: Module,
“./C.js”: Module,
“./D.js”: Module
};

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
  )
})

4、props命名规范

  • 引入属性的时候采用camelCase (驼峰命名法) ,就是在js代码中;
  • 传入的时候采用 kebab-case (短横线分隔命名),就是在html代码中。
<blog-post post-title="hello!"></blog-post>

Vue.component('blog-post', {
  // 在 JavaScript 中是 camelCase 的
  props: ['postTitle'],
  template: '<h3>{{ postTitle }}</h3>'
})

5、props使用

  • 数组形式、简单对象形式、有验证需求的对象( prop 会在当前组件实例创建之前进行验证,所以实例的 property (如 data、computed 等) 在 default 或 validator 函数中是不可用的。 )
props: ['title', 'likes', 'isPublished', 'commentIds', 'author'];
props: {
  title: String,
  likes: Number,
  isPublished: Boolean,
  commentIds: Array,
  author: Object,
  callback: Function,
  contactsPromise: Promise // or any other constructor
}
 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
      }
    }
  }
})
  • 采用v-bind时要注意加""; 这是一个 JavaScript 表达式而不是一个字符串。
<blog-post v-bind:comment-ids="[234, 266, 273]"></blog-post>
<blog-post v-bind:comment-ids="post.commentIds"></blog-post>
  • 将一个对象的所有 property 都作为 prop 传入时,使用不带参数的 v-bind
post: {
  id: 1,
  title: 'My Journey with Vue'
}
<blog-post v-bind="post"></blog-post>
==>
<blog-post
  v-bind:id="post.id"
  v-bind:title="post.title"
></blog-post>

6、非props属性会被添加到根元素上,而不是传到组件内;

对于绝大多数 attribute 来说,从外部提供给组件的值会替换掉组件内部设置好的值。庆幸的是,class 和 style attribute 会稍微智能一些,即两边的值会被合并起来,从而得到最终的值:

<bootstrap-date-input data-date-picker="activated"></bootstrap-date-input>
组件内部没有props接收这个属性的话,类似于普通属性 class="actived",
 data-date-picker="activated" 就会自动添加到 <bootstrap-date-input> 的根元素上。
  • 那么就有一个问题:我不想将没有被props接收的属性默认绑到根元素上,想在内部元素标签上自身决定要不要;(style 和 class 的绑定不能改变,还是默认在根元素上)

借助inheritAttrs: false(设置不自动使用外界属性)、v-bind="$attrs"(哪个元素需要外界传的属性就添加这个)

Vue.component('base-input', {
  inheritAttrs: false,//子组件中的属性
  props: ['label', 'value'],
  template: `
    <label>
      {{ label }}
      <input
        v-bind="$attrs"
        v-bind:value="value"
        v-on:input="$emit('input', $event.target.value)"
      >
    </label>
  `
})
----单文件中
export default {
  inheritAttrs: fasle,
  }
使用:
<base-input
  v-model="username"
  required
  placeholder="Enter your username"
></base-input>
----

7、自定义事件名规范

  • 不同于组件和 prop(在html中使用会转为kebab-case 命名),事件名不存在任何自动化的大小写转换,所以发出与监听的事件名需要完全匹配。
  • 始终使用 kebab-case 的事件名;
<my-component v-on:my-event="doSomething"></my-component>
this.$emit('my-event')

8、自定义组件的 v-model

一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件,
但是像单选框、复选框等类型的输入控件可能会将 value attribute 用于不同的目的。
所以在子组件内部不是输入框时,添加model 选项,可以用来避免这样的冲突:

<base-checkbox v-model="lovingVue"></base-checkbox>
==相当于
<base-checkbox :checked="lovingVue" @change="var=>{lovingVue = var}"></base-checkbox>
----子组件如下:
Vue.component('base-checkbox', {
  model: {
    prop: 'checked',
    event: 'change'
  },//用于指定父组件在v-model对应以哪个属性传进来,并通过哪个事件接收
  props: {
    checked: Boolean
  },
  template: `
    <input
      type="checkbox"
      v-bind:checked="checked"
      v-on:change="$emit('change', $event.target.checked)"
    >
  `
})
这篇关于【vue】深入理解组件的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!