vue组件 v-model语法糖

今天学习了:

Prop 是你可以在组件上注册的一些自定义特性。

注意:一个组件默认可以拥有任意数量的 prop,任何值都可以传递给任何 prop

Prop命名风格:

(1)Prop 的命名风格
①PascalCase首字母大写命名即大驼峰法
②camelCase 小驼峰命名法
③kebab-case 短横线分隔命名法

注意:
HTML 中的特性是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时,驼峰命名法的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名

(1)Prop 的命名风格,案例:
vue组件 v-model语法糖_第1张图片

(1)静态Prop
如下所示,你已经知道了可以像这样给 prop 传入一个静态的值
vue组件 v-model语法糖_第2张图片
(2)动态Prop
prop 可以通过 v-bind 动态赋值,对上述案例稍作修改
vue组件 v-model语法糖_第3张图片

props传值格式:

这里介绍下props传值时的细节点
props传值格式:props传值时,如果属性添加了:则会将后面的属性值理解为表单式,否则将会理解为字符串
vue组件 v-model语法糖_第4张图片

组件参数props校验:

Prop类型:
如果希望每个 prop 都有指定的值类型,可以以对象形式列出 prop,这些属性的名称和值分别是 prop 各自的名称和类型,如下所示:
vue组件 v-model语法糖_第5张图片
组件参数校验:
父组件向子组件传值时,子组件有权对传递的内容进行相关约束,这个过程便是组件的参数校验。
vue组件 v-model语法糖_第6张图片

组件参数校验—基础验证:
需求:子组件要求父组件传递过来的值必须是数字(此时props可以改成对象格式,对象的键为接收的参数名字,值为数据类型)
此时,如果父组件传递的值类型不满足数字,即报错
vue组件 v-model语法糖_第7张图片
组件参数校验—多类型验证:
需求改进:
子组件接收的数据类型为数字或者字符串,即传递过来的数据类型要么为Number,要么为String。
此时可以借助数组语法
vue组件 v-model语法糖_第8张图片
组件参数校验—复杂验证(必填项):
参数校验规则除了上述简单的类型与多类型校验外,还可以执行更复杂的校验,如下所示
vue组件 v-model语法糖_第9张图片

组件参数校验—复杂验证(必填项):
必填项校验,如下所示
vue组件 v-model语法糖_第10张图片

组件参数校验—复杂验证(默认项):
require设置为false时,则为非必填项;此外,还可以设置default默认项。
vue组件 v-model语法糖_第11张图片

组件参数校验—复杂验证(默认项):
如果父组件传值,则会覆盖默认值
在这里插入图片描述

小结:
1、非必填时,如果未传值,则会显示默认值
2、如果传值,则会覆盖默认值

组件参数校验—复杂验证(自定义校验):
除了上述校验外,还可以定义更复杂的校验,使用validator(校验器)可以实现自定义校验。

案例:要求所传参数数值必须在18-50之间
vue组件 v-model语法糖_第12张图片

组件参数校验—复杂验证(自定义校验):
如果父组件传参不满足自定义校验范围,则会报错.
vue组件 v-model语法糖_第13张图片

组件参数校验简介:
组件参数校验即子组件接收父组件传递参数时,执行数据校验

分类类型:
①基础数据类型type校验
②多条件数据类型type校验{[]}
③必填项required校验
④默认值default校验
⑤自定义校验器validator校验

非props特性与props特性:

非props特性与props特性
props特性:父组件传递属性时,子组件的props里声明了对父组件所传属性的接收,即子组件通过props接收父组件所传属性。

非props特性:父组件传递属性时,子组件的props里没有声明对父组件所传属性的接收,即子组件没有通过props接收父组件所传属性。

场景:
vue中默认情况下,调用组件时,如果传入一些没有在props中定义的属性,会把这些“非法”属性渲染在组件的根元素上(class和style例外),而这些“非法”的属性会记录在$attrs属性上。
vue组件 v-model语法糖_第14张图片

props特性:父组件传递属性时,子组件的props里声明了对父组件所传属性的接收,即子组件通过props接收父组件所传属性。
vue组件 v-model语法糖_第15张图片

