vue.js初学入门教程(2)
接着上一篇vue慢速入门教程学习。
4.组件使用基础
什么是组件?组件可以理解为可重用的自定义html。
可以使用一堆组件来构造大型应用,任意类型的应用界面都可以抽象为一个组件树:
可以把组件代码按照template、style、script的拆分方式,放置到对应的.vue文件中。
组件预定义选项中最核心的几个:
模板(template)、初始数据(data)、接受的外部参数(props)、方法(methods)、生命周期钩子函数(lifecycle hooks)。
4.1 基本步骤
使用组件首先需要创建构造器:
var mycomponent = vue.extend({ // 选项... })
要把这个构造器用作组件,需要用 vue.component(tag, constructor) 注册 :
// 全局注册组件,tag 为 my-component vue.component('my-component', mycomponent)
然后使用:
<!doctype html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <div id="xxx"> <my-component></my-component> </div> </body> <script src="js/vue.js"></script> <script> var mycomponent = vue.extend({ template: '<p>9898不得了!</p>' }); vue.component('my-component', mycomponent); new vue({ el: '#xxx' }); </script> </html>
其中,
vue.component('my-component', mycomponent)这种是全局注册,第一个参数是注册组件的名称,第二个参数是组件的构造函数;
选项对象的template属性用于定义组件要渲染的html;
组件的模板替换了自定义元素,自定义元素的作用只是作为一个挂载点。组件挂载在vue实例上才会生效。
对于自定义标签名字,vue.js 不强制要求遵循 w3c 规则(小写,并且包含一个短杠),为了避免不必要的事端尽管遵循这个规则。
4.2 局部注册
用实例选项 components 注册:
<!doctype html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <div id="xxx"> <my-component></my-component> </div> </body> <script src="js/vue.js"></script> <script> var mycomponent = vue.extend({ template: '<p>9898不得了!</p>' }); // vue.component('my-component', mycomponent); new vue({ el: '#xxx', components: { 'my-component': mycomponent } }); </script> </html>
也可以在组件中定义并使用其他组件:
<!doctype html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <div id="example"> <xx-component></xx-component> </div> </body> <script src="js/vue.js"></script> <script> var child = vue.extend({ template: '<div>i am zai</div>', replace: true }) var parent = vue.extend({ template: '<p>i am baba</p><br/><wa></wa>', components: { // <xx-component>只能用在父组件模板内 'wa': child } }) // 创建根实例 new vue({ el: '#example', components: { 'xx-component': parent } }) </script> </html>
其中,子组件只能在父组件的template中使用。
另外,有简化的写法,vue在背后会自动地调用vue.extend():
<!doctype html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <div id="xxx"> <my-component-continue></my-component-continue> </div> </body> <script src="js/vue.js"></script> <script> // 局部注册的简化写法 var vm2 = new vue({ el: '#xxx', components: { 'my-component': { template: '<div>9898不得了!</div>' }, 'my-component-continue': { template: '<div>粮食大丰收!</div>' } } }) </script> </html>
4.3 组件选项问题
在定义组件的选项时,data和el选项必须使用函数。
如果data选项指向某个对象,这意味着所有的组件实例共用一个data。
所以应当使用一个函数作为 data 选项,让这个函数返回一个新对象:
vue.component('my-component', { data: function(){ return {a : 1} } })
同理,el 选项用在 vue.extend() 中时也须是一个函数。
5.数据传递
vue.js组件之间有三种数据传递方式:
props
组件通信
slot
5.1 props
“props”是组件数据的一个字段,期望从父组件传下来数据。因为组件实例的作用域是孤立的,所以子组件需要显式地用props选项来获取父组件的数据。
props选项可以是字面量、表达式、绑定修饰符。
5.1.1 字面量
<!doctype html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <child msg="hello!"></child> <script src="js/vue.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> vue.component('child', { // 声明 props props: ['msg'], // prop 可以用在模板内 // 可以用 `this.msg` 设置 template: '<span>{{ msg }}你困吗</span>' }) new vue({ el: 'body' }) </script> </body> </html>
html 特性不区分大小写。名字形式为 camelcase 的 prop 用作特性时,需要转为 kebab-case(短横线隔开):
vue.component('child', { // camelcase in javascript props: ['mymessage'], template: '<span>{{ mymessage }}</span>' }) <!-- kebab-case in html --> <child my-message="hello!"></child>
5.1.2 动态
类似于用 v-bind 绑定 html 特性到一个表达式,也可以用 v-bind 绑定动态 props 到父组件的数据。每当父组件的数据变化时,也会传导给子组件。比如酱:
<!doctype html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <div> <input v-model="parentmsg"> <br> <child :my-message="parentmsg"></child> </div> <script src="js/vue.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> vue.component('child', { props: ['mymessage'], template: '<span>{{ mymessage }}你困吗</span>' }) new vue({ el: 'body', data:{ parentmsg:'' } }) </script> </body> </html>
当我在input里面输入哈哈的时候:
5.1.3 绑定类型
可以使用绑定修饰符:
.sync,双向绑定
.once,单次绑定
<!-- 默认为单向绑定 --> <child :msg="parentmsg"></child> <!-- 双向绑定 --> <child :msg.sync="parentmsg"></child> <!-- 单次绑定 --> <child :msg.once="parentmsg"></child>
prop 默认是单向绑定:当父组件的属性变化时,将传导给子组件,但是反过来不会。
不过需要注意的是:如果 prop 是一个对象或数组,是按引用传递。在子组件内修改它会影响父组件的状态,不管是使用哪种绑定类型。
示例:
<!doctype html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <div id="app"> <table> <tr> <th colspan="3">父组件数据</td> </tr> <tr> <td>name</td> <td>{{ name }}</td> <td><input type="text" v-model="name" /></td> </tr> <tr> <td>age</td> <td>{{ age }}</td> <td><input type="text" v-model="age" /></td> </tr> </table> <my-component v-bind:my-name.sync="name" v-bind:my-age="age"></my-component> </div> <template id="mycomponent"> <table> <tr> <th colspan="3">子组件数据</td> </tr> <tr> <td>my name</td> <td>{{ myname }}</td> <td><input type="text" v-model="myname" /></td> </tr> <tr> <td>my age</td> <td>{{ myage }}</td> <td><input type="text" v-model="myage" /></td> </tr> </table> </template> <script src="js/vue.js"></script> <script> var vm = new vue({ el: '#app', data: { name: 'k', age: 24 }, components: { 'my-component': { template: '#mycomponent', props: ['myname', 'myage'] } } }) </script> </body> </html>
上面这段设置了名字双向,年龄单向:
以下是一个大神的综合示例:
<!doctype html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <div id="app"> <table> <tr> <th colspan="3">父组件数据</td> </tr> <tr> <td>name</td> <td>{{ name }}</td> <td><input type="text" v-model="name" /></td> </tr> <tr> <td>age</td> <td>{{ age }}</td> <td><input type="text" v-model="age" /></td> </tr> </table> <my-component v-bind:my-name.sync="name" v-bind:my-age="age"></my-component> </div> <template id="mycomponent"> <table> <tr> <th colspan="3">子组件数据</td> </tr> <tr> <td>my name</td> <td>{{ myname }}</td> <td><input type="text" v-model="myname" /></td> </tr> <tr> <td>my age</td> <td>{{ myage }}</td> <td><input type="text" v-model="myage" /></td> </tr> </table> </template> <script src="js/vue.js"></script> <script> var vm = new vue({ el: '#app', data: { name: 'k', age: 24 }, components: { 'my-component': { template: '#mycomponent', props: ['myname', 'myage'] } } }) </script> </body> </html>
可以检索:
其中,{{ col | capitalize}}过滤,首字母大写。
<tr v-for="entry in data | filterby filterkey"> <td v-for="col in columns"> {{entry[col]}} </td> </tr>
过滤搜索关键词;
双循环,tr循环data条数,4行,entry表示每行;td循环columns数量,3列,col表示每列,entry[col]取具体数据。
props: { data: array, columns: array, filterkey: string }
验证:父组件传递过来的data和columns必须是array类型,filterkey必须是字符串类型。
验证要求示例:
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 字符串转换为对象 } } } })
stringtype 可以是下面原生构造器:
number
boolean
function
object
array
type 也可以是一个自定义构造器,使用 instanceof 检测。
当 prop 验证失败时,vue 将拒绝在子组件上设置此值,如果使用的是开发版本会抛出一条警告。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
《vue.js权威指南》
下一篇: 杨阜为什么恨马超?杨阜把马超一家杀光