feat[litemall-wx]: 采用vant-weapp tag组件

This commit is contained in:
Junling Bu
2019-12-04 21:13:55 +08:00
parent 52c0f60d38
commit 561ec67bf3
54 changed files with 552 additions and 137 deletions

View File

@@ -86,5 +86,8 @@
"downloadFile": 10000
},
"debug": true,
"usingComponents": {
"van-tag": "./lib/vant-weapp/tag/index"
},
"sitemapLocation": "sitemap.json"
}

View File

@@ -0,0 +1,7 @@
export declare const RED = "#ee0a24";
export declare const BLUE = "#1989fa";
export declare const WHITE = "#fff";
export declare const GREEN = "#07c160";
export declare const ORANGE = "#ff976a";
export declare const GRAY = "#323233";
export declare const GRAY_DARK = "#969799";

View File

@@ -0,0 +1,7 @@
export const RED = '#ee0a24';
export const BLUE = '#1989fa';
export const WHITE = '#fff';
export const GREEN = '#07c160';
export const ORANGE = '#ff976a';
export const GRAY = '#323233';
export const GRAY_DARK = '#969799';

View File

@@ -0,0 +1,3 @@
import { VantComponentOptions, CombinedComponentInstance } from '../definitions/index';
declare function VantComponent<Data, Props, Methods>(vantOptions?: VantComponentOptions<Data, Props, Methods, CombinedComponentInstance<Data, Props, Methods>>): void;
export { VantComponent };

View File

@@ -0,0 +1,48 @@
import { basic } from '../mixins/basic';
import { observe } from '../mixins/observer/index';
function mapKeys(source, target, map) {
Object.keys(map).forEach(key => {
if (source[key]) {
target[map[key]] = source[key];
}
});
}
function VantComponent(vantOptions = {}) {
const options = {};
mapKeys(vantOptions, options, {
data: 'data',
props: 'properties',
mixins: 'behaviors',
methods: 'methods',
beforeCreate: 'created',
created: 'attached',
mounted: 'ready',
relations: 'relations',
destroyed: 'detached',
classes: 'externalClasses'
});
const { relation } = vantOptions;
if (relation) {
options.relations = Object.assign(options.relations || {}, {
[`../${relation.name}/index`]: relation
});
}
// add default externalClasses
options.externalClasses = options.externalClasses || [];
options.externalClasses.push('custom-class');
// add default behaviors
options.behaviors = options.behaviors || [];
options.behaviors.push(basic);
// map field to form-field behavior
if (vantOptions.field) {
options.behaviors.push('wx://form-field');
}
// add default options
options.options = {
multipleSlots: true,
addGlobalClass: true
};
observe(vantOptions, options);
Component(options);
}
export { VantComponent };

View File

