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 相关文章推荐
详解Bootstrap四种图片样式
Jan 04 Javascript
JavaScript jquery及AJAX小结
Jan 24 Javascript
Radio 单选JS动态添加的选项onchange事件无效的解决方法
Dec 12 Javascript
javascript设计模式之中介者模式学习笔记
Feb 15 Javascript
VUE多层路由嵌套实现代码
May 15 Javascript
JavaScript 中调用 Kotlin 方法实例详解
Jun 09 Javascript
vue项目中使用百度地图的方法
Jun 08 Javascript
node.js读取Excel数据(下载图片)的方法示例
Aug 02 Javascript
使用electron将vue-cli项目打包成exe的方法
Sep 29 Javascript
Vue侦测相关api的实现方法
May 22 Javascript
使用Vue-cli3.0创建的项目 如何发布npm包
Oct 10 Javascript
基于element-ui封装表单金额输入框的方法示例
Jan 06 Javascript
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中替换换行符的几种方法小结
2012/10/15 PHP
PHP单例模式是什么 php实现单例模式的方法
2016/05/14 PHP
Laravel学习教程之model validation的使用示例
2017/10/23 PHP
laravel orm 关联条件查询代码
2019/10/21 PHP
php中数组最简单的使用方法
2020/12/27 PHP
删除select中所有option选项jquery代码
2013/08/12 Javascript
jquery禁用右键单击功能屏蔽F5刷新
2014/03/17 Javascript
浏览器缩放检测的js代码
2014/09/28 Javascript
jQuery实现拖动调整表格单元格大小的代码实例
2015/01/13 Javascript
jquery实现未经美化的简洁TAB菜单效果
2015/08/28 Javascript
详解ECharts使用心得总结
2016/12/06 Javascript
js 单引号替换成双引号,双引号替换成单引号的实现方法
2017/02/16 Javascript
Vue开发中整合axios的文件整理
2017/04/29 Javascript
微信小程序实现下拉刷新和轮播图效果
2017/11/21 Javascript
Vue数据双向绑定的深入探究
2018/11/27 Javascript
vue项目中axios请求网络接口封装的示例代码
2018/12/18 Javascript
vue实现拖拽效果
2019/12/23 Javascript
Element InputNumber计数器的使用方法
2020/07/27 Javascript
python字符串中的单双引
2017/02/16 Python
Python OpenCV读取png图像转成jpg图像存储的方法
2018/10/28 Python
python f-string式格式化听语音流程讲解
2019/06/18 Python
Python3网络爬虫开发实战之极验滑动验证码的识别
2019/08/02 Python
通过字符串导入 Python 模块的方法详解
2019/10/27 Python
如何利用pygame实现简单的五子棋游戏
2019/12/29 Python
pytorch下使用LSTM神经网络写诗实例
2020/01/14 Python
Python基于network模块制作电影人物关系图
2020/06/19 Python
日本一家专门经营各种箱包的大型网站:Traveler Store
2016/08/03 全球购物
新西兰便宜隐形眼镜购买网站:QUICKLENS New Zealand
2019/03/02 全球购物
中专生职业生涯规划书范文
2014/01/10 职场文书
个性与发展自我评价
2014/02/11 职场文书
房地产公司见习自我鉴定
2014/04/28 职场文书
党的群众路线教育实践活动个人整改方案
2014/10/25 职场文书
信访维稳承诺书
2015/05/04 职场文书
餐厅营销的秘密:为什么老顾客会流水?
2019/08/08 职场文书
2019年汽车租赁合同范本!
2019/08/12 职场文书
详解运行Python的神器Jupyter Notebook
2021/06/03 Python