[Improvement] Sku: improve render performance (#550)

This commit is contained in:
neverland 2018-01-19 10:02:25 +08:00 committed by GitHub
parent 1c1fb7342b
commit ddc113a0f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 748 additions and 239 deletions

View File

@ -50,7 +50,7 @@
"vue": ">= 2.5.0"
},
"devDependencies": {
"autoprefixer": "^7.2.4",
"autoprefixer": "^7.2.5",
"avoriaz": "2.0.0",
"babel-cli": "^6.26.0",
"babel-core": "^6.26.0",
@ -63,10 +63,10 @@
"chai": "^4.1.2",
"codecov": "^3.0.0",
"cross-env": "^5.1.3",
"css-loader": "^0.28.8",
"css-loader": "^0.28.9",
"dependency-tree": "^5.12.0",
"eslint": "^4.15.0",
"eslint-plugin-vue": "^4.1.0",
"eslint-plugin-vue": "^4.2.0",
"extract-text-webpack-plugin": "3.0.2",
"fast-vue-md-loader": "^1.0.3",
"friendly-errors-webpack-plugin": "^1.6.1",
@ -89,7 +89,7 @@
"precss": "2.0.0",
"progress-bar-webpack-plugin": "^1.10.0",
"rimraf": "^2.5.4",
"shelljs": "^0.7.8",
"shelljs": "^0.8.0",
"sinon": "^2.4.1",
"sinon-chai": "^2.12.0",
"style-loader": "^0.19.1",
@ -97,15 +97,15 @@
"url-loader": "^0.6.2",
"vant-doc": "1.0.1",
"vue": "^2.5.13",
"vue-loader": "^13.6.2",
"vue-loader": "^13.7.0",
"vue-router": "^3.0.1",
"vue-sfc-compiler": "^0.0.7",
"vue-sfc-compiler": "^0.0.8",
"vue-style-loader": "^3.0.0",
"vue-template-compiler": "^2.5.13",
"vue-template-es2015-compiler": "^1.6.0",
"webpack": "^3.10.0",
"webpack-bundle-analyzer": "^2.9.1",
"webpack-dev-server": "2.9.7",
"webpack-bundle-analyzer": "^2.9.2",
"webpack-dev-server": "2.11.0",
"webpack-merge": "^4.1.1"
}
}

View File