非props特性:父组件传递属性时,子组件的props里没有声明对父组件所传属性的接收,即子组件没有通过props接收父组件所传属性。
改动上述案例,去除props传递属性步骤,如下所示
vue组件 v-model语法糖_第16张图片

$attrs和inheritAttrs属性:

场景:
vue中默认情况下,调用组件时,如果传入一些没有在props中定义的属性,会把这些“非法”属性渲染在组件的根元素上(class和style例外),而这些“非法”的属性会记录在$attrs属性上。
vue组件 v-model语法糖_第17张图片

inheritAttrs继承属性
如何控制不把这些非法的属性渲染在组件的根元素上呢?
答案是在组件内部设置inheritAttrs:false即可。
vue组件 v-model语法糖_第18张图片

a t t r s 指 向 渲 染 属 性 : 通 过 v − b i n d = " attrs指向渲染属性: 通过v-bind=" attrsvbind="attrs"可以把“非法”的属性渲染到指定的组件某个元素上
vue组件 v-model语法糖_第19张图片

vue组件 v-model语法糖_第20张图片

vue组件 v-model语法糖_第21张图片

my-input的使用方式就像原生的input一样,而且my-input并没有设置props,如下
vue组件 v-model语法糖_第22张图片

1、props是用来接收父组件数据的,子组件不可以直接更改props接收的数据,即单向数据流概念。
2、非props特性:
①子组件未通过props接收,不能显示在dom上;
②子组件模板内直接写入内容而非插值表达式,会显示在dom最外层标签上
3、props特性:概括为父组件传,子组件接,dom标签内直接用。
4、props的值可以是两种,一种是字符串数组,一种是对象;
5、props中声明的数据与组件data函数return的数据主要区别
①props的来自父级
②data中的是组件自己的数据,作用域是组件本身
③这两种数据都可以在模板template及计算属性computed和方法methods中使用。
6、inheritAttrs继承属性+ a t t r s 属 性 , 即 可 解 决 非 p r o p s 属 性 带 来 的 问 题 7 、 attrs属性,即可解决非props属性带来的问题 7、 attrsprops7attrs–继承所有的父组件属性(除了prop传递的属性、class 和 style )
8、inheritAttrs:默认值true,继承所有的父组件属性(除props的特定绑定)作为普通的HTML特性应用在子组件的根元素上,如果你不希望组件的根元素继承特性设置inheritAttrs: false,但是class属性会继承
9、$attrs与inheritAttrs:用在父组件传递数据给子组件

H5编码规范:
vue组件 v-model语法糖_第23张图片

H5规范中要求,table里为tbody,tbody里需要放置tr和td,否则会将代码解析到table外。
方案:
这里,tbody中放置的是row,所以会解析到table同级外部,解决方案为is属性。既然tbody里只能放置tr,那么这里便改成tr+is属性
vue组件 v-model语法糖_第24张图片

template组件模板写法
写法一:直接写在选项里的模板
直接在构造器里的template选项后边编写。这种写法比较直观,但是如果模板html代码太多,不建议这么写。
vue组件 v-model语法糖_第25张图片
这里需要注意的是模板的标识不是单引号和双引号,而是,就是Tab上面的键

写法二:写在template标签里的模板
这种写法更像是在写HTML代码,就算不会写Vue的人,也可以制作页面。
vue组件 v-model语法糖_第26张图片

写法三:写在script标签text/x-template里的模板
这种写模板的方法,可以让模板文件从外部引入。
vue组件 v-model语法糖_第27张图片
小结:
写法一:直接写在选项里的模板
写法二:写在template标签里的模板
写法三:写在script标签里的模板
这里介绍了template的三种写法,以后学习到vue-cli的时候还会学到一种xxx.vue的单文件组件写法。

组件data:
组件data
在使用 data 和实例稍有区别, 组件的data必须是函数,且必须将数据 return出去。
案例:
vue组件 v-model语法糖_第28张图片

组件名
vue组件 v-model语法糖_第29张图片

组件注册:

为了能在模板中使用,组件必须先注册以便 Vue 能够识别。Vue有两种组件的注册类型:全局注册和局部注册。

