table of Contents
Preface
Want to use data to drive the rendering of the component, at this time choose to use dynamic components and implementation
Ideas
Dynamic component
Component has: is attribute, which controls which component to be rendered, that is, when the value of is is the registered value, the component will be rendered in to achieve dynamic component rendering
<component :is="component"></component>
<script>
import child from '@/componets/child'
export default {
componets:{
child
},
data(){
component: 'child'
}
}
</script>
import child from ‘@/componets/child’
But the child needs to be added manually.
At this time, there will be a problem: unneeded components will be loaded. When a component is too large, we don't need to load it, because it will affect our performance.
This is not elegant enough, then we have Is there no way to load different grandchildren components in? Yes, we are going to use asynchronous components
Asynchronous component
In large applications, we may need to divide the application into smaller code blocks and load a module from the server only when needed. To simplify, Vue allows you to define your component as a factory function, which will parse your component definition asynchronously. Vue will trigger the factory function only when the component needs to be rendered, and will cache the result for future re-rendering.
Code
Dynamic component code
Let's write the dynamic components first, the
sub-components
<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>
Asynchronous component code
importComponent is to load components asynchronously: just
import
export default (path, callback) => {
return resolve => require([`@/${
path}`], Module => {
callback && callback(Module)
resolve(Module)
})
}
Sun component
At this time, we only need to create grandchildren under'@/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>
Because the pass value of the grandchildren component, if you use this.&emit to expose to the father, it is very troublesome for the father to expose to the grandfather through this.&emit, so we use
$attrs / $listeners (component pass value) to achieve
Ancestor component
At this point we can use storeData to dynamically render components
<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'
}
]
}
]