目录
一.概念(vue的两大核心:数据驱动和组件化)
组件是自定义标签,vueJs提供的组件可以让程序员自己定义标签,对页面进行模块化。每个标签里面包含html、css、js。
标签: <标签名 属性名=“属性值" 事件=”函数“>内容</标签名>
vue的组件就是一个vue对象。vue对象的配置项,在vue组件里也可以使用。
注:
1.组件的配置项中没有el属性,只有根实例存在el,组件中使用template定义模板,且只能有一个根标签;
2.组件名不可和html官方的标签名同名,组件名如果是小驼峰,那么使用时,用短横线/组件名首字母大写;
3.data是一个函数。
[面试题]data是个函数?
一个组件的 data 选项必须是一个函数,且必须返回object,只有这样,每个实例(vue组件对象)就可以维护一份被返回对象的独立的拷贝,否则组件复用时,数据相互影响,也就是说,组件的作用域是独立的。
简单回答:如果不是函数,那么,复用的组件的data共享同一块内存空间。
二.定义组件
方法一:
let 组件变量名= Vue.extend({
template:'<div class="header">{{msg}},我是header组件</div>'
data:function(){
return {
msg:”hi”
}
},
})
方法二:
let 组件变量名={
配置项
}
三.注册组件
<一>全局注册:在任何vue对象中都可以使用。
Vue.component('组件名',组件变量名);
<二>局部注册:只能在当前vue对象(组件)中使用。
//在vue对象的components选项里进行注册
new Vue({
el:
components:{
组件名:组件变量名
}
});
四.使用组件
组件是自定义标签,所以使用组件,就是使用标签。
<组件名></组件名>
五.组件嵌套
把一个组件的标签写在另外一个组件的template里,就是组件的嵌套。
eg:父组件中嵌套了子组件。
注:子组件的定义必须在父组件的前面,因为子组件需要在父组件中注册、使用。
//子组件
let myComSon = {
template:"<div>我是son里的div:{{msg}}</div>",
data:function(){
return {
msg:"hi:son"
}
}
};
//父组件
let myComParent = {
template:`<div>
<p>我是p:{{msg}}</p>
<my-com-son></my-com-son>
</div>`,
data:function(){
return {
msg:"hi"
}
},
components:{
// 局部注册了另外一个组件
"my-com-son":myComSon
}
};
六.组件的属性
使用props(property)来完成组件属性的声明。props是外部给组件传入的数据。而组件的data是组件内部的数据。
- 使用prop传递静态数据
在组件内部增加配置项props来声明组件里的属性。props里可以声明多个属性,即是个数组。
let myComParent = {
props:["name","sex"], //声明了两个自定义属性
template:`<div>
<p>我是p:{{msg}}</p>
<p>人的信息:</p>
<p>姓名:{{name}}</p>
<p>性别:{{sex}}</p>
</div>`,
data:function(){
return {
msg:"hi"
}
}
};
使用该组件,给属性传入数据
<!-- 使用组件时,给属性传入值,传入的值,就可以在组件内部使用 -->
<my-com-parent name="张三疯他哥" sex="男"></my-com-parent>
- 使用prop传递动态数据
组件属性和官方标签的属性是同样的道理,所以给组件的属性也可以v-bind数据,即绑定动态数据。
<my-com-parent v-bind:name="name" sex="男"></my-com-parent>
如果想将一个对象的所有属性作为prop进行传递,可以使用不带任何参数的v-bind(而不是v-bind:prop-name)。
eg:已知一个todo对象
todo: {
text: 'Learn Vue',
isComplete: false
}
<todo-item v-bind="todo"></todo-item>
等价于:
<todo-item
v-bind:text="todo.text"
v-bind:is-complete="todo.isComplete"
></todo-item>
特殊情况:
在JavaScript中对象和数组是通过引用传入的(穿的是地址),所以对于一个数组或对象类型的prop来说,在子组件中改变对这个对象或数组本身将会影响到父组件的状态(data),相当于函数的形参是引用类型。
- prop验证
对属性类型的验证、属性默认值、是否必须等,这时props不能使用数组,需要使用对象。
eg:
props:{
"name":{
type:String, //限制name属性的类型是字符串
required:true //限制name属性是必须传入值的。
},
"sex":[String,Number], //限制sex属性的值可以为字符串,也可以为数字
"age":{
type:Number, //限制age属性的类型是数字型
default:10 // age属性的默认值是10 。如果没有给age传值,那么age就是10。
},
"isadult":Boolean
}
七.单向数据流
prop是单向绑定的,当父组件的属性(数据)变化时,将传给子组件,但是反过来不会。是为了防止子组件无意间修改了父组件的状态,来避免应用的数据流变得难以理解。另外,每次当父组件更新是,子组件的所有prop都会更新为最新值。这意味着不应该在子组件内部改变prop。如果这么做了,Vue会在控制台给出警告。
八.事件
- 绑定事件
①html(标签)里的绑定方式:v-on;
②js(vue)里的绑定方式:vue对象.$on("事件名")
- 触发事件
vue对象.$emit("事件名",参数)
eg:
//子组件:
Vue.component('button-counter',{
template: "<input type='button' v-on:click='incrementCounter' v-model='counter' />",
data:function(){
return {
counter:0
}
},
methods:{
incrementCounter:function(){
this.counter += 1
this.$emit('increment')
}
}
});
//父组件:
<div id="app1">
<p>{{ total }}</p>
<button-counter v-on:increment="incrementTotal"></button-counter>
</div>
var app1 = new Vue({
el: '#app1',
data:{
total:0
},
methods:{
incrementTotal:function(){
this.total += 1;
}
}
})
九.内容(插槽)
组件的内容即就是标签的innerHTML,vueJs里就是slot(插槽)分发内容。
- 单个插槽
eg:
//子组件
let person = {
template:`<div>
<hr/>
<p>我是上p</p>
<slot></slot>
<p>我时下p</p>
<hr/>
</div>`
};
//父组件:
let person = {
template:` <div id="app">
<person>
<div>我是div</div>
</person>
</div>`
};
new Vue({
el:"#app",
components:{
person
}
})
- 具名插槽
如果父级给子级传来好多Dom(html元素),而且需要把不同的dom放在子组件不同位置时,就需要给slot起名字,这就是具名插槽。slot元素可以使用特殊属性name来配置如给分发内容。
<slot name="插槽名"></slot>
eg:
//子组件
let person = {
template:`<div>
<hr/>
<p>我是上p</p>
<slot name="s1"></slot>
<p>我是中p</p>
<slot name="s2"></slot>
<p>我是下p</p>
<hr/>
</div>`
};
//父组件
let person = {
template:`<div id="app">
<person>
<div slot="s1">我是div1</div>
<div slot="s2">我是div2</div>
</person>
</div>`
};
new Vue({
el:"#app",
components:{
person
}
});
十.编译作用域
父组件模板的内容在父组件作用域内(父组件对应的对象的作用域)编译;子组件模板的内容在子组件作用域内编译。
eg:
//子组件
let person = {
template:`<div>
<hr/>
<p>我是上p:{{t}}</p>
<p>我是下p</p>
<hr/>
</div>`,
data(){
return{
t:"我是子组件的数据"
}
}
};
//父组件:
let person = {
template:` <div id="app">
<input :value="msg" />
<person v-show="s">
<p>{{msg}}</p>
<div>我是div1:{{msg}}</div>
</person>
</div>`,
};
new Vue({
el:"#app",
data:{
msg:"hi",
s:true
},
components:{
person
}
});