vue组件 v-model语法糖_第30张图片

(1)全局注册案例:
vue组件 v-model语法糖_第31张图片
全局组件“嵌套性”:在所有子组件中也是如此,也就是说这三个组件在各自内部也都可以相互使用。

(2)局部注册
缘由:全局注册往往是不够理想的,全局注册所有的组件意味着即便你已经不再使用一个组件了,它仍然会被包含在你最终的构建结果中。这造成了用户下载的JS的无谓的增加。
在这些情况下,你可以通过一个普通的 JS对象来定义组件。
在这里插入图片描述

(2)局部注册
如上所示使用JS对象定义好组件对象,然后在 components 选项中定义你想要使用的组件
vue组件 v-model语法糖_第32张图片
对于 components 对象中的每个属性来说,其属性名就是自定义元素的名字,其属性值就是这个组件的选项对象。

(2)局部组件局限
局部注册的组件在其子组件中不可用。
例如:如果你希望 ComponentA 在 ComponentB 中可用,则需要这样写
vue组件 v-model语法糖_第33张图片
或者如果通过 Babel 和 webpack 使用 ES2015 即ES6 模块,那么代码如下所示:

(2)局部注册—简单了解即可
vue组件 v-model语法糖_第34张图片

在 ES2015+ 中,在对象中放一个类似 ComponentA 的变量名其实是 ComponentA: ComponentA 的缩写,即这个变量名同时是:
①用在模板中的自定义元素的名称
②包含了这个组件选项的变量名

模块系统

(1)在模块系统中局部注册
工程化完毕后,在项目下创建一个 components 组件目录,并将每个组件放置在其各自的文件中。然后需要在局部注册之前导入每个想使用的组件。例如,在一个假设的 ComponentB.js 或 ComponentB.vue 文件中:
vue组件 v-model语法糖_第35张图片
(2)基础组件的自动化全局注册
可能你的许多组件只是包裹了一个输入框或按钮之类的元素,是相对通用的。我们会把它们称为基础组件,它们会在各个组件中被频繁的用到。所以会导致很多组件里都会有一个包含基础组件的长列表,如下所示
vue组件 v-model语法糖_第36张图片

(2)基础组件的自动化全局注册
如果使用了 webpack (或在内部使用了 webpack 的 Vue Cli 3+),那么就可以使用 require.context 只全局注册这些非常通用的基础组件。
在应用入口文件 (比如 src/main.js) 中全局导入基础组件的示例代码,如下所示:
vue组件 v-model语法糖_第37张图片

自定义事件

正如之前所讲,子组件→父组件
当子组件需要向父组件传递数据时,需要用到自定义事件。
Vue 组件有一套观察者模式,子组件用 e m i t ( ) 来 触 发 事 件 , 父 组 件 用 emit()来触发事件,父组件用 emit()on()来监听子组件的事件

语法结构:
父组件通过v-on:eventName="parentEventName"来设置监听
子组件通过$.emit(‘eventName’)来触发事件。

自定义事件案例:
(1)子组件触发事件$.emit(‘eventName’,option)
在这里插入图片描述

自定义事件案例:
(2)父组件设置监听v-on:eventName="parentEventName"并接收参数
vue组件 v-model语法糖_第38张图片
自定义事件之事件名:
不同于组件和 prop,事件名不存在任何自动化的大小写转换。而是触发的事件名需要完全匹配监听这个事件所用的名称。举个例子,如果触发一个 camelCase 名字的事件:
在这里插入图片描述

在这里插入图片描述

注意:
不同于组件和 prop,事件名不会被用作一个 JavaScript 变量名或属性名,所以就没有理由使用 camelCase 或 PascalCase 了。
并且 v-on 事件监听器在 DOM 模板中会被自动转换为全小写 (因为 HTML 是大小写不敏感的),所以 v-on:myEvent 将会变成 v-on:myevent——导致 myEvent 不可能被监听到。

推荐:
综上所述,对于自定义事件名,建议始终使用 kebab-case 短横线命名法。

.sync修饰符

