Vue.js组件化开发
组件化开发
基本概念
vue.js 有两大法宝,一个是数据驱动,另一个就是组件化
什么叫组件化
所谓组件化,就是把页面拆分成多个组件,每个组件依赖的 CSS、JS、模板、图片等资源放在一起开发和维护。
因为组件是资源独立的,所以组件在系统内部可复用,组件和组件之间可以嵌套,如果项目比较复杂,可以极大简化代码量,并且对后期的需求变更和维护也更加友好。
组件化思想
1.如果我们将一个页面中所有的处理逻辑全部放在一起,处理起来就会变得非常复杂,而且不利于后续的管理以及扩展.
2.但如果,我们讲一个页面拆分成一个个小的功能块,每个功能块完成属于自己这部分独立的功能,那么之后整个页面的管理和维护就变得非常容易了.
参考:组件基础
认识组件
根组件
被挂载管理的元素块就是一个根组件。在此根组件中可以嵌套多个子组件,根组件一般来说只需要一个
<body>
<div id='app'>
</div>
<script src="vue.js"></script>
<script>
const app = new Vue({
el:'#app',
})
</script>
</body>
子组件
子组件即是被嵌套在根组件中的组件,子组件可复用,并且数据都是相互独立的。
子组件拥有根组件所拥有的所有属性
组件声明
组件的使用分三个步骤:
1.创建组件构造器
2.注册组件
3.使用组件
1.调用Vue.extend()方法创建组件构造器
2.调用Vue.component()方法注册组件
3.在Vue实例的作用范围内使用组件
全局组件
全局组件会自动进行注册,任何Vue的实例都能进行使用。
使用Vue.component("name",{})对其进行声明并注册。
<body>
<div id='app'>
<!-- 3.使用组件 -->
<cpn></cpn>
</div>
<script src="vue.js"></script>
<script>
// 1.创建组件构造器对象
const cpnC = Vue.extend({
template: `
<div>
<h2>第一个组件</h2>
</div>`
})
// 2.注册组件 (全局组件)
Vue.component('cpn',cpnC);
const app = new Vue({
el:'#app',
})
</script>
</body>
局部组件
局部组件在Vue实例下使用components进行注册,它只能在当前实例使用
<body>
<div id='app'>
<!-- 3.使用组件 -->
<cpn></cpn>
</div>
<script src="vue.js"></script>
<script>
// 1.创建组件构造器对象
const cpnC = Vue.extend({
template:`
<div>
<h2>第一个组件</h2>
</div>`
})
const app = new Vue({
el:'#app',
// 2.注册组件(局部组件)
components: {
cpn:cpnC,
}
})
</script>
</body>
组件语法糖写法
这种写法居多
<body>
<div id='app'>
<cpn1></cpn1>
<cpn2></cpn2>
</div>
<script src="vue.js"></script>
<script>
// 全局语法糖
Vue.component('cpn2',{
template:`
<div>
<h1>第一个组件</h1>
</div>`
})
const app = new Vue({
el:'#app',
components: {
// 局部语法糖
cpn1: {
template: `
<div>
<h1>第一个组件</h1>
</div>
`
}
}
})
</script>
</body>
组件模板抽离写法
如果在定义组件时在template属性中写HTML代码,是不太友好的,你可以将模板抽离出来。
而且这个方法是用的最多。
使用<template>标签配合id属性将其作为子组件模板:(以下抽离包括全局和局部)
<body>
<div id='app'>
<cpn1></cpn1>
<cpn2></cpn2>
</div>
<template id='cpn1'>
<div>
<h1>组件抽离</h1>
</div>
</template>
<template id='cpn2'>
<div>
<h1>组件抽离</h1>
</div>
</template>
<script src="vue.js"></script>
<script>
// 全局抽离写法
Vue.component('cpn1', {
template:'#cpn1'
})
const app = new Vue({
el:'#app',
// 局部抽离写法
components: {
cpn2: {
template:'#cpn2',
}
}
})
</script>
</body>
子组件中的data
上面已经说过,子组件可以拥有data/methods/computed/watch/filter等对象。
但是需要注意的是子组件的data必须是一个函数,且必须返回一个Object。
这是因为每个子组件是相互独立的,每一个组件实例都有属于组件的状态。
如果组件中的data是一个对象,那么组件进行多次调用的时候就会互相影响。
所以子组件中的data必须是一个函数,因为函数调用时会重新申请内存,返回一个全新的Object。
<body>
<div id='app'>
<cpn1></cpn1>
<cpn2></cpn2>
</div>
<template id='cpn1'>
<div>
<h1>{{title}}</h1>
<p>{{content}}</p>
</div>
</template>
<template id='cpn2'>
<div>
<h1>{{title}}</h1>
<p>{{content}}</p>
</div>
</template>
<script src="vue.js"></script>
<script>
// 全局注册的组件
Vue.component('cpn1', {
template:'#cpn1',
// data必须是函数
data() {
return {
title:'我是标题11',
content:'我是内容11',
}
}
})
const app = new Vue({
el: '#app',
// 局部注册的组件
components: {
cpn2: {
template: '#cpn2',
// data必须是函数
data() {
return {
title: '我是标题22',
content: '我是内容22',
}
}
}
}
})
</script>
</body>
组件通信
通信的意义
组件之间的通信是十分有必要的,当Vue项目启动后,父组件获取到了一些数据,它将如何把这些数据分发到子组件上。
再比如,子组件上产生了一个新数据,它将如何把该数据交由父组件?
父传子(props)
父组件向子组件传递数据时,则通过
props进行传递。
接收值在父组件模板中采用 - 分割命名,在props中采用驼峰式,在子组件模板中进行使用时采用与props中同样的命名方式
这是因为 - 分割命名方式不是Js的合法变量名,如果props中采用 - 来进行命名,子组件模板在使用时将查询不到该变量名
总结一句话:如果props中采用了驼峰标识(例如:cInfo),那么在父组件中使用必须用 - 来分割(例如:c-info)
<body>
<!-- 父组件模板 -->
<div id='app'>
<!-- 定义接收:一定要使用 - 来分割,不能使用驼峰标识 -->
<cpn :c-message='message' :c-moves='moves' :c-info='info'></cpn>
</div>
<!-- 子组件模板 -->
<template id='cpn'>
<!-- 在子组件中就能使用 props 中接收的变量来渲染 -->
<div>
<h1>{{cMessage}}</h1>
<ul>
<li v-for='item in cMoves'>{{item}}</li>
</ul>
{{cMoves}}
<h2>{{cInfo.name}}</h2>
</div>
</template>
<script src="vue.js"></script>
<script>
// 父组件
const app = new Vue({
el: '#app',
data: {
message: '父组件的message',
moves:['父组件1','父组件2','父组件3'],
info: {
name:'hollow',
age:18,
height:1.88,
}
},
components: {
// 子组件
cpn: {
template: '#cpn',
// 使用props来接收父组件传过来的三个变量
props: {
// 接受收的时候可以随便取名
cMessage: {
type:String,
default:'null',
required:true,
},
cMoves: {
type:Array,
default:[],
},
cInfo: {
type:Object,
default:{},
}
}
}
}
})
</script>
</body>
props中的其他参数
在上述中我在props中添加了其他参数
| 键 | 值 | 描述 |
|---|---|---|
| type | String、Array、Object等 | 定义接收的数据类型 |
| default | 默认值 | 如果定义了default,那么接收到的就是默认值 |
| required | true/false | 定义是否必须接收参数,不写默认false |
子传父($emit)
1.在子组件中创建自定义函数
2.在自定义函数使用$emit,把需要修改或者传递的值或方法给父组件
3.父组件接收子组件传递过来的自定义函数
4.父组件通过接收的值或方法来进行下一步操作
<body>
<div id='app'>
<!-- 3.父组件接收子组件传递过来的自定义函数 -->
<cpn @item-click='cpnClick'></cpn>
</div>
<template id='cpn'>
<div>
<!-- 1.在子组件中创建自定义函数 -->
<button v-for='item in categories' @click='btnClick(item)'>{{item.name}}</button>
</div>
</template>
<script src="vue.js"></script>
<script>
const app = new Vue({
el:'#app',
components: {
cpn: {
template:'#cpn',
data() {
return {
categories:[
{id:'aaa',name:'热门推荐'},
{id:'bbb',name:'事件数码'},
{id:'ccc',name:'家用家电'},
{id:'ddd',name:'电脑办公'},
]
}
},
methods: {
// 2.自定义函数:使用$emit,把需要修改或者传递的值或方法给父组件
btnClick(item) {
this.$emit('item-click',item);
}
}
},
},
// 4.父组件通过接收的值或方法来进行下一步操作
methods: {
cpnClick(item) {
console.log('cpnclick',item);
}
}
})
</script>
</body>
组件访问
父访问子($children)
有的时候我们想直接通过父组件拿到子组件这个对象,调用其下面的某一个方法,可以使用$children属性完成操作。
<body>
<div id='app'>
<cpn></cpn>
<button @click='btnClick'>app按钮</button>
</div>
<template id='cpn'>
<div>
<h1>我是子组件</h1>
</div>
</template>
<script src="vue.js"></script>
<script>
const app = new Vue({
el: '#app',
methods: {
btnClick() {
// 使用$children获取子组件的内容进行操作
console.log(this.$children);
this.$children[0].show();
console.log(this.$children[0].name);
}
},
components: {
cpn: {
template:'#cpn',
methods: {
show() {
console.log('showMessage');
}
},
data() {
return {
name:'我是子组件',
}
},
}
}
})
</script>
</body>
父访问子(refs)
上述的访问方法并不常用,因为父组件非常依赖索引值来访问子组件。
使用$refs来访问子组件就方便的多,我们需要给子组件取一个名字,再用父组件进行调用,这个是非常常用的手段。
<body>
<div id='app'>
<!-- 设置ref属性 -->
<cpn ref="ref1"></cpn>
<button @click='btnClick'>app按钮</button>
</div>
<template id='cpn'>
<div>
<h1>我是子组件</h1>
</div>
</template>
<script src="vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
},
methods: {
btnClick() {
// 通过 $refs 来获取子组件的内容进行操作
this.$refs.ref1.show();
console.log(this.$refs.ref1.name);
}
},
components: {
cpn: {
template:'#cpn',
methods: {
show() {
console.log('showMessage');
}
},
data() {
return {
name:'我是子组件',
}
},
}
}
})
</script>
</body>
子访问父(\(parent)和\)(root)
如果在子组件中想拿到父组件的对象,使用$parent即可,如果存在多层嵌套,它只会拿自己上一层。
如果存在三级或以上嵌套,可以直接使用$root来访问根组件。与$parent使用相同,但是它是具体的一个对象,而并非Array。
下面代码我一起演示了$parent和$root
<body>
<!-- 根组件 -->
<div id='app'>
<cpn></cpn>
</div>
<!-- 子组件 -->
<template id='cpn'>
<!-- 子组件里挂载子子组件 -->
<ccpn></ccpn>
</template>
<!-- 子子组件 -->
<template id='ccpn'>
<div>
<h2>我是子子组件</h2>
<button @click='btnClick'>按钮</button>
</div>
</template>
<script src="vue.js"></script>
<script>
const app = new Vue({
// 根组件
el: '#app',
data: {
message:'你好啊',
name:'我是根的name',
},
components: {
// 子组件
cpn: {
template:'#cpn',
data() {
return {
name:'我是cpn的name',
}
},
// 子组件里注册组件,也就是子子组件
components: {
ccpn: {
template:'#ccpn',
methods: {
btnClick() {
// 通过this.$parent和this.$root访问父组件,也可以通过.的方式获取变量和方法
console.log('父组件是:',this.$parent);
console.log(this.$parent.name);
console.log('根组件是',this.$root);
console.log(this.$root.name);
}
},
}
}
}
}
})
</script>
</body>
下一篇 webpack前端模块化打包工具
本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图,其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。

浙公网安备 33010602011771号