这里有新鲜出炉的 vue.js 教程,程序狗速度看过来!
Vue.js 是构建 web 界面的 JavaScript 库,提供数据驱动的组件,还有简单灵活的 API,使得 MVVM 更简单。
这篇文章主要介绍了 JS 框架之 vue.js component 组件的相关资料, 本文通过实例详解的方式给大家介绍的非常详细,具有参考借鉴价值,需要的朋友可以参考下
这个要单独写,原文是这么描述 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),希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 phperz 网站的支持!
来源: http://www.phperz.com/article/17/0506/331478.html