@ -2,7 +2,12 @@
<popup v-model="show" v-if="!isSkuEmpty" position="bottom" lock-on-scroll prevent-scroll>
<div class="van-sku-container">
<div class="van-sku-layout">
<slot name="sku-header" :skuEventBus="skuEventBus" :selectedSku="selectedSku" :selectedSkuComb="selectedSkuComb">
<slot
name="sku-header"
:sku-event-bus="skuEventBus"
:selected-sku="selectedSku"
:selected-sku-comb="selectedSkuComb"
>
<sku-header
:sku-event-bus="skuEventBus"
:selected-sku="selectedSku"
@ -12,7 +17,7 @@
/>
</slot>
<div class="van-sku-body" :style="bodyStyle">
<slot name="sku-group" :selectedSku="selectedSku" :skuEventBus="skuEventBus">
<slot name="sku-group" :selected-sku="selectedSku" :sku-event-bus="skuEventBus">
<div v-if="hasSku" class="van-sku-group-container van-hairline--bottom">
<div
v-for="(skuTreeItem, index) in skuTree"
@ -35,8 +40,14 @@
</div>
</div>
</slot>
<slot name="extra-sku-group" :skuEventBus="skuEventBus"/>
<slot name="sku-stepper" :skuEventBus="skuEventBus" :selectedSku="selectedSku" :selectedSkuComb="selectedSkuComb" :selectedNum="selectedNum">
<slot name="extra-sku-group" :sku-event-bus="skuEventBus"/>
<slot
name="sku-stepper"
:sku-event-bus="skuEventBus"
:selected-sku="selectedSku"
:selected-sku-comb="selectedSkuComb"
:selected-num="selectedNum"
>
<sku-stepper
ref="skuStepper"
:sku-event-bus="skuEventBus"
@ -60,7 +71,7 @@
/>
</slot>
</div>
<slot name="sku-actions" :skuEventBus="skuEventBus">
<slot name="sku-actions" :sku-event-bus="skuEventBus">
<sku-actions
:sku-event-bus="skuEventBus"
:buy-text="buyText"
@ -75,21 +86,21 @@
<script>
/* eslint-disable camelcase */
import Vue from 'vue';
import Popup from '../../popup';
import Toast from '../../toast';
import SkuHeader from '../components/SkuHeader';
import SkuRow from '../components/SkuRow';
import SkuRowItem from '../components/SkuRowItem';
import SkuStepper from '../components/SkuStepper';
import SkuMessages from '../components/SkuMessages';
import SkuActions from '../components/SkuActions';
import Popup from '../popup';
import Toast from '../toast';
import SkuHeader from './components/SkuHeader';
import SkuRow from './components/SkuRow';
import SkuRowItem from './components/SkuRowItem';
import SkuStepper from './components/SkuStepper';
import SkuMessages from './components/SkuMessages';
import SkuActions from './components/SkuActions';
import {
isAllSelected,
getSkuComb,
getSelectedSkuValues
} from '../utils/skuHelper';
import { LIMIT_TYPE } from '../constants';
import { create } from '../../utils';
} from './utils/skuHelper';
import { LIMIT_TYPE } from './constants';
import { create } from '../utils';
const { QUOTA_LIMIT } = LIMIT_TYPE;
@ -107,13 +118,19 @@ export default create({
},
props: {
sku: Object,
goods: Object,
value: Boolean,
buyText: String,
goodsId: [Number, String],
stepperTitle: String,
hideStock: Boolean,
resetStepperOnHide: Boolean,
disableStepperInput: Boolean,
initialSku: {
type: Object,
default: () => ({})
},
sku: Object,
quota: {
type: Number,
default: 0
@ -122,24 +139,18 @@ export default create({
type: Number,
default: 0
},
hideStock: Boolean,
showAddCartBtn: {
type: Boolean,
default: true
},
buyText: String,
stepperTitle: String,
bodyOffsetTop: {
type: Number,
default: 200
},
resetStepperOnHide: Boolean,
disableStepperInput: Boolean,
messagePlaceholderMap: {
type: Object,
default: () => ({})
},
value: Boolean
}
},
data() {
@ -192,19 +203,19 @@ export default create({
maxHeight: maxHeight + 'px'
};
},
isSkuCombSelected() {
return isAllSelected(this.sku.tree, this.selectedSku);
},
// sku
isSkuEmpty() {
for (var key in this.sku) {
if (Object.prototype.hasOwnProperty.call(this.sku, key)) return false;
}
return true;
return Object.keys(this.sku).length === 0;
},
hasSku() {
return !this.sku.none_sku;
},
selectedSkuComb() {
if (!this.hasSku) {
return {
@ -217,13 +228,14 @@ export default create({
}
return null;
},
skuTree() {
return this.sku.tree || [];
}
},
created() {
var skuEventBus = new Vue();
const skuEventBus = new Vue();
this.skuEventBus = skuEventBus;
skuEventBus.$on('sku:close', this.handleCloseClicked);
@ -250,19 +262,23 @@ export default create({
}
});
},
getSkuMessages() {
return this.$refs.skuMessages ? this.$refs.skuMessages.getMessages() : {};
},
getSkuCartMessages() {
return this.$refs.skuMessages
? this.$refs.skuMessages.getCartMessages()
: {};
},
validateSkuMessages() {
return this.$refs.skuMessages
? this.$refs.skuMessages.validateMessages()
: '';
},
validateSku() {
if (this.selectedNum === 0) {
return this.$t('unavailable');
@ -276,9 +292,11 @@ export default create({
return this.$t('spec');
}
},
handleCloseClicked() {
this.show = false;
},
handleSkuSelected(skuValue) {
// sku
this.selectedSku =
@ -292,9 +310,11 @@ export default create({
selectedSkuComb: this.selectedSkuComb
});
},
handleNumChange(num) {
this.selectedNum = num;
},
handleOverLimit({ action, limitType, quota, quotaUsed }) {
if (action === 'minus') {
Toast(this.$t('least'));
@ -308,12 +328,15 @@ export default create({
}
}
},
handleAddCartClicked() {
this.handleBuyOrAddCart('add-cart');
},
handleBuyClicked() {
this.handleBuyOrAddCart('buy-clicked');
},
handleBuyOrAddCart(type) {
const error = this.validateSku();
if (error) {

View File

@ -1,7 +1,17 @@
<template>
<div class="van-sku-actions">
<van-button v-if="showAddCartBtn" bottom-action @click="onAddCartClicked">{{ $t('cart') }}</van-button>
<van-button type="primary" bottom-action @click="onBuyClicked">{{ buyText || $t('buy') }}</van-button>
<van-button
v-if="showAddCartBtn"
bottom-action
:text="$t('cart')"
@click="skuEventBus.$emit('sku:addCart')"
/>
<van-button
type="primary"
bottom-action
:text="buyText || $t('buy')"
@click="skuEventBus.$emit('sku:buy')"
/>
</div>
</template>
@ -20,15 +30,6 @@ export default create({
buyText: String,
skuEventBus: Object,
showAddCartBtn: Boolean
},
methods: {
onAddCartClicked() {
this.skuEventBus.$emit('sku:addCart');
},
onBuyClicked() {
this.skuEventBus.$emit('sku:buy');
}
}
});
</script>

View File

@ -6,7 +6,7 @@
<div class="van-sku-header__goods-info">
<div class="van-sku__goods-name">{{ goods.title }}</div>
<div class="van-sku__goods-price"><span class="van-sku__price-symbol"></span><span class="van-sku__price-num">{{ price }}</span></div>
<span class="van-sku__close-icon" @click="onCloseClicked" />
<span class="van-sku__close-icon" @click="skuEventBus.$emit('sku:close')" />
</div>
</div>
</template>
@ -26,9 +26,6 @@ export default create({
},
computed: {
skuTree() {
return this.sku.tree;
},
goodsImg() {
const s1Id = this.selectedSku.s1;
const skuImg = this.getSkuImg(s1Id);
@ -45,14 +42,11 @@ export default create({
},
methods: {
onCloseClicked() {
this.skuEventBus.$emit('sku:close');
},
getSkuImg(id) {
if (!id) return;
// skuImgskuTrees1sku
const treeItem = this.skuTree.filter(treeItem => treeItem.k_s === 's1')[0] || {};
const treeItem = this.sku.tree.filter(treeItem => treeItem.k_s === 's1')[0] || {};
if (!treeItem.v) {
return;

View File

@ -1,26 +1,14 @@
<template>
<cell-group class="van-sku-messages">
<template v-for="(message, index) in internalMessages">
<template v-if="message.type === 'image'" />
<field
v-else-if="message.multiple == '1'"
:key="`${goodsId}-${index}`"
:required="message.required == '1'"
:label="message.name"
:placeholder="getPlaceholder('textarea')"
type="textarea"
v-for="(message, index) in internalMessages"
v-model="messageValues[index]"
/>
<field
v-else
:key="`${goodsId}-${index}`"
:required="message.required == '1'"
:label="message.name"
:placeholder="getPlaceholder(message.type)"
:placeholder="getPlaceholder(message)"
:type="getType(message)"
v-model="messageValues[index]"
/>
</template>
</cell-group>
</template>
@ -47,26 +35,23 @@ export default create({
computed: {
internalMessages() {
if (Object.prototype.toString.call(this.messages) === '[object Array]') {
return this.messages;
}
return [];
return Array.isArray(this.messages) ? this.messages.filter(message => message.type !== 'image') : [];
},
messageValues() {
const messageValues = [];
this.internalMessages.forEach((message, index) => {
messageValues[index] = '';
});
return messageValues;
return this.internalMessages.map(() => '');
}
},
methods: {
getType({ type, datetime }) {
if (type === 'id_no') return 'text';
return datetime > 0 ? 'datetime-local' : type;
getType(message) {
if (+message.multiple === 1) {
return 'textarea';
}
if (message.type === 'id_no') {
return 'text';
}
return message.datetime > 0 ? 'datetime-local' : message.type;
},
getMessages() {
@ -96,8 +81,9 @@ export default create({
return messages;
},
getPlaceholder(key) {
return this.messagePlaceholderMap[key] || this.$t(`placeholder.${key}`);
getPlaceholder(message) {
const type = +message.multiple === 1 ? 'textarea' : message.type;
return this.messagePlaceholderMap[type] || this.$t(`placeholder.${type}`);
},
validateMessages() {

View File

@ -1,12 +1,14 @@
<template>
<span
v-if="isChoosable"
@click="onSkuSelected"
class="van-sku-row__item"
:class="{ 'van-sku-row__item--active': isChoosed }">
:class="{
'van-sku-row__item--active': isChoosed,
'van-sku-row__item--disabled': !isChoosable
}"
@click="onSkuSelected"
>
{{ skuValue.name }}
</span>
<span v-else class="van-sku-row__item van-sku-row__item--disabled">{{ skuValue.name }}</span>
</template>
<script>
@ -25,6 +27,7 @@ export default {
isChoosed() {
return this.skuValue.id === this.selectedSku[this.skuKeyStr];
},
isChoosable() {
const matchedSku = Object.assign({}, this.selectedSku, {
[this.skuKeyStr]: this.skuValue.id
@ -44,7 +47,12 @@ export default {
methods: {
onSkuSelected() {
this.skuEventBus.$emit('sku:select', Object.assign({}, this.skuValue, { skuKeyStr: this.skuKeyStr }));
if (this.isChoosable) {
this.skuEventBus.$emit('sku:select', {
...this.skuValue,
skuKeyStr: this.skuKeyStr
});
}
}
}
};

View File

@ -8,7 +8,7 @@
:min="1"
:max="stepperLimit"
:disable-input="disableStepperInput"
@overlimit="handleOverLimit"
@overlimit="onOverLimit"
/>
</div>
<div v-if="!hideStock" class="van-sku__stock">{{ $t('remain', stock) }}</div>
@ -39,14 +39,8 @@ export default create({
stepperTitle: String,
quota: Number,
quotaUsed: Number,
hideStock: {
type: Boolean,
default: false
},
disableStepperInput: {
type: Boolean,
default: false
}
hideStock: Boolean,
disableStepperInput: Boolean
},
data() {
@ -96,7 +90,8 @@ export default create({
setCurrentNum(num) {
this.currentNum = num;
},
handleOverLimit(action) {
onOverLimit(action) {
this.skuEventBus.$emit('sku:overLimit', {
action,
limitType: this.limitType,

View File

@ -1,3 +1,4 @@
import Sku from './Sku';
import SkuActions from './components/SkuActions';
import SkuHeader from './components/SkuHeader';
import SkuMessages from './components/SkuMessages';
@ -5,14 +6,13 @@ import SkuStepper from './components/SkuStepper';
import SkuRow from './components/SkuRow';
import SkuRowItem from './components/SkuRowItem';
import skuHelper from './utils/skuHelper';
import SkuContainer from './containers/SkuContainer';
SkuContainer.SkuActions = SkuActions;
SkuContainer.SkuHeader = SkuHeader;
SkuContainer.SkuMessages = SkuMessages;
SkuContainer.SkuStepper = SkuStepper;
SkuContainer.SkuRow = SkuRow;
SkuContainer.SkuRowItem = SkuRowItem;
SkuContainer.skuHelper = skuHelper;
Sku.SkuActions = SkuActions;
Sku.SkuHeader = SkuHeader;
Sku.SkuMessages = SkuMessages;
Sku.SkuStepper = SkuStepper;
Sku.SkuRow = SkuRow;
Sku.SkuRowItem = SkuRowItem;
Sku.skuHelper = skuHelper;
export default SkuContainer;
export default Sku;

744
yarn.lock

File diff suppressed because it is too large Load Diff