Vue2组件化开发
一、组件化开发的基本使用
①组件注册的基本步骤:
- 创建组件构造器
vue.exetend()
- 注册组件
Vue.componen()
- 使用组件
<div id="app">
<!-- 3.使用组件 -->
<!-- 组件必须放到vue的实例里才有效 -->
<my-cpn></my-cpn>
<my-cpn></my-cpn>
<my-cpn></my-cpn>
</div>
<script src="../vue.js"></script>
<script>
// 1.创建组件构造器对象
const cpnC = Vue.extend({
template: ` <div>
<h2>我是一个组件</h2>
</div>`
})
// 2.注册组件
// 两个参数 一个是注册组件标签名 另一个是组件构造器
Vue.component('my-cpn',cpnC)
const app = new Vue({
el: '#app',
data: {
massage:'你好啊'
}
})
</script>
②全局组件和局部组件:
全局组件:意味着可以在多个vue实例下面使用
<!-- 全局组件的使用 -->
<div id="app">
<cpn></cpn>
</div>
<div id="app2">
<cpn></cpn>
</div>
<script src="../vue.js"></script>
<script>
const cpnC = Vue.extend({
template: ` <div>
<h2>我是一个组件</h2>
</div>`
})
// 注册全局组件,意味着可以在多个vue实例下面使用
Vue.component('cpn',cpnC)
const app = new Vue({
el: '#app',
})
const app2 = new Vue({
el: '#app2',
})
</script>
局部组件: 在一个vue实例里注册的组件是局部组件
<!-- 全局组件的使用 -->
<div id="app">
<!-- 在这里就不能使用<newcpn></newcpn> -->
</div>
<div id="app2">
<newcpn></newcpn>
</div>
<script src="../vue.js"></script>
<script>
const cpnC = Vue.extend({
template: ` <div>
<h2>我是一个组件</h2>
</div>`
})
const app = new Vue({
el: '#app',
})
const app2 = new Vue({
el: '#app2',
// 在一个vue实例里注册的组件是局部组件
components: {
// newcpn 注册组件的标签名
newcpn: cpnC
}
})
</script>
③*父组件和子组件:
<div id="app">
<cpn2></cpn2>
<!-- 这里不能使用cpn1组件 因为cpn1既没有在全局注册,又没有在vue实例里注册 -->
</div>
<script src="../vue.js"></script>
<script>
// 1.创建第一个组件(子组件)
const cpnC1 = Vue.extend({
template: `
<div>
<h2>这是第一个组件</h2>
</div>
`
})
// 2.创建第二个组件(父组件)
const cpnC2 = Vue.extend({
template: `
<div>
<h2>这是第二个组件</h2>
<cpn1></cpn1>
</div>
`,
// 在创建第二个组件时 注册第一个组件并使用
components: {
cpn1:cpnC1
}
})
// 所以可以将vue实例当成最顶层的一个组件 root组件
const app = new Vue({
el: '#app',
components: {
// 在vue实例中注册cpn2组件
cpn2:cpnC2
}
})
</script>
④注册组件的语法糖:
<div id="app">
<cpn1></cpn1>
<cpn2></cpn2>
</div>
<script src="../vue.js"></script>
<script>
// 全局组件注册的语法糖
Vue.component('cpn1',{
template: `
<div>
<h2>我是一个全局组件</h2>
</div>
`
})
// 局部组件的语法糖
const app = new Vue({
el: '#app',
components: {
'cpn2': {
template: `
<div>
<h2>我是一个局部组件</h2>
</div>
`
}
}
})
</script>
⑤组件模板抽离方法.:
第一种写法 用script标签 注意类型必须是text/x-template
<div id="app">
<cpn></cpn>
</div>
<!-- 第一种写法 用script标签 注意类型必须是text/x-template-->
<script type="text/x-template" id="cpn">
<div>
<h2>一个组件</h2>
</div>
</script>
<script src="../vue.js"></script>
<script>
Vue.component('cpn',{
// 这里直接对应id就行
template:'#cpn'
})
const app = new Vue({
el: '#app',
})
</script>
第二种写法 template标签(推荐) :
<div id="app">
<cpn></cpn>
</div>
<!-- 第二种写法 template标签(推荐)-->
<template id="cpn">
<div>
<h2>一个组件</h2>
</div>
</template>
<script src="../vue.js"></script>
<script>
Vue.component('cpn',{
// 这里直接对应id就行
template:'#cpn'
})
const app = new Vue({
el: '#app',
})
</script>
组件是一个单独功能模块的封装
这个模块有属于自己的HTML模板,也应该有属性自己的数据data。
所以组件不可以访问Vue实例里的数据!即使能访问,如果将所有数据都放在vue实例中会显得非常臃肿!
vue组件应该有自己保存数据的地方
⑥*组件的data存放:
组件自己的数据存放在哪里呢?
组件对象也有一个data属性只是这个data属性必须是一一个!函数而且这个函数返回一一个对象,对象内部保存着数据
使用对象保存data可能会出现多个组件共享一个数据,会造成麻烦,而使用函数保存data避免了这个问题
<div id="app">
<cpn></cpn>
</div>
<template id="cpn">
<div>
<h2>{{massage}}</h2>
</div>
</template>
<script src="../vue.js"></script>
<script>
Vue.component('cpn',{
template:'#cpn',
// 组件内部可以有data属性,但是data不能像vue实例一样,data不能是对象
// data只能写成一个函数
data(){
return {
massage:'一个组件'
}
}
})
const app = new Vue({
el: '#app',
})
</script>
⑦简单计数器的组件化写法:
<div id="app">
<cpn></cpn>
<cpn></cpn>
<!-- 多个组件不共享一个data对象 -->
</div>
<template id="cpn">
<div>
<h2>当前计数:{{counter}}</h2>
<button @click="increment">+</button>
<button @click="decrement">-</button>
</div>
</template>
<script src="../vue.js"></script>
<script>
// 1.注册组件
Vue.component('cpn',{
template: '#cpn',
data(){
return {
counter:0
}
},
methods: {
increment() {
this.counter++
},
decrement() {
this.counter--
}
}
})
const app = new Vue({
el: '#app',
data: {
massage:'你好啊'
}
})
</script>
二、父子组件的通信:
子组件不能直接引用父组件或者Vue实例里的数据,但是,在开发中,往往一些数据确实需要从上层传递到下层:比如在一个页面中,我们从服务器请求到了很多的数据。其中一部分数据,并非是我们整个页面的大组件来展示的,而是需要下面的子组件进行展示。
这个时候,并不会让子组件再次发送一个网络请求 ,而是直接让大组件(父组件)将数据传递给小组件(子组件)。
父子组件通信方法:
1.通过props向子组件传递数据
2.通过事件向父组件发送信息
在开发中,Vue实例和子组件间的通信和父子组件间的通信过程是一样的,所以可以将Vue实例看做一个父组件。
①父传子——props:
props的值有两种方式:
1 字符串数组:数组中的字符串就是传递时的名称。
2对象:对象可以设置传递时的类型,也可以设置默认值等。
<!-- 通过对象传递(主要) -->
<div id="app">
<!-- 注意这里要用v-bind 不然会将"movies"当做字符串赋值-->
<cpn :cmovies="movies" :cmassage="massage"></cpn>
</div>
<template id="cpn">
<div>
<ul>
<li v-for="item in cmovies">{{item}}</li>
</ul>
<h2>{{cmassage}}</h2>
</div>
</template>
<script src="../vue.js"></script>
<script>
// 父传子 props
const cpn = {
template:'#cpn',
// props对象写法:
// 这种写法的好处 1.是可以做到类型限制 2.可以提供一些默认值
props: {
cmovies:{
type: Array,
// 类型是对象或者数组时,默认值必须是一个函数
default() {
return []
}
},
cmassage:{
type:String,
// 默认值 在没有传入数据的时候会显示默认值
default:'你好啊',
// 是否必传
required: true
}
}
}
const app = new Vue({
el: '#app',
data: {
massage:'你好啊',
movies:['肖生克的救赎','楚门的世界','时空恋旅人']
},
components: {
// 属性的增强写法
cpn
}
})
</script>
//props对象写法还可以这样写
props: {
cmovies:Array
}
<!-- 通过字符串数组传递 -->
props: ['cmovies','cmassage']