@@ -0,0 +1 @@
.van-ellipsis{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.van-multi-ellipsis--l2{-webkit-line-clamp:2}.van-multi-ellipsis--l2,.van-multi-ellipsis--l3{display:-webkit-box;overflow:hidden;text-overflow:ellipsis;-webkit-box-orient:vertical}.van-multi-ellipsis--l3{-webkit-line-clamp:3}.van-clearfix:after{display:table;clear:both;content:""}.van-hairline,.van-hairline--bottom,.van-hairline--left,.van-hairline--right,.van-hairline--surround,.van-hairline--top,.van-hairline--top-bottom{position:relative}.van-hairline--bottom:after,.van-hairline--left:after,.van-hairline--right:after,.van-hairline--surround:after,.van-hairline--top-bottom:after,.van-hairline--top:after,.van-hairline:after{position:absolute;box-sizing:border-box;-webkit-transform-origin:center;transform-origin:center;content:" ";pointer-events:none;top:-50%;right:-50%;bottom:-50%;left:-50%;border:0 solid #eee;-webkit-transform:scale(.5);transform:scale(.5)}.van-hairline--top:after{border-top-width:1px}.van-hairline--left:after{border-left-width:1px}.van-hairline--right:after{border-right-width:1px}.van-hairline--bottom:after{border-bottom-width:1px}.van-hairline--top-bottom:after{border-width:1px 0}.van-hairline--surround:after{border-width:1px}

View File

@@ -0,0 +1 @@
.van-clearfix:after{display:table;clear:both;content:""}

View File

@@ -0,0 +1 @@
.van-ellipsis{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.van-multi-ellipsis--l2{-webkit-line-clamp:2}.van-multi-ellipsis--l2,.van-multi-ellipsis--l3{display:-webkit-box;overflow:hidden;text-overflow:ellipsis;-webkit-box-orient:vertical}.van-multi-ellipsis--l3{-webkit-line-clamp:3}

View File

@@ -0,0 +1 @@
.van-hairline,.van-hairline--bottom,.van-hairline--left,.van-hairline--right,.van-hairline--surround,.van-hairline--top,.van-hairline--top-bottom{position:relative}.van-hairline--bottom:after,.van-hairline--left:after,.van-hairline--right:after,.van-hairline--surround:after,.van-hairline--top-bottom:after,.van-hairline--top:after,.van-hairline:after{position:absolute;box-sizing:border-box;-webkit-transform-origin:center;transform-origin:center;content:" ";pointer-events:none;top:-50%;right:-50%;bottom:-50%;left:-50%;border:0 solid #eee;-webkit-transform:scale(.5);transform:scale(.5)}.van-hairline--top:after{border-top-width:1px}.van-hairline--left:after{border-left-width:1px}.van-hairline--right:after{border-right-width:1px}.van-hairline--bottom:after{border-bottom-width:1px}.van-hairline--top-bottom:after{border-width:1px 0}.van-hairline--surround:after{border-width:1px}

View File

@@ -0,0 +1,8 @@
/// <reference types="miniprogram-api-typings" />
export declare function isDef(value: any): boolean;
export declare function isObj(x: any): boolean;
export declare function isNumber(value: any): boolean;
export declare function range(num: number, min: number, max: number): number;
export declare function nextTick(fn: Function): void;
export declare function getSystemInfoSync(): WechatMiniprogram.GetSystemInfoSuccessCallbackResult;
export declare function addUnit(value?: string | number): string | undefined;

View File

@@ -0,0 +1,32 @@
export function isDef(value) {
return value !== undefined && value !== null;
}
export function isObj(x) {
const type = typeof x;
return x !== null && (type === 'object' || type === 'function');
}
export function isNumber(value) {
return /^\d+(\.\d+)?$/.test(value);
}
export function range(num, min, max) {
return Math.min(Math.max(num, min), max);
}
export function nextTick(fn) {
setTimeout(() => {
fn();
}, 1000 / 30);
}
let systemInfo = null;
export function getSystemInfoSync() {
if (systemInfo == null) {
systemInfo = wx.getSystemInfoSync();
}
return systemInfo;
}
export function addUnit(value) {
if (!isDef(value)) {
return undefined;
}
value = String(value);
return isNumber(value) ? `${value}px` : value;
}

View File

@@ -0,0 +1 @@
export declare const basic: string;

View File

@@ -0,0 +1,22 @@
export const basic = Behavior({
methods: {
$emit(...args) {
this.triggerEvent(...args);
},
getRect(selector, all) {
return new Promise(resolve => {
wx.createSelectorQuery()
.in(this)[all ? 'selectAll' : 'select'](selector)
.boundingClientRect(rect => {
if (all && Array.isArray(rect) && rect.length) {
resolve(rect);
}
if (!all && rect) {
resolve(rect);
}
})
.exec();
});
}
}
});

View File

@@ -0,0 +1 @@
export declare const button: string;

View File

@@ -0,0 +1,18 @@
export const button = Behavior({
externalClasses: ['hover-class'],
properties: {
id: String,
lang: {
type: String,
value: 'en'
},
businessId: Number,
sessionFrom: String,
sendMessageTitle: String,
sendMessagePath: String,
sendMessageImg: String,
showMessageCard: Boolean,
appParameter: String,
ariaLabel: String
}
});

View File

@@ -0,0 +1 @@
export declare const link: string;

View File

@@ -0,0 +1,17 @@
export const link = Behavior({
properties: {
url: String,
linkType: {
type: String,
value: 'navigateTo'
}
},
methods: {
jumpLink(urlKey = 'url') {
const url = this.data[urlKey];
if (url) {
wx[this.data.linkType]({ url });
}
}
}
});

View File

@@ -0,0 +1 @@
export declare const behavior: string;

View File

@@ -0,0 +1,14 @@
export const behavior = Behavior({
methods: {
set(data, callback) {
return new Promise(resolve => {
this.setData(data, () => {
if (callback && typeof callback === 'function') {
callback.call(this);
}
resolve();
});
});
}
}
});

View File

@@ -0,0 +1 @@
export declare function observe(vantOptions: any, options: any): void;

View File

@@ -0,0 +1,19 @@
import { behavior } from './behavior';
export function observe(vantOptions, options) {
const { watch } = vantOptions;
options.behaviors.push(behavior);
if (watch) {
const props = options.properties || {};
Object.keys(watch).forEach(key => {
if (key in props) {
let prop = props[key];
if (prop === null || !('type' in prop)) {
prop = { type: prop };
}
prop.observer = watch[key];
props[key] = prop;
}
});
options.properties = props;
}
}

View File

@@ -0,0 +1 @@
export declare const openType: string;

View File

@@ -0,0 +1,25 @@
export const openType = Behavior({
properties: {
openType: String
},
methods: {
bindGetUserInfo(event) {
this.$emit('getuserinfo', event.detail);
},
bindContact(event) {
this.$emit('contact', event.detail);
},
bindGetPhoneNumber(event) {
this.$emit('getphonenumber', event.detail);
},
bindError(event) {
this.$emit('error', event.detail);
},
bindLaunchApp(event) {
this.$emit('launchapp', event.detail);
},
bindOpenSetting(event) {
this.$emit('opensetting', event.detail);
},
}
});

View File

@@ -0,0 +1 @@
export declare const touch: string;

View File

@@ -0,0 +1,35 @@
const MIN_DISTANCE = 10;
function getDirection(x, y) {
if (x > y && x > MIN_DISTANCE) {
return 'horizontal';
}
if (y > x && y > MIN_DISTANCE) {
return 'vertical';
}
return '';
}
export const touch = Behavior({
methods: {
resetTouchStatus() {
this.direction = '';
this.deltaX = 0;
this.deltaY = 0;
this.offsetX = 0;
this.offsetY = 0;
},
touchStart(event) {
this.resetTouchStatus();
const touch = event.touches[0];
this.startX = touch.clientX;
this.startY = touch.clientY;
},
touchMove(event) {
const touch = event.touches[0];
this.deltaX = touch.clientX - this.startX;
this.deltaY = touch.clientY - this.startY;
this.offsetX = Math.abs(this.deltaX);
this.offsetY = Math.abs(this.deltaY);
this.direction = this.direction || getDirection(this.offsetX, this.offsetY);
}
}
});

View File

@@ -0,0 +1 @@
export declare const transition: (showDefaultValue: boolean) => any;

View File

@@ -0,0 +1,120 @@
import { isObj } from '../common/utils';
const getClassNames = (name) => ({
enter: `van-${name}-enter van-${name}-enter-active enter-class enter-active-class`,
'enter-to': `van-${name}-enter-to van-${name}-enter-active enter-to-class enter-active-class`,
leave: `van-${name}-leave van-${name}-leave-active leave-class leave-active-class`,
'leave-to': `van-${name}-leave-to van-${name}-leave-active leave-to-class leave-active-class`
});
const nextTick = () => new Promise(resolve => setTimeout(resolve, 1000 / 30));
export const transition = function (showDefaultValue) {
return Behavior({
properties: {
customStyle: String,
// @ts-ignore
show: {
type: Boolean,
value: showDefaultValue,
observer: 'observeShow'
},
// @ts-ignore
duration: {
type: null,
value: 300,
observer: 'observeDuration'
},
name: {
type: String,
value: 'fade'
}
},
data: {
type: '',
inited: false,
display: false
},
attached() {
if (this.data.show) {
this.enter();
}
},
methods: {
observeShow(value) {
value ? this.enter() : this.leave();
},
enter() {
const { duration, name } = this.data;
const classNames = getClassNames(name);
const currentDuration = isObj(duration) ? duration.enter : duration;
this.status = 'enter';
this.$emit('before-enter');
Promise.resolve()
.then(nextTick)
.then(() => {
this.checkStatus('enter');
this.$emit('enter');
this.setData({
inited: true,
display: true,
classes: classNames.enter,
currentDuration
});
})
.then(nextTick)
.then(() => {
this.checkStatus('enter');
this.transitionEnded = false;
this.setData({
classes: classNames['enter-to']
});
})
.catch(() => { });
},
leave() {
if (!this.data.display) {
return;
}
const { duration, name } = this.data;
const classNames = getClassNames(name);
const currentDuration = isObj(duration) ? duration.leave : duration;
this.status = 'leave';
this.$emit('before-leave');
Promise.resolve()
.then(nextTick)
.then(() => {
this.checkStatus('leave');
this.$emit('leave');
this.setData({
classes: classNames.leave,
currentDuration
});
})
.then(nextTick)
.then(() => {
this.checkStatus('leave');
this.transitionEnded = false;
setTimeout(() => this.onTransitionEnd(), currentDuration);
this.setData({
classes: classNames['leave-to']
});
})
.catch(() => { });
},
checkStatus(status) {
if (status !== this.status) {
throw new Error(`incongruent status: ${status}`);
}
},
onTransitionEnd() {
if (this.transitionEnded) {
return;
}
this.transitionEnded = true;
this.$emit(`after-${this.status}`);
const { show, display } = this.data;
if (!show && display) {
this.setData({ display: false });
}
}
}
});
};

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1,21 @@
import { VantComponent } from '../common/component';
VantComponent({
props: {
size: String,
mark: Boolean,
color: String,
plain: Boolean,
round: Boolean,
textColor: String,
type: {
type: String,
value: 'default'
},
closeable: Boolean
},
methods: {
onClose() {
this.$emit('close');
}
}
});

View File

@@ -0,0 +1,14 @@
<wxs src="../wxs/utils.wxs" module="utils" />
<view
class="custom-class {{ utils.bem('tag', [type, size, { mark, plain, round }]) }} {{ plain ? 'van-hairline--surround' : '' }}"
style="{{ color && !plain ? 'background-color: ' + color + ';' : '' }}{{ textColor || (color && plain) ? 'color: ' + (textColor || color) : '' }}"
>
<slot />
<van-icon
wx:if="{{ closeable }}"
name="cross"
custom-class="van-tag__close"
bind:click="onClose"
/>
</view>

View File

@@ -0,0 +1 @@
@import '../common/index.wxss';.van-tag{display:-webkit-inline-flex;display:inline-flex;-webkit-align-items:center;align-items:center;line-height:normal;padding:.2em .5em;padding:var(--tag-padding,.2em .5em);color:#fff;color:var(--tag-text-color,#fff);font-size:10px;font-size:var(--tag-font-size,10px);border-radius:.2em;border-radius:var(--tag-border-radius,.2em)}.van-tag:after{border-color:currentColor;border-radius:.2em * 2;border-radius:var(--tag-border-radius,.2em) * 2}.van-tag--default{background-color:#969799;background-color:var(--tag-default-color,#969799)}.van-tag--default.van-tag--plain{color:#969799;color:var(--tag-default-color,#969799)}.van-tag--danger{background-color:#ee0a24;background-color:var(--tag-dander-color,#ee0a24)}.van-tag--danger.van-tag--plain{color:#ee0a24;color:var(--tag-dander-color,#ee0a24)}.van-tag--primary{background-color:#1989fa;background-color:var(--tag-primary-color,#1989fa)}.van-tag--primary.van-tag--plain{color:#1989fa;color:var(--tag-primary-color,#1989fa)}.van-tag--success{background-color:#07c160;background-color:var(--tag-success-color,#07c160)}.van-tag--success.van-tag--plain{color:#07c160;color:var(--tag-success-color,#07c160)}.van-tag--warning{background-color:#ff976a;background-color:var(--tag-warning-color,#ff976a)}.van-tag--warning.van-tag--plain{color:#ff976a;color:var(--tag-warning-color,#ff976a)}.van-tag--plain{background-color:#fff;background-color:var(--tag-plain-background-color,#fff)}.van-tag--mark{padding-right:.7em}.van-tag--mark,.van-tag--mark:after{border-radius:0 999px 999px 0;border-radius:0 var(--tag-round-border-radius,999px) var(--tag-round-border-radius,999px) 0}.van-tag--round,.van-tag--round:after{border-radius:999px;border-radius:var(--tag-round-border-radius,999px)}.van-tag--medium{font-size:12px;font-size:var(--tag-medium-font-size,12px)}.van-tag--large{font-size:14px;font-size:var(--tag-large-font-size,14px)}.van-tag__close{margin-left:2px}

View File

@@ -0,0 +1,5 @@
function isArray(array) {
return array && array.constructor === 'Array';
}
module.exports.isArray = isArray;

View File

@@ -0,0 +1,38 @@
var array = require('./array.wxs');
var object = require('./object.wxs');
var PREFIX = 'van-';
function join(name, mods) {
name = PREFIX + name;
mods = mods.map(function(mod) {
return name + '--' + mod;
});
mods.unshift(name);
return mods.join(' ');
}
function traversing(mods, conf) {
if (!conf) {
return;
}
if (typeof conf === 'string' || typeof conf === 'number') {
mods.push(conf);
} else if (array.isArray(conf)) {
conf.forEach(function(item) {
traversing(mods, item);
});
} else if (typeof conf === 'object') {
object.keys(conf).forEach(function(key) {
conf[key] && mods.push(key);
});
}
}
function bem(name, conf) {
var mods = [];
traversing(mods, conf);
return join(name, mods);
}
module.exports.bem = bem;

View File

@@ -0,0 +1,54 @@
/**
* Simple memoize
* wxs doesn't support fn.apply, so this memoize only support up to 2 args
*/
function isPrimitive(value) {
var type = typeof value;
return (
type === 'boolean' ||
type === 'number' ||
type === 'string' ||
type === 'undefined' ||
value === null
);
}
// mock simple fn.call in wxs
function call(fn, args) {
if (args.length === 2) {
return fn(args[0], args[1]);
}
if (args.length === 1) {
return fn(args[0]);
}
return fn();
}
function serializer(args) {
if (args.length === 1 && isPrimitive(args[0])) {
return args[0];
}
var obj = {};
for (var i = 0; i < args.length; i++) {
obj['key' + i] = args[i];
}
return JSON.stringify(obj);
}
function memoize(fn) {
var cache = {};
return function() {
var key = serializer(arguments);
if (cache[key] === undefined) {
cache[key] = call(fn, arguments);
}
return cache[key];
};
}
module.exports.memoize = memoize;

View File

@@ -0,0 +1,13 @@
/* eslint-disable */
var REGEXP = getRegExp('{|}|"', 'g');
function keys(obj) {
return JSON.stringify(obj)
.replace(REGEXP, '')
.split(',')
.map(function(item) {
return item.split(':')[0];
});
}
module.exports.keys = keys;

View File

@@ -0,0 +1,7 @@
var bem = require('./bem.wxs').bem;
var memoize = require('./memoize.wxs').memoize;
module.exports = {
bem: memoize(bem),
memoize: memoize
};

View File

@@ -1,31 +0,0 @@
'use strict';
Component({
externalClasses: ['custom-class'],
/**
* 组件的属性列表
* 用于组件自定义设置
*/
properties: {
// 颜色状态
type: {
type: String,
value: ''
},
// 自定义颜色
color: {
type: String,
value: ''
},
// 左侧内容
leftText: {
type: String,
value: ''
},
// 右侧内容
rightText: {
type: String,
value: ''
}
}
});

View File

@@ -1,10 +0,0 @@
<view class="custom-class zan-capsule zan-capsule--{{type}}">
<block wx:if="{{color}}">
<view class="zan-capsule__left" style="background: {{ color }}; border-color: {{ color }}">{{ leftText }}</view>
<view class="zan-capsule__right" style="color: {{ color }}; border-color: {{ color }}">{{ rightText }}</view>
</block>
<block wx:else>
<view class="zan-capsule__left">{{ leftText }}</view>
<view class="zan-capsule__right">{{ rightText }}</view>
</block>
</view>

View File

@@ -1,42 +0,0 @@
.zan-capsule {
display: inline-block;
font-size: 12px;
vertical-align: middle;
line-height: 19px;
-webkit-transform: scale(0.83);
transform: scale(0.83);
}
.zan-capsule__left, .zan-capsule__right {
display: inline-block;
line-height: 17px;
height: 19px;
vertical-align: middle;
box-sizing: border-box;
}
.zan-capsule__left {
padding: 0 2px;
color: #fff;
background: #999;
border-radius: 2px 0 0 2px;
border: 1rpx solid #999;
}
.zan-capsule__right {
padding: 0 5px;
color: #999;
border-radius: 0 2px 2px 0;
border: 1rpx solid #999;
}
.zan-capsule--danger .zan-capsule__left {
color: #fff;
background: #f24544;
border-color: #f24544;
}
.zan-capsule--danger .zan-capsule__right {
color: #f24544;
border-color: #f24544;
}

View File

@@ -1,6 +1,3 @@
{
"navigationBarTitleText": "团购专区",
"usingComponents": {
"zan-capsule": "/lib/zanui-weapp/capsule/index"
}
"navigationBarTitleText": "团购专区"
}

View File

@@ -8,9 +8,7 @@
<view class="text">
<view class="header">
<text class="name">{{item.name}}</text>
<view class="capsule-tag">
<zan-capsule color="#a78845" leftText="{{item.grouponMember}}人成团" rightText="立减{{item.grouponDiscount}}" />
</view>
<van-tag type="warning">{{item.grouponMember}}人成团</van-tag>
</view>
<text class="desc">{{item.brief}}</text>
<view class="price">

View File

@@ -54,16 +54,6 @@ page, .container {
font-size: 30rpx;
}
.groupon-list .capsule-tag {
float: right;
padding-right: 0rpx;
padding-top: 8rpx;
}
.groupon-list .zan-capsule + .zan-capsule {
margin-left: 10px;
}
.groupon-list .desc {
width: 476rpx;
display: block;

View File

@@ -1,6 +1,3 @@
{
"navigationBarTitleText": "我的团购",
"usingComponents": {
"zan-capsule": "../../../lib/zanui-weapp/capsule/index"
}
"navigationBarTitleText": "我的团购"
}

View File

@@ -40,12 +40,8 @@
</view>
<view class="b">
<view class="l">实付:¥{{item.actualPrice}}</view>
<view class="capsule-tag">
<zan-capsule color="#a78845" leftText="状态" rightText="{{item.joinerCount>=item.rules.discountMember?'已达成':'团购中'}}" />
</view>
<view class="capsule-tag">
<zan-capsule color="#a78845" leftText="发起" rightText="{{item.creator}}" wx:if="{{!item.isCreator}}" />
</view>
<van-tag type="primary">{{item.joinerCount>=item.rules.discountMember?'已达成':'团购中'}}</van-tag>
<van-tag round type="warning" wx:if="{{!item.isCreator}}">{{item.creator}}发起</van-tag>
</view>
</navigator>
</view>

View File

@@ -4,15 +4,6 @@ page {
background: #f4f4f4;
}
.capsule-tag {
float: right;
/* padding-right: 10rpx; */
}
.zan-capsule + .zan-capsule {
margin-left: 5px;
}
.orders-switch {
width: 100%;
background: #fff;

View File

@@ -1,7 +1,4 @@
{
"navigationBarTitleText": "首页",
"enablePullDownRefresh": true,
"usingComponents": {
"zan-capsule": "../../lib/zanui-weapp/capsule/index"
}
"enablePullDownRefresh": true
}

View File

@@ -72,9 +72,7 @@
<view class="text">
<view class="header">
<text class="name">{{item.name}}</text>
<view class="capsule-tag">
<zan-capsule color="#a78845" leftText="{{item.grouponMember}}人成团" rightText="立减{{item.grouponDiscount}}" />
</view>
<van-tag type="warning">{{item.grouponMember}}人成团</van-tag>
</view>
<text class="desc">{{item.brief}}</text>
<view class="price">

View File

@@ -242,16 +242,6 @@
font-size: 30rpx;
}
.a-groupon .capsule-tag {
float: right;
padding-right: 0rpx;
padding-top: 8rpx;
}
.a-groupon .zan-capsule + .zan-capsule {
margin-left: 10px;
}
.a-groupon .b .desc {
width: 476rpx;
display: block;