在vue2.4以前,父组件向子组件传值用props;子组件不能直接更改父组件传入的值,需要通过$emit触发自定义事件,通知父组件改变后的值,如此才能实现父子组件的通信。
过程比较繁琐,写法如下:
vue组件 v-model语法糖_第39张图片

.sync修饰符:
vue2.4以后的写法明显舒服许多,上面同样的功能,直接上代码
vue组件 v-model语法糖_第40张图片
写法上简化了一部分,很明显父组件不用再定义方法检测值变化了。其实只是对以前的$emit方式的一种缩写,.sync其实就是在父组件定义了一update:value方法,来监听子组件修改值的事件。

v-model语法糖

(1)v-model指令是什么?
vue通过v-model实现双向绑定数据,所以首先我们要明白v-model在这个过程中做了什么。
(2)v-model指令本质?
有vue基础的同学应该知道,v-model本质是一个语法糖。
即v-bind和v-on的结合体。

(3)v-model本质验证
表单元素比如input,v-bind绑定一个值,就把data数据传给了value,同时再通过v-on监听input事件,当表单数据改变的时候,也会把值传给data数据,代码如下

vue组件 v-model语法糖_第41张图片

(4)v-model等效写法

综上所述,v-model为v-on和v-bind结合体

在这里插入图片描述

自定义组件之v-model

官方文档:
允许一个自定义组件在使用 v-model 时定制 prop 和 event。默认情况下,一个组件上的 v-model 会把 value 用作 prop 且把 input 用作 event,但是一些输入类型比如单选框和复选框按钮可能想使用 value prop 来达到不同的目的。使用 model 选项可以回避这些情况产生的冲突。

官方文档说明:
上面,这句话比较长,咱们来一步步理解,首先是第一句
------允许一个自定义组件在使用v-model时定制prop和event
一般说来,v-model用在表单元素上进行数据的双向绑定,自定义组件通常通过父子组件传值绑定数据

案例1:组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件

vue组件 v-model语法糖_第42张图片

vue组件 v-model语法糖_第43张图片

代码解析:
前面说了,父子组件传值通过prop和$emit

第一步:父组件把num通过prop传给了子组件,但要注意,这里的子组件可以给prop取了一个别名,例如叫做value作为区分,所以子组件的props对象中的键为取的别名value。如果没有设置别名,则直接使用即可
第二步:当子组件input值改变的时候,子组件监听了一个oninput方法,注意这里也给 e m i t 中 的 事 件 取 了 一 个 别 名 , 只 不 过 这 个 别 名 和 原 来 的 名 字 一 样 o n i n p u t , i n p u t 值 改 变 后 , 通 过 emit中的事件取了一个别名,只不过这个别名和原来的名字一样oninput,input值改变后,通过 emitoninputinputemit提交input事件并把新值传给父组件,又要注意->$emit的荷载为字符串

官方解析:
v-model用在自定义组件最大的好处是提高了组件的封装性,父组件不必要另外写一个接受子组件发送给来的$emit方法。

最后是第三句话,但是一些输入类型比如单选框和复选框按钮可能想使用 value prop 来达到不同的目的。
—其实这很容易理解,因为value字符串在input中是有意义的,取别名有利于区分…

案例2:对上述案例做下调整,修改事件类型event为blur失焦时触发,代码如下
vue组件 v-model语法糖_第44张图片
此时,不再是实时输入触发数据更新,而是输入框失焦时更新数据。

案例3:
正如官方文档所说:像单选框、复选框等类型的输入控件可能会将 value 特性用于不同的目的,model 选项可以用来避免这样的冲突。
接下来修改model默认项,如下所示
vue组件 v-model语法糖_第45张图片

课堂总结
1、v-model是v-bind:value和v-on:input的简写
2、H5编码规范中要求,部分标签的嵌套结构必须固定(例如:table里为tbody,tbody里需要放置tr和td,否则会将代码解析到table外)
3、不同于组件和 prop,事件名$emit(事件)不存在任何自动化的大小写转换,必须短横线
4、组件名语义化:命名注意“语义化”,即你给予组件的名字可能依赖于你打算拿它来做什么

组件绑定原生事件

vue组件 v-model语法糖_第46张图片

在这里插入图片描述

