vue深入了解组件(一)

本文详细探讨了Vue组件的注册,包括全局注册、局部注册和基础组件自动化注册。接着介绍了Prop的类型、传递方式和验证,强调了Prop的单向数据流原则。此外,文章还讨论了自定义事件,如v-model、.sync修饰符和原生事件的绑定。通过这些,读者可以深入理解Vue组件的工作原理。
摘要由CSDN通过智能技术生成

一. 组件注册

以下代码使用Babel 和 webpack 的模块系统

1.通过vue.component 全局注册
  • 全局注册的组件可以用在任何新建的 vue根实例(new Vue)模板中。
  • 全局组件在各自内部也都可以相互使用

main.js

import componentA from './componentA
Vue.component('组件名', componentA)

当你有多个全局组件需要注册时,可以这样写
新建一个configurations.js

import demoA drom './demo1';
import demoB drom './demo1';
import demoC drom './demo1';
function deploy(Vue) {
	Vue.component('demoA', demoA);
	Vue.component('demoB', demoA);
	Vue.component('demoC', demoA);
}
export default deploy;

main.js

...
import deploy from './configurations';
Vue.use(deploy )
2.局部注册
  • 全局注册的缺点: 如果你使用一个像 webpack 这样的构建系统,全局注册所有的组件意味着即便你已经不再使用一个组件了,它仍然会被包含在你最终的构建结果中。
  • 局部注册的组件在其子组件中不可用
...
import componentA from "./componetA;
export default {
	data() {
		return {};
	},
	components: { componentA },
}
3.基础组件的自动化全局注册
  • 有时组件只是包裹了一个输入框或按钮之类的元素,是相对通用的基础组件。基础组件如果使用局部注册,会非常麻烦。
  • 推荐使用require.context 只全局注册这些非常通用的基础组件
  • 例子:main.js为应用入口文件,组件使用PascalCase命名法
    main.js
import upperFirst from 'lodash/upperFirst'
import camelCase from 'lodash/camelCase'
// 这两个方法用来实现PascalCase命名
const requireComponent = required.context(
	// 基础组件的相对路径
	'./basecomponent',
	// 是否查询子目录
	false,
	// 匹配文件目录的正则
	/BaseA+\.(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
  )	
  )
 )
})

二. Prop

1.Prop的类型
  • 基础例子
props: ['a', 'b', 'c']
  • 如果你希望每个prop都有指定的类型,可以这么写
props: {
	a: String,
	b: Number,
	c: Boolean
}

在它们遇到错误的类型时会从浏览器的 JavaScript 控制台提示用户

2. 传递静态或动态 Prop
  • 传递静态的 prop
<son-component title="My journey with Vue"></son-component>
  • 传递动态的 prop
<son-component v-bind:title="My journey with Vue"></son-component>
3. 传入一个对象的所有属性
  • 当你想把一个对象的所有属性作为 prop 传入时 你可以使用不带参数的 v-bind (取代 v-bind:prop-name)
    例子:给定一个对象 postMsg
postMsg: {
	title: 'test',
	name: 'psot'
}

下面的模板

<son-component v-bind="postMsg"></son-component>

等同于

<son-component 
v-bind:title="postMsg.title"
v-bind:name="postMsg.name"
>
</son-component>

注意:上面两种写法子组件都要使用props接收数据

4. prop的单向数据流

官网原话:所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。

  • 不应该在一个子组件内部改变 prop,如果你这样做了,Vue 会在浏览器的控制台中发出警告
  • 这里有两种常见的试图改变一个 prop 的情形:
  1. 子组件接下来希望将prop数据作为一个本地数据来使用,此时最好定义一个本地的 data 属性并将这个 prop 用作其初始值
props: ['a', 'b'],
data() {
	return {
		sonData: this.a;
	}
}
  1. 这个 prop 以一种原始的值传入且需要进行转换,此时 最好使用这个 prop 的值来定义一个计算属性
props: ['size'],
compouted: {
	twoBei() {
		return this.size.trim().toLowerCase();
	}
}
5. prop的验证

给prop指定类型,或者一些特定需求。这在开发一个会被别人用到的组件时尤其有帮助。
官网例子

export default {
	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
      		}
    	}
	}
}

关于类型检查
type 可以是下列原生构造函数中的一个:

  • String
  • Number
  • Boolean
  • Array
  • Object
  • Date
  • Function
  • Symbol
    你也可以使用自定义构造函数,此时 通过 instanceof 来进行检查确认
6. 非 Prop 的特性
  • 非 prop 特性是指传向一个组件,但是该组件并没有相应 prop 定义的特性 ($attrs)
  1. 替换/合并已有的特性
  • 现有一个子组件 base-input, 模板如下
