JS框架之vue.js(深入三:组件1)


Posted in Javascript onSeptember 29, 2016

这个要单独写,原文是这么描述vue的组件的:组件(Component)是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能。在有些情况下,组件也可以是原生 HTML 元素的形式,以 is 特性扩展。

这个特性我感觉比较难理解,一步步来,看看组件到底是个什么东西?

1.举个栗子

//model层:
// 通过extend方式定义一个Vue组件
var MyComponent = Vue.extend({
template: '<div>A custom component!</div>'
})
// 向Vue注册这个组件,名称定为my-component
Vue.component('my-component', MyComponent)
// 创建根实例
new Vue({
el: '#example'
})
//Vue层:
<div id="example">
<my-component></my-component>
</div>

渲染为:

<div id="example">
<div>A custom component!</div>
</div>

就是这个栗子,差点把我忽悠了,以为前面对extend的概念理解错了。还记得前面是这么描述
var MyComponent = Vue.extend()的,Vue相当于基类,MyComponent继承了Vue,拥有了Vue的属性和方法,但是继承的概念还有另一层,就是基类是木有子类自定义的属性和方法的。这里的子类MyComponent扩展了一个属性template,按照继承的说法,Vue基类是不能使用的,但是这个栗子看似违背了这个规则,最后创建的是Vue实例,同时让模板生效了。正常的写法不是应该这样:

//model层:
// 通过extend方式定义一个Vue组件
var MyComponent = Vue.extend({
template: '<div>A cu stom component!</div>'
})
// 不用注册
//Vue.component('my-component', MyComponent)
// 创建MyComponent 实例
new MyComponent ({
el: '#example'
})
//Vue层:
<div id="example">
//不用组件
//<my-component></my-component>
</div>

经过试验,这种写法确实没错,也可以正常显示。问题来了,为什么第一种写法也是可以的,比较两处代码,发现第一种写法有一个注册过程,注册了一个my-component,最后使用的也是这个my-component,仔细想想,并不是说Vue实例可以使用template,而是向Vue注册了这个组件后,Vue实例就可以使用这个组件了,所以并不冲突。(吓死宝宝了- -)

想清楚这个后,再来考虑另外一个问题,这两种写法的区别在于哪里?
有没有发现,第二种写法其实是很有限制的,他替换了整个div,不管div中有多少内容。比如:

<div id="example">
ssssdfsdaf
<button>abc</button>
</div>

最后统统不见,被替换成<div>A cu stom component!</div>。灵活度太低,如果我只想替换ssssdfsdaf怎么办?所以就要用第一种方式了,于是幡然醒悟,原来这就是组件,就像一个零件一样,想往哪塞就往哪塞:

<div id="example">
<my-template>ssssdfsdaf<my-template>
<button>abc</button>
</div>

另外,注册必须在新建实例前,反过来的话,新建的实例肯定不能使用组件的。

原文还说replace可以决定是否替换,这个不知道咋用,先留一坑在这,后面看看能否用上。 //坑1

2.组件注册有两种方式:

一是前面看到的全局注册方式,Vue.component,这种全局可用。

二是局部注册方式

// 局部注册也可以这么做
var Parent = Vue.extend({
components: {
'my-component': {
template: '<div>A custom component!</div>'
}
}
})

这种写法最简,很明显Parent扩展了Vue,拥有了组件my-component。此时的组件只有Parent能用,Vue不能用。

3.is属性

组件在使用的过程中也是有限制的。原因在于:

Vue 的模板是 DOM 模板,使用浏览器原生的解析器而不是自己实现一个。所以组件被替换后必须依照html的正常标准来,它必须是有效的 HTML 片段。一些 HTML 元素对什么元素可以放在它里面有限制。常见的限制:

a 不能包含其它的交互元素(如按钮,链接)

ul 和 ol 只能直接包含 li

select 只能包含 option 和 optgroup

table 只能直接包含 thead, tbody, tfoot, tr, caption, col, colgroup

tr 只能直接包含 th 和 td

以table为例

<table>
<my-component></my-component>
<my-component></my-component>
</table>
// 定义
var MyComponent = Vue.extend({
template: '<tr>A custom component!</tr>'
})

这样的写法看似正常,因为<table><tr></tr></table>结构是正常的,但是实际上不能依赖自定义组件在浏览器验证之前的展开结果,所以这里不被认为是<tr>。为此,is属性便有作用了,将以上写法改写:

<table>
<tr is="my-component"></tr> //这里改成is属性
<tr is="my-component"></tr>
<tr is="my-component"></tr>
</table>
// 定义
var MyComponent = Vue.extend({
template: '<div>A custom component!</div>' //这里不能用tr
})

修改后,相当于

<table>
<tr><my-component></my-component></tr>
<tr><my-component></my-component></tr>
<tr><my-component></my-component></tr>
</table>

