惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

NISL@THU
NISL@THU
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
D
Darknet – Hacking Tools, Hacker News & Cyber Security
阮一峰的网络日志
阮一峰的网络日志
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
WordPress大学
WordPress大学
IT之家
IT之家
Cyberwarzone
Cyberwarzone
博客园_首页
博客园 - 聂微东
V
Visual Studio Blog
Cisco Talos Blog
Cisco Talos Blog
V
Vulnerabilities – Threatpost
Google DeepMind News
Google DeepMind News
Schneier on Security
Schneier on Security
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
The Hacker News
The Hacker News
雷峰网
雷峰网
Last Week in AI
Last Week in AI
Spread Privacy
Spread Privacy
L
Lohrmann on Cybersecurity
O
OpenAI News
人人都是产品经理
人人都是产品经理
AWS News Blog
AWS News Blog
小众软件
小众软件
T
Tailwind CSS Blog
The Cloudflare Blog
L
LINUX DO - 最新话题
有赞技术团队
有赞技术团队
Know Your Adversary
Know Your Adversary
The GitHub Blog
The GitHub Blog
L
LINUX DO - 热门话题
Y
Y Combinator Blog
Stack Overflow Blog
Stack Overflow Blog
B
Blog
MyScale Blog
MyScale Blog
S
SegmentFault 最新的问题
S
Schneier on Security
The Last Watchdog
The Last Watchdog
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Security Archives - TechRepublic
Security Archives - TechRepublic
大猫的无限游戏
大猫的无限游戏
罗磊的独立博客
Blog — PlanetScale
Blog — PlanetScale
博客园 - Franky
I
InfoQ
P
Proofpoint News Feed
量子位
S
Security @ Cisco Blogs

博客园 - zhouyu

shardingsphere实现按月分表 Vue3手册译稿 - 深入组件 - 插槽 vscode Vue3 多根节点语法检验错误fix Vue3手册译稿 - 深入组件 - 非prop属性 Vue3手册译稿 - 深入组件 - pros Vue3手册译稿 - 深入组件 - 组件注册 Vue3手册译稿 - 基础 - 组件基础 Vue3手册译稿 - 基础 - 表单输入绑定 Vue3手册译稿 - 基础 - 事件处理 Vue3手册译稿 - 基础 - 列表渲染 Vue3手册译稿 - 基础 - 条件渲染 Vue3手册译稿 - 基础 - Class和Style绑定 Vue3手册译稿 - 基础 - 计算属性及监听器 Vue3手册译稿 - 基础 - Data属性及方法 Vue3手册译稿 - 基础 - 模板语法 Vue3手册译稿 - 基础 - 应用&组件实例 Vue3手册译稿 - 基础 - 介绍 Vue3手册译稿 - 基础 - 安装 元旦三天假期,实现一个电商退单管理系统【四】-手机客户端实现
Vue3手册译稿 - 深入组件 - 自定义事件
zhouyu · 2021-03-15 · via 博客园 - zhouyu

本章节需要掌握组件基础
emit我译成发射,觉得发射这个词比较形象的形容将子组件事件发射出来的一个动作。

事件名

像组件和props,事件名也会进行自动转换,如果你在子组件里发射一个驼峰命名的事件,你就可以在父组件中添加一个短横线分隔的监听:

this.$emit('myEvent')
<my-component @my-event="doSomething"></my-component>

因为有props情形存在,模板内DOM议使用短横线分隔命名方式。如果你使用字符串模板,则不存在这个限制。

自定义事件定义

Vue School自定义事件视频教程

自定义事件发射(请子组件传递到父组件)可以通过emits选项:

app.component('custom-form', {
  emits: ['inFocus', 'submit']
})

当在emits中定义了一个原生事件(如click)时,组件事件将会代替原生事件监听。

提示
推荐定义所有已发射的事件,以便记录组件是如何工作的

验证已射事件

prop类型验证一样,一个已发射事件如果通过对象语法而不是数组语法,也可以被验证。
添加一个验证,事件会分配一个函数来接收参数,并传递给$emit调用,返回一个布尔值来确认事件是否有效。

app.component('custom-form', {
  emits: {
    // 无验证
    click: null,

    // 验证提交事件
    submit: ({ email, password }) => {
      if (email && password) {
        return true
      } else {
        console.warn('不合法的 submit 事件加载!')
        return false
      }
    }
  },
  methods: {
    submitForm() {
      this.$emit('submit', { email, password })
    }
  }
})

v-model参数

默认组件的v-model使用modelValue作为prop和update:modelValue作为事件。我们可以传递一个参数给v-model修改这些名称:

<my-component v-model:title="bookTitle"></my-component>
app.component('my-component', {
  props: {
    title: String
  },
  emits: ['update:title'],
  template: `
    <input
      type="text"
      :value="title"
      @input="$emit('update:title', $event.target.value)">
  `
})