<input type="date" class="form-control">
  • 调用 base-input 时,添加了一个类名并传入一个type属性
<base-input
	class="style1"
	type="text"
> </base-input>

备注:对于绝大多数特性来说,从外部提供给组件的值会替换掉组件内部设置好的值。class和style除外,这两个属性的值会合并,而type属性会变成 text。

  1. 禁用特性继承
  • 当你不希望组件的根元素继承特性,你可以在组件的选项中设置 inheritAttrs: false
  • 当设置inheritAttrs: true(默认)时,子组件的顶层标签元素中会渲染出父组件传递过来的属性
  • 当设置inheritAttrs: false时,子组件的顶层标签元素中不会渲染出父组件传递过来的属性
  • inheritAttrs为true或者false 都不会影响 $attrs
  • inheritAttrs: false 选项不会影响 style 和 class 的绑定。
    链接

三. 自定义事件

1. 在组件上使用v-mdel
  • 在html标签上使用 v-mdel
<input v-model="mydata">

等价于

<input :value="mydata" @input="value = $enent.target.value">

$enent.target.value指input输入框的值

  • 在组件上使用v-mdel

自定义的input组件

<template>
    <input :value="value" @input="$emit('input', $event.target.value)">
</template>

<script>
export default {
 props: ['value'],
  data() {
    return {};
  },
};
</script>

调用组件时

<custom-input
  v-model="searchText"
></custom-input>

或者

<custom-input
  :value="searchText"
  @:input="searchText = $event"
></custom-input>
2. 自定义组件的 v-model

一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件

  • 注意:单选框复选框 等类型的输入控件可能会将 value 特性用于不同的目的
  • 解决方法:可以在定义组件时使用model 选项来避免这样的冲突:
    自定义单选框组件 base-checkbox
<template> 
	<input
		type="checkbox",
		:checked="checked",
		@change="$emit("change", $event.target.checked)"
	>
</template>
export default {
	name: "base-checkbox",
	model: {
		prop: "checked",
		event: "change"
	},
	props: {
		checked: Boolean
	},
}

调用组件时

<base-checkbox v-model="lovingVue"> </base-checkbox>

注意: lovingVue的值会传如 名为cheched 的prop,base-checkbox组件的checked发生变化触发change事件时,lovingVue会更新。

3. 将原生事件绑定到组件
  1. 在一个组件的根元素上直接监听一个原生事件,使用 v-on的.native修饰符
  • .native修饰符适用于 组件的根元素支持所监听的原生事件的情况
<base-input @focus.native="onFoucus"> </base-input>

如果base-input组件的根元素不是 input,focus事件就不会触发

  1. $listeners 属性
  • $listeners是一个对象,其中包含了作用在这个组件上的所有监听器
{
	focus: (event)=>{},
	input: (value)=>{},
	......
}
  • v-on=" l i s t e n e r s &quot; 效 果 和 v − b i n d = &quot; listeners&quot; 效果和 v-bind=&quot; listeners"vbind="attrs"相似,他可以将所有的事件监听器指向组件的某个特定的子元素
  1. 结合 $listeners 和计算属性,创建一个可以配合 v-model 工作的基础输入框组件
<template> 
	<label>
      {{title}}
      <input v-bind="$attrs" :value="value" v-on="inputListeners">
    </label>
<template/>
export default {
	inheritAttrs: false,  // 禁用特性继承
	props: ["label", "value"],
	computed: {
		inputListeners() {
			return {
				Object.assign{
					{},
					this.$listeners,
					{
						// 由于调用组件时传入了input事件,此时需要覆写input监听器的行为
						input: (event) => { this.$emit("input", event.target.value) }
					}
				}
			}
		}
	}
}

现在 base-input 组件是一个完全透明的包裹器了,也就是说它可以完全像一个普通的 元素一样使用了:所有跟它相同的特性和监听器的都可以工作。

4. .sync 修饰符
  • 使用场景: 当需要对一个 prop 进行“双向绑定”,我们推荐使用 update:myPropName 的模式触发事件

在一个包含 title prop 的假设的组件中,我们可以用以下方法表达对其赋新值的意图

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

父组件可以监听 update:title 事件并根据需要更新一个本地的数据属性

<text-document
  :title="doc.title"
  @update:title="doc.title = $event"
></text-document>

.sync 修饰符的写法

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

注意:

  • :title.sync的写法不能和表达式一起使用(例如 :title.sync=“doc.title + 1”)
  • v-bind.sync = "{ a: 1 }"这种写法也不支持,只支持绑定一个data的属性
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值