vue高级组件封装——动态组件&&异步组件

前言

想用数据去驱动组件的渲染,此时就选择用了动态组件和实现

思路

动态组件

component有:is属性,它是控制要渲染那个组件,即当is的值为注册的值,即会把组件渲染进去,实现动态组件渲染

<component :is="component"></component>
<script>
import child from '@/componets/child'
export default {
    
    
	componets:{
    
    
		child
	},
	data(){
    
    
		component: 'child'
	}
}
</script>

import child from ‘@/componets/child’

但是 child 需要手动添加,
此时会有个问题:会加载不需要的组件出来,当一个组件过大,我们不需要把它加载出来,因为会影响到我们的性能
这样子不够优雅,那我们有没有办法加载不同的孙组件进来?有,即我们就要使用异步组件

异步组件

在大型应用中,我们可能需要将应用分割成小一些的代码块,并且只在需要的时候才从服务器加载一个模块。为了简化,Vue 允许你以一个工厂函数的方式定义你的组件,这个工厂函数会异步解析你的组件定义。Vue 只有在这个组件需要被渲染的时候才会触发该工厂函数,且会把结果缓存起来供未来重渲染。

代码

动态组件代码

我们先写出动态组件出来
子组件

<template>
	<div class="m-detail">
		<component :is="item.component" v-for="(item, index) in detailArr" :key="index" :data="item.data"
		v-bind="$attrs" v-on="$listeners">
		</component>
	</div>
</template>

<script>
import importComponent from '@/utils/importComponent'
export default {
    
    
	title: 'store',
	props: {
    
    
		detailData: {
    
    
			type: Array,
			default() {
    
    
				return []
			}
		}
	},
	data() {
    
    
		return {
    
    }
	},
	computed: {
    
    
		detailArr() {
    
    
			const arr = []
			for (var i = 0; i < this.detailData.length; i++) {
    
    
				(i => {
    
    
					const item = this.detailData[i]
					var _type = this.detailData[i].type
					const detailMap = {
    
    
						BlockList: {
    
    
							products:item.products
						},
						FloatList: {
    
    
							products:item.products
						}
					}
					const obj = {
    
    
						component: importComponent(`components/Store/${
      
      _type}.vue`),
						data: {
    
    
							...detailMap[_type]
						}
					}
					arr.push(obj)
				})(i)
			}
			return arr
		}
	}
}
</script>

<style lang="less" scoped>
.m-detail {
    
    
	min-height: 400px;
}
</style>

异步组件代码

importComponent就是异步加载组件:
引入即可

export default (path, callback) => {
    
    
	return resolve => require([`@/${
      
      path}`], Module => {
    
    
		callback && callback(Module)
		resolve(Module)
	})
}

孙组件

此时我们只需要在‘@/components/Store/’下面建立孙组件;

<template>
	<view class="bank-card">
		<view class="item text-center">
			<text class="text-gray cuIcon-roundleftfill-copy roundleftfil" @click="hanldSwiper('left')"></text>
			<text class="text-gray cuIcon-roundrightfill roundrightfill" @click="hanldSwiper('right')"></text>
			<view class="item-title font-weight">图片</view>
			<swiper class="swiper" :current="current">
				<swiper-item v-for="(item,index) in data.products" :key="index">
					 <view class="swiper-item uni-bg-red" :style="`background-image: url(${item.productPic});`"></view>
				</swiper-item>
			</swiper>
			<view>
				<text class="spot">123</text>
				<text class="spot">123</text>
				<text class="spot">123</text>
			</view>
			<view class="bg-grey flex justify-between footer">
				<view class="text-center">个人邀请</view>
				<text class="line"></text>
				<view @click="posterShare()">海报分享</view>
			</view>
		</view>
	</view>
</template>

<script>
export default{
    
    
	name: 'BankCard',
	props: {
    
    
		data: {
    
    
			type: Object
		}
	},
	data(){
    
    
		return{
    
    
			current:0
		}
	},
	methods: {
    
    
		hanldSwiper(item){
    
    
			if(item == 'left' && this.current > 0){
    
    
				this.current -= 1
				return
			}
			if(item == 'right' && this.current < this.data.products.length-1){
    
    
				this.current += 1
				return
			}
		},
		posterShare(){
    
    
			this.$emit('toShare','val')
		}
	}
}
</script>

<style lang="less">
.bank-card{
    
    
	.nav{
    
    
		margin: 30upx 0;
		.title{
    
    
			font-weight: 700;
			font-size: 32upx;
		}
	}
	.item{
    
    
		width: 100%;
		height: 500upx;
		border: 1px solid #CCCCCC;
		display: inline-block;
		margin-right: 30upx;
		border-radius: 30upx;
		padding: 30upx 0;
		position: relative;
		overflow: hidden;
		.item-title{
    
    
			margin-bottom: 30upx;
			color:#000000
		}
		.roundleftfil{
    
    
			position: absolute;
			left:80upx;
			top:180upx;
			font-size: 50upx;
		}
		.roundrightfill{
    
    
			position: absolute;
			right:80upx;
			top:180upx;
			font-size: 50upx;
		}
		.footer{
    
    
			width: 100%;
			height: 60upx;
			line-height: 60upx;
			position: absolute;
			bottom: 0;
			>view {
    
    
				width: 49%;
			}
		}
	}
	.spot{
    
    
		margin:0 10upx;
		vertical-align: center;
	}
}
.swiper{
    
    
	width: 340upx;
	height: 240upx;
	margin:auto;
	border-radius: 30upx;
	overflow: hidden;
	.swiper-item{
    
    
		width: 100%;
		height: 100%;
		background-size: cover;
		background-repeat: round;
	}
}
</style>

因为祖孙 组件的传值,如果使用this.&emit向父亲暴露,父亲再通过this.&emit向爷爷暴露是很麻烦的,因此我们使用
$attrs / $listeners(组件传值)来实现

祖组件

此时我们就可以使用storeData来动态渲染组件了

<Store :detailData="storeData" @toShare='toShare'></Store>

this.storeData = [
			{
    
    
				type: 'BlockList',
				products:[
					{
    
    
						newId:'13',			productPic:'https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=229065980,2895464780&fm=26&gp=0.jpg'
					},
					{
    
    
						newId:'14',
						productPic:'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2350817201,1137116540&fm=26&gp=0.jpg'
					},
					{
    
    
						newId:'15',					productPic:'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.zcool.cn%2Fcommunity%2F031156f5aeb21a8a801207fa1bc9eac.jpg&refer=http%3A%2F%2Fimg.zcool.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1618385640&t=bc51aaaa2dc72dd8e565807935529732'
					}
					
				]
			}
		]

猜你喜欢

转载自blog.csdn.net/weixin_43236062/article/details/114887062