vue组件 v-model语法糖_第47张图片

分析验证:
当点击按钮的时候发现,没有弹框提示,也就是说 handleClick 方法根本没有执行,究其原因,在于此时组件绑定事件等价于自定义事件。

方案:
通过 $emit 事件派发传递给父组件,代码如下所示:
vue组件 v-model语法糖_第48张图片

分析验证:
this.$emit方法也可以传递参数,修改代码,如下所示
vue组件 v-model语法糖_第49张图片

组件绑定原生事件:
如上代码,在组件上绑定原生事件还需要自定义事件,过于麻烦。这个时候 .native 原生修饰符就派上用场了,代码如下

vue组件 v-model语法糖_第50张图片

接下来再看个案例,给组件根元素添加.native绑定原生事件(onblur失焦事件),即失焦时触发

vue组件 v-model语法糖_第51张图片

组件绑定原生事件和$listeners

vue组件 v-model语法糖_第52张图片

监听属性$listeners :
为了解决这个问题,Vue 提供了一个 l i s t e n e r s 属 性 , 它 是 一 个 对 象 , 里 面 包 含 了 在 这 个 组 件 上 的 所 有 监 听 器 。 注 意 : 使 用 . n a t i v e 修 饰 符 的 事 件 , 不 会 体 现 在 listeners 属性,它是一个对象,里面包含了在这个组件上的所有监听器。 注意:使用.native修饰符的事件,不会体现在 listeners使.nativelisteners属性上。

场景:
当组件的根元素不具备一些DOM事件,但是根元素内部元素具备相对应的DOM事件,那么可以使用$listeners获取父组件传递进来的所有事件函数,再通过v-on="xxxx"绑定到相对应的内部元素上即可。

分析:
因为child组件的外层根元素是一个label元素,所以默认情况下使用v-on:blur是无效的,所以需要配合 l i s t e n e r s 使 用 , 该 属 性 可 以 把 事 件 的 监 听 指 向 组 件 中 某 个 特 定 的 元 素 注 意 : 再 次 强 调 , 如 果 父 级 的 事 件 添 加 了 . n a t i v e 修 饰 符 , 在 listeners使用,该属性可以把事件的监听指向组件中某个特定的元素 注意:再次强调,如果父级的事件添加了.native修饰符,在 listeners使.nativelisteners中不会体现出来的

vue组件 v-model语法糖_第53张图片

监听属性$listeners:
目前为止, 组件便是一个完全透明的包裹器了,也就是说它可以完全像一个普通的 元素一样使用了:所有跟它相同的特性和监听器的都可以工作。

小结:
1、组件根元素添加.native表示绑定原生事件
2、在开发里常通过props把构造器中data的值传递给组件,我们只要进行绑定就可以了,就是我们之前所介绍的v-bind:xxx
3、构造器即平时所说的Vue实例

这里简单介绍几个vue小技巧
1、$ listeners,它是一个对象,里面包含了作用在这个组件上的所有监听器,你就可以配合 v-on=" l i s t e n e r s " 将 所 有 的 事 件 监 听 器 指 向 这 个 组 件 的 某 个 特 定 的 子 元 素 。 2 、 引 用 下 v u e 的 官 方 a p i 中 对 listeners" 将所有的事件监听器指向这个组件的某个特定的子元素。 2、引用下vue的官方api中对 listeners"2vueapiattrs的说明: a t t r s 包 含 了 父 作 用 域 中 不 作 为 p r o p 被 识 别 ( 且 获 取 ) 的 特 性 绑 定 ( c l a s s 和 s t y l e 除 外 ) 3 、 attrs包含了父作用域中不作为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外) 3、 attrsprop()(classstyle)3listeners(自下而上传递数据), $attrs(自上而下多组件传递数据)

l i s t e n e r s 常 用 于 组 件 由 下 向 上 回 传 事 件 , 通 过 v − o n = " listeners常用于组件由下向上回传事件,通过 v-on=" listenersvon="listeners" 传入内部组件——在创建更高层次的组件时非常有用。

跨级通信方案
使用 a t t r s 和 attrs和 attrslisteners实现祖孙组件之间的数据传递,也就是多重嵌套组件之间的数据传递

