1 组件
拥有专属的HTML,CSS和数据的页面独立区域。
优点:便于重用、松散耦合、分工协作
页面由一个个独立的区域组成,封装为组件。即每个页面由多个组件组成
1.创建Vue组件:
1.1先在<template></template>中定义组件的HTML片段,要求<template>内只能有唯一的父元素包裹
1.2创建Vue组件
Vue.component(“组件名”,{
template:”选择器”, //找到页面上一个<template>元素,并监控其中的内容——组件的HTML片段
//data:function(){return {}}的简写
data(){ //每使用一次组件,就调用一次data函数,为当前组件生成一个新data对象
return {
模型变量
}
},
…同new Vue()
})
2.使用组件: 一个组件,其实就是一个可重用的标签!组件名就是标签名
运行时: 用<template>中的HTML片段代替<组件名>标签的位置
2 组件生命周期
一个组件的加载过程
包括: 4个阶段:
1.Create创建:创建组件实例对象,并创建data对象
2.Mount挂载:将组件模板中的元素,绑定后,挂载到DOM树
3.Update:模型变量被更新
4.Destory:要销毁一个组件
生命周期钩子函数: 每个生命周期阶段抛出的事件处理函数
只要希望在某个生命周期阶段执行一项任务时,都要写在该阶段对应的构造函数中。
包括:
beforeCreate: 创建组件实例之前触发
created: 创建组件实例之后,但挂载组件到DOM树之前触发
new Vue($data:模型数据 $el:undefined)
已经可以发送ajax请求
暂时不能执行DOM操作!
beforeMount: 挂载组件到DOM树之前触发
mounted: 挂载组件到DOM树之后触发
new Vue($data:模型数据 $el:虚拟DOM树)
也可以发送ajax请求
可执行DOM操作!
beforeUpdate: 模型数据被更新前触发
updated: 模型数据更新后触发
beforeDestroy: 销毁组件对象之前触发
destroyed: 销毁组件后触发
注意created阶段只在页面重新加载时才再次执行,所以在created阶段发送axios请求后需要添加watch监听函数对地地址栏监听才能保证vue组件的每次跳转都能发送axios请求
3 组件化开发
组件: 拥有专属的HTML,CSS,JS和数据的页面独立区域
组件化开发: 拿到页面后,先划分区域,每个区域都是拥有专有HTML,CSS,数据的独立组件
组件分类:
-
根组件: new Vue({el:"#app", data:{}})
通常一个页面,只有一个根组件 -
全局组件,可在任何位置随意使用的组件
Vue.component(“组件名”,{
template:"#tplxxx",
data:function(){ return {} }
}) -
局部组件,也称子组件,只能用于某个特定父组件内的组件
1)将作为子组件的全局组件,降级为普通的对象, 组件对象名应该是将来的组件标签名改为驼峰命名
2)在父组件中添加components属性:{
子组件对象, …
}
子组件定义位置应该在其父组件之前;Vue会将驼峰命名的子组件,转化为-命名的小写标签名.
4 组件间传参
-
父->子:父组件的模型变量,子组件无权直接使用
解决: “属性下行”
1)子组件var 子组件={ template:"xxx", props:["变量", ... ] //声明一个内外两用的变量 //对外: 父元素可为其绑定数据 //对内: 相当于data:{ 变量 } } <template id="tpl子组件"> {{变量}} <ANY :属性="变量" </template>
2)父组件
<template id="tpl父组件"> <子组件 :变量="模型变量"></子组件> 父组件将自己的模型变量的值传递给子组件的变量属性,子组件就获得了父组件的数据
-
子->父: 事件上行
问题: 子组件无权直接删除父组件中的模型变量的内容
解决: 事件上行
1)父组件:在子组件身上提前定义自定义事件和处理函数:<template id="tpl父组件"> <子组件 @自定义事件="父的处理函数"//不要加() //当有人触发自定义事件时,自动执行父组件中的处理函数,修改父组件自己的数据 父组件{ ... methods:{ 处理函数(形参) {//形参会收到子传来的参数 //操作父组件中的数据 } } }
2)子组件
子组件对象={ … methods:{ 事件处理函数(){ This.$emit(“自定义事件”,要给父的值) } } }
事件上行下行示例
<template id="tplTodoAdd">
<div>
<input v-model="new_task"><button @click="add()">添加</button>
</div>
</template>
<script>
var todoAdd={
template:"#tplTodoAdd",
data:function(){
return { new_task:"" }
},
methods:{
add(){
this.$emit("add",this.new_task);
this.new_task="";
}
}
}
</script>
<template id="tplTodoItem">
<li>{{i+1}} - {{task}}</li>
</template>
<script>
var todoItem={
template:"#tplTodoItem",
props:["task","i"]//对外:父组件可绑定数据
//对内: data:{ task:xx, i:x }
}
</script>
<template id="tplTodoList">
<ul>
<todo-item v-for="(task,i) of tasks" :task="task" :i="i"></todo-item>
</ul>
</template>
<script>
var todoList={
template:"#tplTodoList",
props:["tasks"],//对外: 父组件可绑定数据
//对内: 相当于data:{tasks}
components:{ todoItem }
}
</script>
<template id="tplTodo">
<div>
<h1>待办事项列表</h1>
<todo-add @add="do_add"></todo-add>
<todo-list :tasks="tasks"></todo-list>
</div>
</template>
<script>
Vue.component("todo",{
template:"#tplTodo",
data:function(){
return {//data
tasks:["吃饭","睡觉","打亮亮"]
}
},
components:{
todoAdd,//Vue自动转为todo-add
todoList//Vue自动转为todo-list
},
methods:{
do_add(new_task){
this.tasks.push(new_task);
}
}
})
</script>
<div id="app">
<todo></todo>
</div>
<script>
new Vue({
el:"#app",
data:{}
})
</script>