Vue的组件式开发
Vue的组件化开发
作用
将大的系统拆解成小的组件
整个页面逻辑整体进行处理不利于后期的维护和扩展,因此可以将多个小功能块放到一起组成大的页面
也就是将大组件分成小组件,小组件再抽像 其中小组件独立可复用
创建组件
(这里是最基本的创建组件的方式)
1.创建组件构造器 调用Vue.extend()
2.注册组件 Vue.component()(全局组件)
const cpnC = Vue.extend({
template: '<div><h2>标题</h2><h4>内容1</h4></div>'
})
Vue.component('my-cpn',cpnC)
3.使用组件 在Vue示例的作用范围内使用组件
<div id="app">
<my-cpn></my-cpn>
</div>
组件可以在实例中使用,不能拿出来单独使用
全局组件和局部组件
const app = new Vue({
el:'#app',
data:{
message:'nihao',
},
components:{
// cpn:使用组件时的标签名
cpn:cpnC1 //在这里注册的不是全局,只有一个能用
}
})
const app2 = new Vue({
el:'#app2'
})
app2不能使用cpn
父组件和子组件
父组件里面可以有子组件
Vue实例也可以看作是一个组件(root组件),也可以将vue组件看作其他组件的父组件
//第一个组件构造器(子组件)
const cpnC1 = Vue.extend({
template: '<div><h2>标题</h2><h4>内容1</h4></div>',
})
//第二个组件构造器(父组件)
const cpnC2 = Vue.extend({
template: '<div> <h2>hhh</h2> <h4>lalal</h4> <cpn1></cpn1> </div>',
components:{
cpn1:cpnC1
//在这注册之后只能在这个组件里面使用
//会优先在这找
}//在第二个组件构造器中创建组件,
//第一个组件可以放到第二个组件构造器中
})
分离写法
全部在组件扩展器中写非常不方便,而且在js中写很多html语法会非常乱,所以使用分离写法
<!-- 第一种分离写法 -->
<script type="text/x-template" id="cpn">
<div>
<h2>hhh</h2>
<h4>lalal</h4>
</div>
</script>
<!-- 第二种 -->
<template id='cpn2'>
<div>
<h2>hhh</h2>
<h4>lalal</h4>
</div>
</template>
然后在使用id为cpn的部分的时候直接使用template:'#cpn’即可
Vue.component('cpn1',{
template:'#cpn'
})//直接传到extend()中
//这是以语法糖的形式注册全局组件
数据传递
类比vue实例中的存放方式,可以在定义组件的时候设定data和methods
data必须是一个函数,一定要有return,返回的是一个对象(多个组件示例使用的不是一个data对象,这样每次使用的时候调用一次data函数,在栈空间中产生一个新的对象)
Vue.component('cpn1',{
template:'#cpn',
data(){
return {
title: 'abc',
count:1
}
},
methods:{
add(){
this.count++;
}
}
})
数据传递
父传子props
props:{
cmovies:{
type:Array,//限制了类型
default(){
return []
}
},
cm:{
type:String,
default:'aaaaa',//提供默认值
// require:true//要用这些属性必须传这个值,不然会报错
}
},
type进行了类型限制,要求了传入的时候的必须类型 default提供了默认值(类型是对象或者数组的时候默认值必须是一个函数) require:只要使用这个组件就一定要传这个值,否则就会报错
子传递到父$emit
<template id="cpn">
<div>
<button v-for="item in categories" @click="btnClick(item)">{{item.name}}</button> </div>
</template>
(categories是子组件中的数组)
当父组件要拿到子组件中的item时
btnClick(item){
//子组件发射事件
this.$emit('itemclick',item)
//itemclick:事件名称,默认将item传过去
}
然后在使用组件的时候v-on(也可写为@)事件
<div id="app">
<cpn v-on:itemclick="cpnclick"></cpn>
<!--@itemclick也可以,差别是@itemclick未传参时会传event,(itemClick不能写驼峰)-->
<!-- cpnclick是在父组件中的 -->
<!-- 在子组件中通过$emit()来触发事件
在父组件中通过v-on来监听子组件事件 -->
</div>
$children 和 $ref
btnClick(){
console.log(this.$children);//打印的是一个数组,可以通过这个方法直接拿到子组件
for(let c of this.$children){
console.log(c.name);
c.showMessage;//调用子组件中的方法
}
console.log(this.$refs.aaa.name);//拿到子组件
// $refs =>对象类型,默认是一个空的对象 必须在组件中加入ref=''
}
$parent 和 $root
btnClick(){
// 访问父组件
console.log(this.$parent);
console.log(this.$parent.name);
//得到父组件中的元素
// 访问根组件root
console.log(this.$root);
console.log(this.$root.message);
}
插槽slot
组件在不同的地方放置时需要的内容不同,可以替换slot中的内容
可以给slot中加上默认值,没有其他内容将显示默认值
替换内容时可替换多个语句
<div id="app">
<cpn><button>按钮</button></cpn>
<cpn><input type="text"></cpn>
<cpn></cpn><!--使用默认值-->
<cpn>
<h2>hhh</h2>
<h2>hehehe</h2>
</cpn>
<!-- 可以放多个 -->
</div>
<template id='cpn'>
<div>我是组件
<slot><button>按钮</button></slot>
<!-- 组件在不同的地方放置时需要的东西不同 -->
<!-- 要是在这里放置一个默认值,没有的也显示默认值 -->
</div>
</template>
具名插槽
没有指定名字就只替换没有名字的插槽,有名字的要替换需要添加名字
<div id="app">
<cpn><span slot="c">标题</span></cpn>
<cpn><span>我还是组件</span></cpn>
</div>
<template id='cpn'>
<div>我是组件
<slot name="l"><span>左边</span></slot>
<slot name="c"><span>中间</span></slot>
<slot name="r"><span>右边</span></slot>
<slot>我不是组件</slot>
</div>
</template>
作用域插槽
父组件替换插槽的标签,但是内容由子组件来提供
components:{
cpn:{
template:'#cpn',
data(){
return {
pLanguages:['JS','C++','C#','Java']//这是子组件中的数据
}
},
created(){
this.pLanguages.join('-')
}
}
}
对数据有不同的展示需求时,可以先将数据放入插槽
然后在改变展示形式的时候,父组件不能直接拿到数据,因为数据不在vue实例中,需要子组件传过去
<div id="app">
<cpn></cpn>
<cpn>
<!-- 需要获取子组件中的数据 -->
<template #default="slot">
<span>{{slot.data.join(' - ')}}</span>
<!-- join():将字符串用指定的字符连接 -->
</template>
</cpn>
</div>
<template id='cpn'>
<div>
<slot :data="pLanguages">
<ul>
<li v-for="item in pLanguages">{{item}}</li>
</ul>
</slot>
</div>
</template>
将组件抽取出来
其实vue中也是可以写template的,会替代el,但是如果在这里写很多行代码的话会很乱,所以要抽取出来变成组件(还有data、methods也要抽取出来) 然后只需要在vue中用components注册就可以了
我们可以将项目中的多个文件使用webpack进行打包,会自动寻找文件之间的依赖,只需要将main.js进行打包则所有的相关文件都会被打包生成一个文件,然后在html文件中自动引入
自己配置webpack非常复杂,需要使用脚手架(CLI)