一.组件
1.什么是组件
拥有专属的HTML和CSS+JS+数据的可重用的页面独立功能区域
2.为什么使用组件
因为重用!
3.何时使用组件
只要页面中出现可能反复使用的功能区域,都要封装为组件,再反复使用组件
4.如何使用:2步
(1).定义组件
Vue.component("组件名",{//强调:组件名名不要用驼峰命名,多个英文单词要用-分割
//和new Vue()中几乎完全一样!每个组件其实就是new Vue()一个功能完全相同的小的分身而已,new Vue()负责监控整个页面,而组件负责监控自己负责的小范围区域而已,没有el了,取而代之的是一个
//组件的template中只能有一个唯一的父元素包裹
template:`HTML代码片段`, //因为这里是为将来反复使用这个组件定义的统一样式模板,将来使用这个组件时,反复创建的副本,和这里的HTML片段完全一样!
//data不再是一个对象,而变成一个可反复调用的函数
data(){ //将来每使用一次这个组件,就调用一次data()函数
return { //每次调用data()函数,就返回一个新创建的模型对象给当前这个组件的一个副本专属----保证组件虽然可反复使用,但是数据是彼此隔离,互不影响!
组件模板中所需的变量
}
},
//以下内容和new Vue()就完全一样
methods:{....}
conputed:{....}
生命周期钩子函数
.... ....
})
(2).如何使用自定义的组件
组件其实就是一个可反复使用的自定义HTML元素而已,组件名其实就是元素的标签<组件名></组件名>
5.原理
(1).new Vue()扫描页面时,碰到不认识的元素标签,就会去Vue家找有没有同名的自定义组件
(2).如果找到同名的自定义组件,则先用组件对象的templateHTML片段代替页面上组件元素的位置
(3).自动调用一次data()函数,为本次组件的副本创建一个全新的专属的模型对象副本--保证这个组件副本中操作模型变量,不影响其他组件副本中的数据
(4).最后为这次组件副本创建一个小快递员对象,保持组件范围内模型对象与界面之前的同步
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="js/vue.js"></script>
<script>
// 想定义一个计数器组件,点+-号,可更改数量
// 1.创建组件对象,定义组件名称,多个英文单词用-分割
Vue.component("my-counter", {
// 每个组件的制作过程和new Vue()制作过程几乎完全一样
// 2.定义界面模板:template
// 要求唯一父元素包裹
// 本例中:两个button可点击执行+-计算,所以@click标记
template: `<div>
<button @click="minus">-</button><span>{{n}}</span><button @click="add">+</button>
</div>`,
// 3.创建模型对象
// 本例中:共需要1个变量n
data() {//将来会被自动反复调用
return {//反复创建模型对象副本-这里相当于new Vue()中的data对象
n: 1
}
},
// 其余的和new Vue()就完全一样了
//本例中共需要minus和add两个函数
methods: {
minus() { if (this.n > 1) { this.n-- } },
add() { this.n++ }
}
})
</script>
</head>
<body>
<div id="app">
<ul>
<li>
<my-counter></my-counter>
</li>
<li>
<my-counter></my-counter>
</li>
<li>
<my-counter></my-counter>
</li>
</ul>
</div>
<script>
var vm = new Vue({
el: "#app"
})
</script>
</body>
</html>
二.组件化开发
1.什么是组件化开发
一个HTML页面其实都是由多个组件拼接起来的,拿到页面后,第一件事应该是划分组件区域,然后在由多个人分头编写一个页面的不同区域,最后再将每个编写的组件拼接到一起形成一个HTML页面展示给我们看!
2.为什么组件化开发
(1).便于大项目的分工协作,并行开发,效率高!
(2).松耦合!组件与组件之间相对独立,互不影响,一个出错,不影响大家!
3.何时使用
几乎所有项目都采用将组件化开发!
4.如何
(1).拿到页面图片,划分组件结构,2个依据
a.按功能
b.按是否重用
(2).划分了几个组件,就要创建几个独立的js文件,在独立的js文件中定义组件对象
(3).将所有组件引入到HTML页面中,由new Vue()经过反复扫描和替换过程,将所组件内容最终拼接到一起给用户显示
5.子组件
(1)问题:Vue.component()创建的组件,称为全局组件,可在页面中任何位置随意使用,
但是有些组件明显不能超过父组件的范围使用
(2).解决:如果限制一个子组件只能在父组件范围内使用,就应该定义子组件,而不应该
使用全局组件
(3).如何使用:2步
a.定义子组件对象:
1).子组件对象的内容应该和定义全局组件内容的要求完全一致!
2).但是不能用Vue.component()创建,应该仅仅保存在一个普通的js变量里
3).变量名应该是子组件名称的驼峰命名方式!
b.必须在父组件对象中的components属性中,将子组件对象包含进来.
父组件对象:{
template:`........`,
data(){
return {....}
},
.. ..,
components:{驼峰命名的组件变量名,... ...}
}
(4).结果:凡是出现在这个父组件components中的子组件对象,就只能在当前父组件内使用,出了当前父组件使用,会报错!
(5).问题:子组件定义时的变量名时驼峰命名,在父组件模板中使用子组件标签时,应该用驼峰?还是-
(6).答:用-分割多个单词!因为components会自动将驼峰命名的组件变量名,翻译为-分割的名字
(7).强调:将多个子组件引入到页面时,组件间必须在父组件之前引入!
6.不考虑数据情况下,将待办事件列表拆分为父子组件
todo-add.js
var todoAdd={
template:`<div>
<input><button>+</button>
</div>`
}
todo-item.js
var todoItem={
template:`<li>
1 吃饭 <a href="javascript:;">×</a>
</li>`
}
todo-list.js
var todoList={
template:`<ul>
<todo-item></todo-item>
<todo-item></todo-item>
<todo-item></todo-item>
</ul>`
components:{todoItem}
}
todo.js
Vue.compon("todo",{
template:`<div>
<h1>代办事项列表</h1>
<todo-add></todo-add>
<todo-list><todo-list>
</div>`,
components:{todoAdd,todlList}
})
todo.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="js/vue.js"></script>
<script src="4_todo-add.js">
//var todoAdd={ ... }
</script>
<script src="4_todo-item.js">
//var todoItem={ ... }
</script>
<script src="4_todo-list.js">
//var todoList={
// ...
// components:{ todoItem }
//}
</script>
<script src="4_todo.js">
//Vue.component("todo",{
// ...
// components:{ todoAdd, todoList }
//})
</script>
</head>
<body>
<div id="app">
<todo></todo>
</div>
<script>
new Vue({
el:"#app"
})
</script>
</body>
</html>
7.组件间数据传递
(1).问题:vue组件开发中,子组件无权直接使用父组件的变量!
(2).解决:采用专门的方法,让父组件将自己的一个变量传递给子组件才行
(3).如何:(父传子)2步:
a.父亲放数据:父组件在template中
<子组件 :自定义属性="父要给予的变量">
父把自己的一个变量值放到孩子身上一个指定名称的兜里
b.孩子接收数据:子组件对象中:
子组件对象:{
props:["自定义属性"],//孩子从父亲放东西的同名兜里取出父给的数据继续使用
template:`...子组件的模板中使用自定义属性名等效于使用父组件的变量值...`
}
强调:
1).通常为了保证一个东西在程序中只有一个统一的名称,便于维护,避免歧义,都在将父组件变量名和自 定义属性起相同的名字,但不是必须
2).props中的属性名 VS data中的变量
i.相同点:都即可用于HTML中的绑定和指令,又可用于js中通过this.xxx访问
ii.不同点:data中变量的值是组件内定义的,props中的属性值是外部给的!
8.实例:实现代办事项列表的任务列表和添加功能
todo.js
Vue.component("todo",{
template:`<div>
<h1>代办事项列表</h1>
<todo-add :tasks="tasks"></todo-add>
<todo-list :tasks="tasks"></todo-list>
<div>`,
data(){
return {
tasks:["吃饭","睡觉","打豆豆"]
}
},
components: { todoAdd,todoList}
})
todo-add.js
var todoAdd={
props:["tasks"],
template:`<div>
<input v-model="newTask"><button @click="add">+</button>
</div>`,
data(){
return {
newTask:""
}
},
methods:{
add() {
this.tasks.push(this.newTask);
//添加完新任务后,清空文本框
this.newTask="";//双向绑定
}
}
}
todo-lsit
var todoList={
props:["tasks"],
template:`<ul>
<todo-item v-for="(t,i) of tasks" :key="i" :task="t" :i="i">
</ul>`,
components:{todoTtem}
}
todo-item.js
var todoItem={
props:["task","i"],
template:`<li>
{{i+1}} {{task}} <a href="javascript:;">×</a>
</li>`
}
todo.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="js/vue.js"></script>
<script src="4_todo-add.js">
//var todoAdd={ ... }
</script>
<script src="4_todo-item.js">
//var todoItem={ ... }
</script>
<script src="4_todo-list.js">
//var todoList={
// ...
// components:{ todoItem }
//}
</script>
<script src="4_todo.js">
//Vue.component("todo",{
// ...
// components:{ todoAdd, todoList }
//})
</script>
</head>
<body>
<div id="app">
<todo></todo>
</div>
<script>
new Vue({
el:"#app"
})
</script>
</body>
</html>