在这个案例中,子组件会同步接收titleprop,发射update:title事件:

app.component('my-component', {
  props: {
    title: String
  },
  emits: ['update:title'],
  template: `
    <input
      type="text"
      :value="title"
      @input="$emit('update:title', $event.target.value)">
  `
})
<my-component v-model:title="bookTitle"></my-component>

v-model绑定

正如前面所学习v-model参数,我们可以为同一个组件实例添加多个v-model参数。
每个v-model可以与不同的prop相同步,组件不需要额外的选项:

<user-name
  v-model:first-name="firstName"
  v-model:last-name="lastName"
></user-name>
app.component('user-name', {
  props: {
    firstName: String,
    lastName: String
  },
  emits: ['update:firstName', 'update:lastName'],
  template: `
    <input
      type="text"
      :value="firstName"
      @input="$emit('update:firstName', $event.target.value)">

    <input
      type="text"
      :value="lastName"
      @input="$emit('update:lastName', $event.target.value)">
  `
})

我们来写一个完整点的例子,实现一个区号-座机输入组件,结果如下图:
image

代码如下:

<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>component v-model</title>
	<script src="https://unpkg.com/vue@next"></script>
   </head>
   <body>
		<div id="app">
			<tel-input v-model:tel-number="telNumber" v-model:area-number="areaNumber"></tel-input>
			<p>
				{{areaNumber}}-{{telNumber}}
			</p>
		</div>
   </body>
   <script type="text/javascript">
	const data_and_methods = {
		data() {
			return {
				telNumber: '',
				areaNumber:  ''
			}
		},
		methods: {
			
		}
	}
	const app = Vue.createApp(data_and_methods)
	app.component('tel-input',{
		props: {
			areaNumber:String,
			telNumber:String
		},
		emits: ['update:areaNumber','update:telNumber'],
		template: `
			<input placeholder="区号" type="number" class="area-number" :value="areaNumber" @input="$emit('update:areaNumber',$event.target.value)" />
			-
			<input placeholder="座机号码" type="number" class="tel-number" :value="telNumber" @input="$emit('update:telNumber',$event.target.value)" />
		`
	})
	
	app.mount("#app")
   </script>
   <style type="text/css">
		.area-number {width:60px;}
	</style>
</html>

处理v-model修饰符

在前面我们学习输入绑定时,v-model有一些内置的修饰符如.trim,.number,.lazy等。有些情形,你也想增加一些自定义的修饰符。
让我们来创建一个capitalize修饰符,使用v-model绑定将输入首字母转换为大写。
组件v-model修饰符通过modelModifersprop提供给组件。下面的例子,我们创建了一个含有默认为空对象 的modelModifiersprop组件。
注意在组件created生命周期勾子触发器中,modelModifiersprop包含capitalize且值是true - 当它被设置在v-model绑定v-model.capitalize="myText"

<my-component v-model.capitalize="myText"></my-component>
app.component('my-component', {
  props: {
    modelValue: String,
    modelModifiers: {
      default: () => ({})
    }
  },
  emits: ['update:modelValue'],
  template: `
    <input type="text"
      :value="modelValue"
      @input="$emit('update:modelValue', $event.target.value)">
  `,
  created() {
    console.log(this.modelModifiers) // { capitalize: true }
  }
})

现在我们设置好了prop,我们检测modelModifiers对象的键,然后通过方法处理要发射出去的值。下面我们来把输入框的首字母转换为大写:

<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>component v-model modifiers</title>
	<script src="https://unpkg.com/vue@next"></script>
   </head>
   <body>
		<div id="app">
			<my-component v-model.capitalize="myText"></my-component>
			<p>{{ myText }}</p>
		</div>
   </body>
   <script type="text/javascript">
	const data_and_methods = {
		data() {
			return {
				myText: ''
			}
		}
	}
	const app = Vue.createApp(data_and_methods)
	app.component('my-component',{
		props: {
			modelValue: String,
			modelModifiers: {
				default: () => ({})
			}
		},
		emits: ['update:modelValue'],
		template: `
			<input type="text"
				:value="modelValue"
				@input="emitValue" />
		`,
		methods: {
			emitValue(e){
				let value = e.target.value
				if(this.modelModifiers.capitalize){
					value = value.charAt(0).toUpperCase() + value.slice(1)
				}
				this.$emit('update:modelValue',value)
			}
		},
		created() {
			console.log(this.modelModifiers)
		}
	})
	
	app.mount("#app")
   </script>
</html>

v-model绑定参数,生成的prop名将会是arg+"modelModifiers"

<my-component v-model:description.capitalize="myText"></my-component>
app.component('my-component', {
  props: ['description', 'descriptionModifiers'],
  emits: ['update:description'],
  template: `
    <input type="text"
      :value="description"
      @input="$emit('update:description', $event.target.value)">
  `,
  created() {
    console.log(this.descriptionModifiers) // { capitalize: true }
  }
})