保留了原来的tr,所以dom解析不会出错

4.Props:组件通讯的手段

4.1“prop” 是组件数据的一个字段,期望从父组件传下来。子组件需要显式地用 props 选项 声明 props:

Vue.component('child', {
// 声明 props,这里驼峰式命名
props: ['myMessage'],
//模板中可以这样用
template: '<span>{{ myMessage }}</span>'
})

HTML 特性不区分大小写。名字形式为 camelCase 驼峰式的 prop 用作特性时,需要转为 kebab-case(短横线隔开),所以html中是这个样子的:

<!-- kebab-case in HTML -->
<child my-message="hello!"></child>

以上这种是props的静态用法,也可以用 v-bind 绑定动态 Props 到父组件的数据。每当父组件的数据变化时,也会传导给子组件:

<div>
<input v-model="parentMsg">
<br>
<child v-bind:my-message="parentMsg"></child>
</div>

这时候看到v-model有点懵逼,这货不是跟{{}}类似,引用data属性中的parentMsg吗?此时肯定是没有定义parentMsg的,所以v-bind:my-message=”parentMsg”绑定组件的同时,赋予了父组件parentMsg属性。

4.2 prop的绑定类型:

prop 默认是单向绑定:当父组件的属性变化时,将传导给子组件,但是反过来不会。这是为了防止子组件无意修改了父组件的状态——这会让应用的数据流难以理解。不过,也可以使用 .sync 或 .once 绑定修饰符显式地强制双向或单次绑定:

<!-- 默认为单向绑定 -->
<child :msg="parentMsg"></child>
<!-- 双向绑定 -->
<child :msg.sync="parentMsg"></child>
<!-- 单次绑定 -->
<child :msg.once="parentMsg"></child>

双向绑定会把子组件的 msg 属性同步回父组件的 parentMsg 属性。单次绑定在建立之后不会同步之后的变化。这里原文还特定强调了下, prop 是一个对象或数组时,是按引用传递,修改内容会随时修改父组件内容,这个有语言基础的都知道。

4.3 prop验证:

组件可以为 props 指定验证要求。当组件给其他人使用时这很有用,因为这些验证要求构成了组件的 API,确保其他人正确地使用组件。此时 props 的值是一个对象({}而不是[]),包含验证要求:

Vue.component('example', {
props: {
// 基础类型检测 (`null` 意思是任何类型都可以)
propA: Number,
// 多种类型 (1.0.21+)
propM: [String, Number],
// 必需且是字符串
propB: {
type: String,
required: true
},
// 数字,有默认值
propC: {
type: Number,
default: 100
},
// 对象/数组的默认值应当由一个函数返回
propD: {
type: Object,
default: function () {
return { msg: 'hello' }
}
},
// 指定这个 prop 为双向绑定
// 如果绑定类型不对将抛出一条警告
propE: {
twoWay: true
},
// 自定义验证函数
propF: {
validator: function (value) {
return value > 10
}
},
// 转换函数(1.0.12 新增)
// 在设置值之前转换值
propG: {
coerce: function (val) {
return val + '' // 将值转换为字符串
}
},
propH: {
coerce: function (val) {
return JSON.parse(val) // 将 JSON 字符串转换为对象
}
}
}
})

type 可以是下面原生构造器:

String

Number

Boolean

Function

Object

Array

type 也可以是一个自定义构造器,使用 instanceof 检测。

当 prop 验证失败了,Vue 将拒绝在子组件上设置此值,如果使用的是开发版本会抛出一条警告。

这里也是看的我一脸懵逼,连个栗子都不给,拿刚才的例子改一下打个比方

Vue.component('child', {
// 声明 props,这里驼峰式命名
props: ['myMessage'],
//模板中可以这样用
template: '<span>{{ myMessage+1}}</span>' //改成表达式
})
<!-- kebab-case in HTML -->
<child my-message="hello!"></child> //这里先不改

如果我们希望别人把child组件的myMessage当做Number类型来处理,而我们这里又没有做prop验证,结果就是{{ myMessage+1}}会变成字符串拼接,当html传入的是hello!,渲染出来结果:hello!

所以说,告诉别人这里要传入Number类型是必要的,于是改为:

Vue.component('child', {
// 声明 props,这里驼峰式命名
props: {myMessage:Number},
//模板中可以这样用
template: '<span>{{ myMessage+1}}</span>' //改成表达式
})

这时候如果传入hello!,此时渲染结果?没错,就是NaN。这样别人就知道要传入一个数字了。
如果这样传入

<child my-message="123"></child> //改成123

这样总行了吧,运行,他喵的居然还不行,还是NaN。原文有这样的解释:

//#字面量语法 vs. 动态语法
//初学者常犯的一个错误是使用字面量语法传递数值:
<!-- 传递了一个字符串 "1" -->
<comp some-prop="1"></comp>
因为它是一个字面 prop,它的值以字符串 "1" 而不是以实际的数字传下去。如果想传递一个实际的 JavaScript 数字,需要使用动态语法,从而让它的值被当作 JavaScript 表达式计算:
<!-- 传递实际的数字 -->
<comp :some-prop="1"></comp>

好吧,也就是说刚才传递的实际上是字符串”123”,结果必然是NaN,再改:

<child :my-message="123"></child> //改成123

此时{{myMessage+1}}会得到正确的结果:124

以上所述是小编给大家介绍的JS框架之vue.js(深入三:组件1),希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
网页设计常用的一些技巧
Dec 22 Javascript
javascript 硬盘序列号+其它硬件信息
Dec 23 Javascript
JQuery Dialog的内存泄露问题解决方法
Jun 18 Javascript
Javascript数组的排序 sort()方法和reverse()方法
Jun 04 Javascript
值得分享的bootstrap table实例
Sep 22 Javascript
seajs学习之模块的依赖加载及模块API的导出
Oct 20 Javascript
想用好React的你必须要知道的一些事情
Jul 24 Javascript
JavaScript中set与get方法用法示例
Aug 15 Javascript
jQuery实现点击图标div循环放大缩小功能
Sep 30 jQuery
JS实现的定时器展示简单秒表、页面弹框及跳转操作完整示例
Jan 26 Javascript
JavaScript观察者模式原理与用法实例详解
Mar 10 Javascript
vue实现Toast组件轻提示
Apr 10 Vue.js
JavaScript 对象详细整理总结
Sep 29 #Javascript
JS实现拖动滚动条评分的效果代码分享
Sep 29 #Javascript
Angular 中 select指令用法详解
Sep 29 #Javascript
jQuery视差滚动效果网页实现方法经验总结
Sep 29 #Javascript
js仿小米官网图片轮播特效
Sep 29 #Javascript
基于jquery实现弹幕效果
Sep 29 #Javascript
js获取Get值的方法
Sep 29 #Javascript
You might like
php str_getcsv把字符串解析为数组的实现方法
2017/04/05 PHP
php实现对短信验证码发送次数的限制实例讲解
2021/03/04 PHP
Add Formatted Data to a Spreadsheet
2007/06/12 Javascript
ExtJS扩展 垂直tabLayout实现代码
2009/06/21 Javascript
深入理解JavaScript系列(7) S.O.L.I.D五大原则之开闭原则OCP
2012/01/15 Javascript
jQuery隔行变色与普通JS写法的对比
2013/04/21 Javascript
ZeroClipboard插件实现多浏览器复制功能(支持firefox、chrome、ie6)
2014/08/30 Javascript
jquery实现表格隔行换色效果
2015/11/19 Javascript
分享jQuery封装好的一些常用操作
2016/07/28 Javascript
JS实现的相册图片左右滚动完整实例
2016/11/23 Javascript
JS简单实现滑动加载数据的方法示例
2017/10/18 Javascript
浅谈vue项目打包优化策略
2018/09/29 Javascript
详解微信图片防盗链“此图片来自微信公众平台 未经允许不得引用”的解决方案
2019/04/04 Javascript
JavaScript判断浏览器运行环境的详细方法
2019/06/30 Javascript
JavaScript 替换所有匹配内容及正则替换方法
2020/02/12 Javascript
javascript前端和后台进行数据交互方法示例
2020/08/07 Javascript
Python3基础之基本数据类型概述
2014/08/13 Python
Python验证码识别的方法
2015/07/10 Python
Python的Django框架可适配的各种数据库介绍
2015/07/15 Python
python下调用pytesseract识别某网站验证码的实现方法
2016/06/06 Python
Python合并字典键值并去除重复元素的实例
2016/12/18 Python
Python读取Json字典写入Excel表格的方法
2018/01/03 Python
python 列表,数组,矩阵两两转换tolist()的实例
2018/04/04 Python
解决pyinstaller打包exe文件出现命令窗口一闪而过的问题
2018/10/31 Python
Python3之手动创建迭代器的实例代码
2019/05/22 Python
Pandas操作CSV文件的读写实现方法
2019/11/13 Python
python定义类self用法实例解析
2020/01/22 Python
python如何实现复制目录到指定目录
2020/02/13 Python
2020最新pycharm汉化安装(python工程狮亲测有效)
2020/04/26 Python
keras训练曲线,混淆矩阵,CNN层输出可视化实例
2020/06/15 Python
《会变的花树叶》教学反思
2014/02/10 职场文书
流动人口婚育证明范本
2014/09/26 职场文书
党员查摆四风问题思想汇报
2014/10/25 职场文书
被告代理词范文
2015/05/25 职场文书
地道战观后感400字
2015/06/04 职场文书
2015迎新晚会活动总结
2015/07/16 职场文书