$attrs----向下传递
$listeners----向上传递

跨级组件传值通信
假设第三层组件想和第一层组件进行通信
1、(第一层组件向第三层组件传值)—禁止第一层直接传值到第三层,需要逐层传递,即1→2→3,此时便可以实现跨级组件向下通信
2、(第三层组件向第一层组件传值)—通过触发自定义事件将数据传递至第二层,然后第二层通过事件触发传递至第一层,如此逐层传递,便可以实现跨级组件向上通信

$listeners

vue组件 v-model语法糖_第54张图片

vue组件 v-model语法糖_第55张图片

跨级向上通信:
接下来添加数据操作,因为单向数据流规定:后代组件不可以直接修改父组件传值,所以需要在后代组件里设置传值缓存,然后再事件回传.
vue组件 v-model语法糖_第56张图片

数据传递

简单总结下数据传递方向
之前使用 $attrs 实现数据的向下传递, 但是又怎么实现下层数据或事件的向上交互呢? 这里就要使用到 $listeners

$attrs是向下传递数据, $listeners 是向上传递方法,接受对象里的方法,来触发从父级接受来的函数。

vue组件 v-model语法糖_第57张图片

vue组件 v-model语法糖_第58张图片

$ref用法大概分为两种,普通DOM元素用法和组件用法
(1)普通DOM元素用法
有时Vue项目需要操作DOM节点,所以需要获取DOM。一般来讲,获取DOM元素,需document.querySelector()获取这个dom节点,然后才能进一步操作。

vue组件 v-model语法糖_第59张图片

r e f 与 ref与 refrefs

vue组件 v-model语法糖_第60张图片

(1)普通DOM元素用法
新版做法:用ref绑定之后,我们就不需要在获取dom节点了,直接在上面的input上绑定 r e f , 然 后 通 过 ref,然后通过 refrefs.$ref即可调用,这样就可以减少获取dom节点的消耗。

vue组件 v-model语法糖_第61张图片
(2)组件component用法
案例:利用组件,实现计数器count效果
1、首先封装个简单的组件,每次点击+1,调用两次
vue组件 v-model语法糖_第62张图片
(2)组件component用法
2、接下来,想在HTML模板里获取两个组件次数的和。此时需要在父组件获取子组件的状态变化,即自定义事件,利用发布订阅模式。
vue组件 v-model语法糖_第63张图片

(2)组件component用法
最后,获取两个组件实例单独的数据,相加即可
vue组件 v-model语法糖_第64张图片

官方文档描述小结:
$ref:注册引用信息属性,用来给元素或子组件注册引用信息。
$refs:一个对象,持有已经注册过ref的所有子组件。

通俗理解:
$ref:注册引用信息属性
$refs:注册引用信息对象

r e f 含 义 : 被 用 来 给 元 素 或 子 组 件 注 册 引 用 信 息 , 引 用 信 息 将 会 注 册 在 父 组 件 的 ref含义: 被用来给元素或子组件注册引用信息,引用信息将会注册在父组件的 refrefs对象上。如果在普通的DOM元素上使用,那么指向的就是普通的DOM元素。

$ref 三种用法:
1、ref 加在普通的元素上,用this.ref.name 获取到的是dom元素
2、ref 加在子组件上,用this.ref.name 获取到的是组件实例,可以使用组件的所有方法。
3、利用 v-for 和 ref 获取一组数组或者dom 节点

小结:
1、 r e f : 被 用 来 给 元 素 或 子 组 件 注 册 引 用 信 息 , 引 用 信 息 将 会 注 册 在 父 组 件 的 ref:被用来给元素或子组件注册引用信息,引用信息将会注册在父组件的 refrefs对象上。如果在普通的DOM元素上使用,那么指向的就是普通的DOM元素
2、$refs:一个对象,持有注册过 ref 特性 的所有 DOM 元素和组件实例

注意:refs只会在组件渲染完成之后生效,并且它们不是响应式的。这只意味着一个直接的子组件封装的“逃生舱”——你应该避免在模板或计算属性中访问 $refs 。

你可能感兴趣的:(vue组件 v-model语法糖)