移除 lib下miniprogram_npm

This commit is contained in:
Wang Kejun 2023-11-10 12:22:19 +08:00
parent 21061896f4
commit 3df45090a6
367 changed files with 12 additions and 19638 deletions

View File

@ -1,265 +0,0 @@
import WxCanvas from './wx-canvas';
import * as echarts from './echarts';
let ctx;
function compareVersion(v1, v2) {
v1 = v1.split('.')
v2 = v2.split('.')
const len = Math.max(v1.length, v2.length)
while (v1.length < len) {
v1.push('0')
}
while (v2.length < len) {
v2.push('0')
}
for (let i = 0; i < len; i++) {
const num1 = parseInt(v1[i])
const num2 = parseInt(v2[i])
if (num1 > num2) {
return 1
} else if (num1 < num2) {
return -1
}
}
return 0
}
Component({
properties: {
canvasId: {
type: String,
value: 'ec-canvas'
},
ec: {
type: Object
},
forceUseOldCanvas: {
type: Boolean,
value: false
}
},
data: {
isUseNewCanvas: false
},
ready: function () {
// Disable prograssive because drawImage doesn't support DOM as parameter
// See https://developers.weixin.qq.com/miniprogram/dev/api/canvas/CanvasContext.drawImage.html
echarts.registerPreprocessor(option => {
if (option && option.series) {
if (option.series.length > 0) {
option.series.forEach(series => {
series.progressive = 0;
});
}
else if (typeof option.series === 'object') {
option.series.progressive = 0;
}
}
});
if (!this.data.ec) {
console.warn('组件需绑定 ec 变量,例:<ec-canvas id="mychart-dom-bar" '
+ 'canvas-id="mychart-bar" ec="{{ ec }}"></ec-canvas>');
return;
}
if (!this.data.ec.lazyLoad) {
this.init();
}
},
methods: {
init: function (callback) {
const version = wx.getSystemInfoSync().SDKVersion
const canUseNewCanvas = compareVersion(version, '2.9.0') >= 0;
const forceUseOldCanvas = this.data.forceUseOldCanvas;
const isUseNewCanvas = canUseNewCanvas && !forceUseOldCanvas;
this.setData({ isUseNewCanvas });
if (forceUseOldCanvas && canUseNewCanvas) {
console.warn('开发者强制使用旧canvas,建议关闭');
}
if (isUseNewCanvas) {
// console.log('微信基础库版本大于2.9.0,开始使用<canvas type="2d"/>');
// 2.9.0 可以使用 <canvas type="2d"></canvas>
this.initByNewWay(callback);
} else {
const isValid = compareVersion(version, '1.9.91') >= 0
if (!isValid) {
console.error('微信基础库版本过低,需大于等于 1.9.91。'
+ '参见https://github.com/ecomfe/echarts-for-weixin'
+ '#%E5%BE%AE%E4%BF%A1%E7%89%88%E6%9C%AC%E8%A6%81%E6%B1%82');
return;
} else {
console.warn('建议将微信基础库调整大于等于2.9.0版本。升级后绘图将有更好性能');
this.initByOldWay(callback);
}
}
},
initByOldWay(callback) {
// 1.9.91 <= version < 2.9.0:原来的方式初始化
ctx = wx.createCanvasContext(this.data.canvasId, this);
const canvas = new WxCanvas(ctx, this.data.canvasId, false);
echarts.setCanvasCreator(() => {
return canvas;
});
// const canvasDpr = wx.getSystemInfoSync().pixelRatio // 微信旧的canvas不能传入dpr
const canvasDpr = 1
var query = wx.createSelectorQuery().in(this);
query.select('.ec-canvas').boundingClientRect(res => {
if (typeof callback === 'function') {
this.chart = callback(canvas, res.width, res.height, canvasDpr);
}
else if (this.data.ec && typeof this.data.ec.onInit === 'function') {
this.chart = this.data.ec.onInit(canvas, res.width, res.height, canvasDpr);
}
else {
this.triggerEvent('init', {
canvas: canvas,
width: res.width,
height: res.height,
canvasDpr: canvasDpr // 增加了dpr可方便外面echarts.init
});
}
}).exec();
},
initByNewWay(callback) {
// version >= 2.9.0:使用新的方式初始化
const query = wx.createSelectorQuery().in(this)
query
.select('.ec-canvas')
.fields({ node: true, size: true })
.exec(res => {
const canvasNode = res[0].node
this.canvasNode = canvasNode
const canvasDpr = wx.getSystemInfoSync().pixelRatio
const canvasWidth = res[0].width
const canvasHeight = res[0].height
const ctx = canvasNode.getContext('2d')
const canvas = new WxCanvas(ctx, this.data.canvasId, true, canvasNode)
echarts.setCanvasCreator(() => {
return canvas
})
if (typeof callback === 'function') {
this.chart = callback(canvas, canvasWidth, canvasHeight, canvasDpr)
} else if (this.data.ec && typeof this.data.ec.onInit === 'function') {
this.chart = this.data.ec.onInit(canvas, canvasWidth, canvasHeight, canvasDpr)
} else {
this.triggerEvent('init', {
canvas: canvas,
width: canvasWidth,
height: canvasHeight,
dpr: canvasDpr
})
}
})
},
canvasToTempFilePath(opt) {
if (this.data.isUseNewCanvas) {
// 新版
const query = wx.createSelectorQuery().in(this)
query
.select('.ec-canvas')
.fields({ node: true, size: true })
.exec(res => {
const canvasNode = res[0].node
opt.canvas = canvasNode
wx.canvasToTempFilePath(opt)
})
} else {
// 旧的
if (!opt.canvasId) {
opt.canvasId = this.data.canvasId;
}
ctx.draw(true, () => {
wx.canvasToTempFilePath(opt, this);
});
}
},
touchStart(e) {
if (this.chart && e.touches.length > 0) {
var touch = e.touches[0];
var handler = this.chart.getZr().handler;
handler.dispatch('mousedown', {
zrX: touch.x,
zrY: touch.y,
preventDefault: () => {},
stopImmediatePropagation: () => {},
stopPropagation: () => {}
});
handler.dispatch('mousemove', {
zrX: touch.x,
zrY: touch.y,
preventDefault: () => {},
stopImmediatePropagation: () => {},
stopPropagation: () => {}
});
handler.processGesture(wrapTouch(e), 'start');
}
},
touchMove(e) {
if (this.chart && e.touches.length > 0) {
var touch = e.touches[0];
var handler = this.chart.getZr().handler;
handler.dispatch('mousemove', {
zrX: touch.x,
zrY: touch.y,
preventDefault: () => {},
stopImmediatePropagation: () => {},
stopPropagation: () => {}
});
handler.processGesture(wrapTouch(e), 'change');
}
},
touchEnd(e) {
if (this.chart) {
const touch = e.changedTouches ? e.changedTouches[0] : {};
var handler = this.chart.getZr().handler;
handler.dispatch('mouseup', {
zrX: touch.x,
zrY: touch.y,
preventDefault: () => {},
stopImmediatePropagation: () => {},
stopPropagation: () => {}
});
handler.dispatch('click', {
zrX: touch.x,
zrY: touch.y,
preventDefault: () => {},
stopImmediatePropagation: () => {},
stopPropagation: () => {}
});
handler.processGesture(wrapTouch(e), 'end');
}
}
}
});
function wrapTouch(event) {
for (let i = 0; i < event.touches.length; ++i) {
const touch = event.touches[i];
touch.offsetX = touch.x;
touch.offsetY = touch.y;
}
return event;
}

View File

@ -1,4 +0,0 @@
{
"component": true,
"usingComponents": {}
}

View File

@ -1,4 +0,0 @@
<!-- 新的接口对其了H5 -->
<canvas wx:if="{{isUseNewCanvas}}" type="2d" class="ec-canvas" canvas-id="{{ canvasId }}" bindinit="init" bindtouchstart="{{ ec.disableTouch ? '' : 'touchStart' }}" bindtouchmove="{{ ec.disableTouch ? '' : 'touchMove' }}" bindtouchend="{{ ec.disableTouch ? '' : 'touchEnd' }}"></canvas>
<!-- 旧的 -->
<canvas wx:else class="ec-canvas" canvas-id="{{ canvasId }}" bindinit="init" bindtouchstart="{{ ec.disableTouch ? '' : 'touchStart' }}" bindtouchmove="{{ ec.disableTouch ? '' : 'touchMove' }}" bindtouchend="{{ ec.disableTouch ? '' : 'touchEnd' }}"></canvas>

View File

@ -1,4 +0,0 @@
.ec-canvas {
width: 100%;
height: 100%;
}

View File

@ -1,7 +0,0 @@
type Options = {
width?: number;
height?: number;
devicePixelRatio?: number;
};
export declare function init(dom: any, theme?: string | null, options?: Options): any;
export {};

File diff suppressed because one or more lines are too long

View File

@ -1,111 +0,0 @@
export default class WxCanvas {
constructor(ctx, canvasId, isNew, canvasNode) {
this.ctx = ctx;
this.canvasId = canvasId;
this.chart = null;
this.isNew = isNew
if (isNew) {
this.canvasNode = canvasNode;
}
else {
this._initStyle(ctx);
}
// this._initCanvas(zrender, ctx);
this._initEvent();
}
getContext(contextType) {
if (contextType === '2d') {
return this.ctx;
}
}
// canvasToTempFilePath(opt) {
// if (!opt.canvasId) {
// opt.canvasId = this.canvasId;
// }
// return wx.canvasToTempFilePath(opt, this);
// }
setChart(chart) {
this.chart = chart;
}
addEventListener() {
// noop
}
attachEvent() {
// noop
}
detachEvent() {
// noop
}
_initCanvas(zrender, ctx) {
zrender.util.getContext = function () {
return ctx;
};
zrender.util.$override('measureText', function (text, font) {
ctx.font = font || '12px sans-serif';
return ctx.measureText(text);
});
}
_initStyle(ctx) {
ctx.createRadialGradient = () => {
return ctx.createCircularGradient(arguments);
};
}
_initEvent() {
this.event = {};
const eventNames = [{
wxName: 'touchStart',
ecName: 'mousedown'
}, {
wxName: 'touchMove',
ecName: 'mousemove'
}, {
wxName: 'touchEnd',
ecName: 'mouseup'
}, {
wxName: 'touchEnd',
ecName: 'click'
}];
eventNames.forEach(name => {
this.event[name.wxName] = e => {
const touch = e.touches[0];
this.chart.getZr().handler.dispatch(name.ecName, {
zrX: name.wxName === 'tap' ? touch.clientX : touch.x,
zrY: name.wxName === 'tap' ? touch.clientY : touch.y,
preventDefault: () => {},
stopImmediatePropagation: () => {},
stopPropagation: () => {}
});
};
});
}
set width(w) {
if (this.canvasNode) this.canvasNode.width = w
}
set height(h) {
if (this.canvasNode) this.canvasNode.height = h
}
get width() {
if (this.canvasNode)
return this.canvasNode.width
return 0
}
get height() {
if (this.canvasNode)
return this.canvasNode.height
return 0
}
}

View File

@ -1,124 +0,0 @@
import zIndex from '../behaviors/zIndex';
import hover from '../behaviors/hover';
Component({
behaviors: [zIndex,hover],
externalClasses: ['l-class-title', 'l-class-item', 'l-class-cancel','l-title-class','l-item-class','l-cancel-class'],
properties: {
locked: Boolean,
showCancel: Boolean,
show: Boolean,
itemList: Array,
cancelText: {
type: String,
value: '取消'
},
title: String,
zIndex:{
type:Number,
value: 777
},
openApi: {
type: Boolean,
value: true,
}
},
data: {
success: '',
fail: '',
isIphoneX: false
},
attached() {
if (this.data.openApi) {
this.initActionSheet();
}
this.initUIAdapter();
},
pageLifetimes: {
show() {
if (this.data.openApi) {
this.initActionSheet();
}
},
},
methods: {
/**
* 区分UI尺寸
*/
initUIAdapter() {
wx.getSystemInfo({
success: (res) => {
this.setData({
isIphoneX: res.model === 'iPhone X',
});
}
});
},
initActionSheet() {
wx.lin = wx.lin || {};
wx.lin.showActionSheet = (options={}) => {
const {
itemList = [],
success = null,
fail = null,
title = '',
locked = false,
cancelText = '取消',
showCancel = false,
} = options;
this.setData({
itemList: itemList.slice(0, 10),
success,
fail,
title,
locked,
cancelText,
showCancel,
show: true,
});
return this;
};
},
handleClickItem(e) {
const {
success
} = this.data;
success && success({ ...e.currentTarget.dataset });
this.triggerEvent('linitemtap', { ...e.currentTarget.dataset },{ bubbles: true, composed: true });
this._hideActionSheet();
},
_showActionSheet() {
this.setData({
show: true
});
},
_hideActionSheet() {
this.setData({
show: false
});
},
handleClickCancel() {
const {
fail
} = this.data;
fail && fail({
errMsg: 'showactionsheet:fail cancel'
});
this.triggerEvent('lincancel', {
errMsg: 'showactionsheet:fail cancel'
},{ bubbles: true, composed: true });
this._hideActionSheet();
},
handleClickPopUp() {
if (!this.data.locked) {
this.handleClickCancel();
}
},
}
});

View File

@ -1,8 +0,0 @@
{
"component": true,
"usingComponents": {
"l-icon":"../icon/index",
"l-popup":"../popup/index",
"l-button":"../button/index"
}
}

View File

@ -1,34 +0,0 @@
.l-action-sheet {
background:#f7f7f7;
}
.l-item-button {
height: 88rpx;
line-height: 88rpx;
text-align: center;
background: #fff;
border-bottom: 2rpx solid #F3F3F3;
font-size: 28rpx;
color: #45526B;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
overflow: hidden;
}
.l-cancel {
margin-top: 12rpx;
}
.l-cancel-x .l-item-button{
padding-bottom: 44rpx;
}
.l-image-button > .l-button-text{
margin-left: 20rpx;
}
.list-hover{
opacity: .8;
}

View File

@ -1,26 +0,0 @@
<l-popup show="{{show}}" showMask="{{true}}" contentAlign="bottom" locked="{{locked}}" bind:lintap="handleClickPopUp" z-index="{{zIndex}}">
<view class='l-action-sheet'>
<view class="l-item-button l-class-title l-title-class" wx:if="{{title}}">
{{ title }}
</view>
<view wx:for="{{ itemList }}" wx:key="name" hover-class="{{isHover?'list-hover':''}}">
<l-button bind:lintap="handleClickItem" data-index="{{ index }}" data-item="{{ item }}" open-type="{{ item.openType }}" icon="{{ item.icon }}" type="default" size="large" special="{{true}}" long>
<view style="{{ item.color ? 'color: ' + item.color : '' }}" class="l-item-button l-class-item l-item-class {{item.image || item.icon ? 'l-image-button':''}}">
<image wx:if="{{item.image}}" class="l-button-image" src="{{item.image}}" style="{{item.imageStyle}}"/>
<l-icon
wx:elif="{{ item.icon }}"
name="{{ item.icon }}"
l-class="l-item-button"
size="{{ item.iconSize }}"
color="{{item.iconColor?item.iconColor:item.color}}"></l-icon>
<text class="l-button-text">{{ item.name }}</text>
</view>
</l-button>
</view>
<view class="l-cancel l-class-cancel l-cancel-class {{isIphoneX ? 'l-cancel-x':''}}" wx:if="{{ showCancel }}" hover-class="{{isHover?'list-hover':''}}">
<l-button type="default" size="large" long="true" bind:lintap="handleClickCancel" special="{{true}}">
<view class="l-item-button l-cancel-button">{{ cancelText }}</view>
</l-button>
</view>
</view>
</l-popup>

View File

@ -1,189 +0,0 @@
// miniprogram_npm/lin-ui/album/index.js
Component({
externalClasses: ['l-class', 'l-single-image-class', 'l-multi-image-class'],
properties: {
urls: {
type: Array
},
// 是否可以预览
preview: {
type: Boolean,
value: true
},
gapRow: {
type: Number,
value: 10,
},
gapColumn: {
type: Number,
value: 10,
},
// 单图时长边大小
singleSize: {
type: Number,
value: 360,
},
// 多图时图片边长
multipleSize: {
type: Number,
value: 158,
},
// 单图显示模式
singleMode: {
type: String,
value: 'aspectFit',
},
// 多图显示模式
multipleMode: {
type: String,
value: 'aspectFill',
},
key: {
type: String,
value: 'url'
},
maxNumber: {
type: Number,
value: 9
},
customRowNumber: {
type: Boolean,
value: false
},
everyRowNumber: {
type: Number,
value: 3
},
previewFullImage: {
type: Boolean,
value: true,
}
},
data: {
// 传值方式是新方式还是旧方式
newType: true,
// 单图短边大小
shortSideValue: 0,
// 用于显示的图片列表
showUrls: [],
// 传入的url长度是否大于maxNumber指定的数量
isLong: false,
},
observers: {
'urls': function () {
this.init();
}
},
methods: {
/**
* urls 数据变化后进行初始化
*/
init() {
// 取出参数
let {urls, maxNumber, key} = this.data;
// 如果 urls 长度超出指定图片数量,则将其截断
if (urls.length > maxNumber) {
urls = urls.slice(0, maxNumber);
this.setData({
isLong: true,
});
}
this.setData({
showUrls: urls
});
if (!this.data.customRowNumber) {
let urlLength = this.data.showUrls.length;
if (urlLength > 1 && urlLength < 5 && urlLength !== 3) {
this.setData({
everyRowNumber: 2
});
} else (this.setData({
everyRowNumber: 3
}));
}
// 判断传入模式
const newType = this.judgeType();
this.setData({
newType
});
if (urls.length === 1) {
this.horizontalOrVertical(newType ? urls[0][key] : urls[0]);
}
},
// 判断传入的urls是字符串列表(old模式)还是对象列表(new模式)
judgeType() {
const urls = this.data.urls;
if (urls.length !== 0) {
if (typeof (urls[0]) !== 'object') {
return false;
}
}
return true;
},
//判断照片是横屏还是竖屏并计算短边的长度
//如不指定短边的长度短边会默认显示image组件的长度
horizontalOrVertical: function (src) {
wx.getImageInfo({
src: src,
success: (res) => {
const longSide = res.width >= res.height ? res.width : res.height;
const shortSide = res.width >= res.height ? res.height : res.width;
this.setData({
horizontalScreen: res.width >= res.height,
shortSideValue: shortSide * this.data.singleSize / longSide
});
}
});
},
onPreviewTap(e) {
const index = e.currentTarget.id;
let urls;
if (this.data.previewFullImage) {
urls = this.data.urls;
} else {
urls = this.data.showUrls;
}
let tempFilePath = '';
let previewImageList = [];
const newType = this.data.newType;
const key = this.data.key;
if (newType) {
tempFilePath = urls[index][key];
for (let i = 0; i < urls.length; i++) {
previewImageList.push(urls[i][key]);
}
} else {
tempFilePath = urls[index];
previewImageList = urls;
}
let detail = {
index, // 下标
current: urls[index], // 当前显示图片的http链接
all: urls // 需要预览的图片http链接列表
};
let option = {};
if (this.data.preview === true) {
wx.previewImage({
current: tempFilePath, // 当前显示图片的http链接
urls: previewImageList // 需要预览的图片http链接列表
});
}
this.triggerEvent('lintap', detail, option);
}
}
});

View File

@ -1,5 +0,0 @@
{
"component": true,
"usingComponents": {
}
}

View File

@ -1,48 +0,0 @@
/* miniprogram_npm/lin-ui/picture-album/index.wxss */
.container {
display: grid;
}
.vertical {
height: 360rpx;
}
.parent {
display: inline-grid;
grid-template-columns: repeat(auto-fill);
}
.child {
box-sizing: border-box;
background-color: white;
flex: 0 0 44%;
height: 100px;
border: 1px solid red;
margin-top: 4%;
margin-left: 2%;
margin-right: 2%;
}
.dimback {
background: #000;
}
.dim {
opacity: 0.6;
filter: alpha(opacity=60);
}
.imageContainer {
position: relative;
}
.imageContainer:last-child>.text {
color: white;
font-weight: bold;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: larger;
}

View File

@ -1,12 +0,0 @@
<wxs src="index.wxs" module="album"></wxs>
<!-- 最外层 view 用于修复 issue 1100 -->
<view class="l-class" style="display:flex">
<view style="{{album.gridStyle(gapRow, gapColumn, multipleSize, everyRowNumber)}}">
<block wx:for="{{showUrls}}" wx:key="index" class="child">
<view class="imageContainer {{album.dimBack(isLong, index, maxNumber, previewFullImage)}}" style="{{album.blockStyle(urls, horizontalScreen, shortSideValue, singleSize, multipleSize)}}">
<image class="{{album.blockClass(urls, horizontalScreen) + ' ' + album.dim(isLong, index, maxNumber, previewFullImage)}}" id='{{index}}' bind:tap="onPreviewTap" style="{{album.blockStyle(urls, horizontalScreen, shortSideValue, singleSize, multipleSize)}}" src="{{newType?item[key]:item}}" mode="{{urls.length === 1?singleMode:multipleMode}}" />
<view wx:if="{{album.image(isLong, index, maxNumber, previewFullImage)}}" class="text">+{{urls.length-maxNumber}}</view>
</view>
</block>
</view>
</view>

View File

@ -1,79 +0,0 @@
var containerStyle = function (urls, multipleSize, gapRow, gapColumn) {
if (urls.length === 2 || urls.length === 4) {
return 'width:' + (2 * multipleSize + gapRow) + 'rpx; grid-row-gap:' + gapColumn + 'rpx; grid-column-gap:' + gapRow + 'rpx;grid-template-columns:repeat(auto-fit, ' + multipleSize + 'rpx);'
} else {
return 'width:' + (3 * multipleSize + 2 * gapRow) + 'rpx; grid-row-gap:' + gapColumn + 'rpx; grid-column-gap:' + gapRow + 'rpx;grid-template-columns:repeat(auto-fit, ' + multipleSize + 'rpx);'
}
}
var blockClass = function (urls, horizontalScreen) {
if (urls.length === 1) {
if (horizontalScreen) {
return 'l-single-image-class'
} else {
return 'vertical l-single-image-class'
}
} else {
return 'l-multi-image-class'
}
}
var blockStyle = function (urls, horizontalScreen, shortSideValue, singleSize, multipleSize) {
if (urls.length === 1) {
if (horizontalScreen) {
return 'height:' + shortSideValue + 'rpx;width:' + singleSize + 'rpx;'
} else {
return 'width:' + shortSideValue + 'rpx;height:' + singleSize + 'rpx;'
}
} else {
return 'height:' + multipleSize + 'rpx;width:' + multipleSize + 'rpx;'
}
}
var gridStyle = function (gapRow, gapColumn, multipleSize, everyRowNumber) {
return 'display:inline-grid;grid-template-columns: repeat(' + everyRowNumber + ',' + multipleSize + 'rpx);grid-row-gap:' + gapRow + 'rpx;grid-column-gap:' + gapColumn + 'rpx;'
}
var dimBack = function (isLong, index, maxNumber, previewFullImage) {
if (previewFullImage) {
if (isLong) {
if (index == maxNumber - 1) {
return 'dimback'
}
}
}
return ''
}
var dim = function (isLong, index, maxNumber, previewFullImage) {
if (previewFullImage) {
if (isLong) {
if (index == maxNumber - 1) {
return 'dim'
}
}
}
return ''
}
var image = function (isLong, index, maxNumber, previewFullImage) {
if (previewFullImage) {
if (isLong) {
if (index == maxNumber - 1) {
return true
}
}
}
return false
}
module.exports = {
containerStyle: containerStyle,
blockClass: blockClass,
blockStyle: blockStyle,
gridStyle: gridStyle,
dimBack: dimBack,
dim: dim,
image: image,
}

View File

@ -1,166 +0,0 @@
import validator from '../behaviors/validator';
import zIndex from '../behaviors/zIndex';
const detail = true;
const option = {
bubbles: true,
composed: true
};
Component({
/**
* 组件的属性列表
*/
behaviors: [zIndex, validator],
externalClasses: ['l-class', 'l-panel-class', 'l-bg-class', 'l-header-class'],
options: {
multipleSlots: true // 在组件定义时的选项中启用多slot支持
},
properties: {
// 显示与隐藏
show: {
type: Boolean,
value: false
},
// 最大高度
maxHeight: {
type: Number,
value: 600
},
// 最小高度
minHeight: {
type: Number,
value: 200
},
// 顶部弧度
arcRadius: {
type: Number,
value: 18
},
// 动画效果的显示和隐藏
transition: {
type: Boolean,
value: true
},
// 锁定
locked: {
type: Boolean,
value: false
},
// 背景透明度
opacity: {
type: Number,
value: 0.4
},
// 弹出方向
direction: {
type: String,
options: ['top', 'bottom'],
value: 'bottom'
},
// header是否吸顶
headerFixed: {
type: Boolean,
value: true
}
},
/**
* 组件的初始数据
*/
data: {
_arcRadiusTop: 12,
_ardRadiusBottom: 18,
arcStyle: ''
},
/**
* 侦听器
*/
observers: {
'show': function (show) {
if (show) {
this.triggerEvent('linshow', detail, option);
this.getArcPopupStyle();
} else {
this.triggerEvent('linclose', detail, option);
}
},
'arcRadius': function (arcRadius) {
if (this.properties.direction === 'top') {
this.data._arcRadiusTop = arcRadius;
} else {
this.data._ardRadiusBottom = arcRadius;
}
this.getArcPopupStyle();
}
},
pageLifetimes: {
show() {
this._init();
},
},
/**
* 组件的方法列表
*/
methods: {
_init() {
wx.lin = wx.lin || {};
wx.lin.showArcPopup = (options) => {
const {
zIndex = 99,
tranistion = true,
direction = 'bottom',
locked = false
} = {
...options
};
this.setData({
zIndex,
tranistion,
direction,
locked,
show: true
});
};
wx.lin.hideArcPopup = () => {
this.setData({
show: false
});
};
},
getArcPopupStyle() {
const direction = this.properties.direction;
const arcRadiusTop = this.data._arcRadiusTop;
const ardRadiusBottom = this.data._ardRadiusBottom;
const maxHeight = this.properties.maxHeight;
const minHeight = this.properties.minHeight;
const arcStyle = `
border-bottom-left-radius:${direction === 'top' ? arcRadiusTop : 0}rpx;
border-bottom-right-radius:${direction === 'top' ? arcRadiusTop : 0}rpx;
border-top-left-radius:${direction === 'bottom' ? ardRadiusBottom : 0}rpx;
border-top-right-radius:${direction === 'bottom' ? ardRadiusBottom : 0}rpx;
max-height:${maxHeight}rpx;
min-height:${minHeight}rpx;
`;
this.setData({
arcStyle,
});
},
onArcPopupTap() {
if (this.data.locked) {
return;
}
if (this.properties.show) {
this.setData({
show: false
});
}
}
},
ready() {
this.getArcPopupStyle();
}
});

View File

@ -1,6 +0,0 @@
{
"component": true,
"usingComponents": {
"l-popup": "../popup/index"
}
}

View File

@ -1,25 +0,0 @@
.container-arc-popup {
width: 100%;
}
.arc-popup {
overflow: hidden;
width: 100%;
background: #fff;
}
.content-arc-popup {
padding: 30rpx;
box-sizing: border-box;
}
.header-popup {
width: 100%;
z-index: 999;
&.fixed {
position: sticky;
top: 0;
background-color: #fff;
}
}

View File

@ -1,24 +0,0 @@
<l-popup
show="{{show}}"
contentAlign="{{direction}}"
transition="{{transition}}"
opacity="{{opacity}}"
locked="{{locked}}"
z-index="{{zIndex}}"
l-class="l-class"
l-bg-class="l-bg-class"
bind:lintap="onArcPopupTap"
>
<scroll-view
scroll-y="true"
class="arc-popup l-panel-class"
style="{{arcStyle}}"
>
<view class="header-popup {{headerFixed ? 'fixed' : ''}} l-header-class">
<slot name="header" />
</view>
<view class="content-arc-popup">
<slot />
</view>
</scroll-view>
</l-popup>

View File

@ -1,70 +0,0 @@
Component({
externalClasses: [
'l-class',
'l-class-text',
'l-text-class'
],
properties: {
icon: String,
iconColor: {
type: String,
value: '#3963BC'
},
iconSize: {
type: String,
value: '28'
},
text: String,
src: String,
openData: {
type: Array,
observer: '_initOpenData'
},
shape: {
type: String,
value: 'circle'
},
mode: {
type: String,
value: 'scaleToFill'
},
size: {
type: Number,
value: 120,
},
placement: {
type: String,
value: 'right'
},
},
data: {
_isHaveUserNickName: false,
_isHaveUserAvatarUrl: false,
_iconSize: '',
_iconColor: '#ffffff'
},
methods: {
_initOpenData: function (openData) {
this._isHaveUserAvatarUrl(openData);
this._isHaveUserNickName(openData);
},
_isHaveUserAvatarUrl: function (openData) {
this.setData({
_isHaveUserAvatarUrl: openData.indexOf('userAvatarUrl') !== -1
});
},
_isHaveUserNickName: function (openData) {
this.setData({
_isHaveUserNickName: openData.indexOf('userNickName') !== -1
});
},
tapAvatar: function (e) {
this.triggerEvent('lintap', e, {
bubbles: true,
composed: true
});
},
}
});

View File

@ -1,6 +0,0 @@
{
"component": true,
"usingComponents": {
"l-icon":"../icon/index"
}
}

View File

@ -1,80 +0,0 @@
@import "../styles/_base.less";
.l-avatar {
display: inline-flex;
justify-content: center;
align-items: center;
}
.l-avatar-image {
flex: 1;
display: inline-flex;
justify-content: center;
align-items: center;
background: @avatar-bg;
overflow: hidden;
}
.l-avatar-text {
display: inline-block;
height: max-content;
width: max-content;
font-size:28rpx;
color:rgba(69,82,107,1);
line-height:40px;
}
.open-data {
width: 100%;
height: 100%;
}
.l-avatar-text .open-data,
.l-avatar-text .l-avatar-text-text {
font-size:inherit;
color:inherit;
line-height:inherit;
}
.l-square {
border-radius: 8rpx;
}
.l-circle {
border-radius: 50%;
}
.l-placement-left,
.l-placement-right{
align-items: center;
justify-content: center;
}
.l-placement-left{
margin-right: 24rpx;
flex-direction: row-reverse;
}
.l-placement-left .l-avatar-text {
margin-right: 24rpx;
}
.l-placement-right {
flex-direction: row;
}
.l-placement-right .l-avatar-text {
margin-left: 24rpx;
}
.l-placement-top {
flex-direction: column-reverse;
}
.l-placement-top .l-avatar-text {
margin-bottom: 12rpx;
}
.l-placement-bottom {
flex-direction: column;
}
.l-placement-bottom .l-avatar-text {
margin-top: 12rpx;
}

View File

@ -1,12 +0,0 @@
<view class="l-avatar {{text||_isHaveUserNickName?'l-placement-'+placement:''}}" mut-bind:tap="tapAvatar">
<view class="l-avatar-image {{shape?'l-'+shape:''}} l-class" wx:if="{{_isHaveUserAvatarUrl||icon||src}}" style="width:{{size}}rpx;height:{{size}}rpx;min-width:{{size}}rpx;min-height:{{size}}rpx;">
<open-data class="open-data" wx:if="{{_isHaveUserAvatarUrl}}" type="userAvatarUrl" />
<l-icon wx:elif="{{icon}}" size="{{iconSize || size*0.6}}" color="{{iconColor||'#ffffff'}}" name="{{icon}}" />
<image wx:elif="{{src}}" src="{{src}}" mode="{{mode}}" style="width:{{size}}rpx;height:{{size}}rpx" />
</view>
<view class="l-avatar-text l-class-text l-text-class" wx:if="{{text||_isHaveUserNickName}}">
<open-data class="open-data" wx:if="{{_isHaveUserNickName}}" type="userNickName" />
<text class="l-avatar-text-text" wx:elif="{{text}}">{{text}}</text>
</view>
</view>

View File

@ -1,93 +0,0 @@
import validator from '../behaviors/validator';
Component({
externalClasses: ['l-class', 'l-class-self', 'l-self-class'],
behaviors: [validator],
properties: {
// 红点模式
dot: {
type: Boolean,
value: false
},
shape: {
type: String,
value: 'horn',
options: ['horn', 'circle']
},
value: {
type: String,
value: '0'
},
mode: {
type: String,
value: 'number',
options: ['number', 'text']
},
// 数字最大值
maxCount: {
type: Number,
value: 99
},
// 数字形式
numberType: {
type: String,
value: 'overflow',
options: ['overflow', 'limit', 'ellipsis']
},
show: {
type: Boolean,
value: true
}
},
data: {
finalCount: 0
},
observers: {
'value': function () {
this.finalCount();
}
},
methods: {
// 最终数字
finalCount() {
if (isNaN(Number(this.data.value)) || (this.data.mode === 'text')) {
this.setData({
finalCount: this.data.value
});
} else {
this.switchType();
}
},
switchType() {
switch (this.data.numberType) {
case 'overflow':
this.setData({
finalCount: Number(this.data.value) > Number(this.data.maxCount) ? `${this.data.maxCount}+` : this.data.value
});
break;
case 'ellipsis':
this.setData({
finalCount: Number(this.data.value) > Number(this.data.maxCount) ? '...' : this.data.value
});
break;
case 'limit':
this.setData({
finalCount: Number(this.data.value) > 999 ? (Number(this.data.value) >= 9999 ? Math.floor(this.data.value / 10000 * 100) / 100 + 'w' : Math.floor(this.data.value / 1000 * 100) / 100 + 'k') : this.data.value
});
break;
default:
this.setData({
finalCount: Number(this.data.value)
});
break;
}
},
// 点击事件
handleTap() {
this.triggerEvent('lintap', {}, {
bubbles: true,
composed: true
});
},
}
});

View File

@ -1,6 +0,0 @@
{
"component": true,
"usingComponents": {
}
}

View File

@ -1,54 +0,0 @@
@import "../styles/_base.less";
.l-badge {
position : relative;
display : inline-block;
line-height : 1;
vertical-align: middle;
&-content {
max-width : 650rpx;
left : 70%;
background-color : #ff474b;
color : #fff;
position : absolute;
font-size : 20rpx;
display : inline-block;
white-space : nowrap;
text-overflow : ellipsis;
overflow : hidden;
text-align : center;
box-sizing : border-box;
z-index : 10;
letter-spacing : .5rpx;
&-horn {
height : 28rpx;
min-width : 54rpx;
padding : 0 8rpx;
border-radius: 14rpx 14rpx 14rpx 0rpx;
line-height : 28rpx;
top : -10rpx;
}
&-circle {
height : 32rpx;
min-width : 32rpx;
padding : 0 10rpx;
border-radius: 16rpx;
line-height : 32rpx;
top : -10rpx;
}
}
&-dot {
height : 16rpx;
width : 16rpx;
transform : translateX(50%);
border-radius : 50%;
background-color: #ff474b;
position : absolute;
top : -4rpx;
right : 0rpx;
}
}

View File

@ -1,7 +0,0 @@
<view class="l-badge" mut-bind:tap="handleTap">
<slot/>
<block wx:if="{{show}}">
<view wx:if="{{dot}}" class="l-badge-dot l-class l-class-self l-self-class"></view>
<view wx:else class="{{'l-badge-content-'+shape}} l-badge-content l-class l-class-self l-self-class">{{finalCount}}</view>
</block>
</view>

View File

@ -1,19 +0,0 @@
// eslint-disable-next-line no-undef
export default Behavior({
behaviors: [],
properties: {},
data: {
distance: 0
},
attached(){
this.offsetMargin();
},
methods: {
offsetMargin() {
const { windowHeight, screenHeight } = wx.getSystemInfoSync();
this.setData({
distance: (screenHeight-windowHeight )
});
}
}
});

View File

@ -1,222 +0,0 @@
// eslint-disable-next-line no-undef
export default Behavior({
behaviors: [],
properties: {
time: {
optionalTypes: [String, Object],
value: new Date().getTime() + 86400000,
observer: function (newVal, oldVal) {
if (newVal && !oldVal) {
this.getLatestTime();
}
}
},
status: {
type: Boolean,
value: true,
observer: function (newVal) {
if (newVal) {
this.init();
} else if (!newVal) {
clearInterval(this.data.timer);
}
}
},
timeType: {
type: String,
value: 'datetime'
},
format: {
type: String,
value: '{%d}天{%h}时{%m}分{%s}秒'
},
isZeroPadd: {
type: Boolean,
value: true,
},
countdownType: {
type: String,
value: 'normal'
},
isClearInterval: {
type: Boolean,
value: true
}
},
data: {
initAddTime: 0,
timer: null,
date: [],
},
ready: function () {
this.getLatestTime();
},
detached: function () {
if (this.data.isClearInterval) {
clearInterval(this.data.timer);
}
},
pageLifetimes: {
hide() {
if (this.data.isClearInterval) {
clearInterval(this.data.timer);
}
},
show() {
if (this.data.isClearInterval) {
this.getLatestTime();
}
}
},
methods: {
// 自动补零
zeroPadding(num) {
num = num.toString();
return num[1] ? num : '0' + num;
},
init() {
clearInterval(this.data.timer);
const timer = setTimeout(() => {
this.getLatestTime.call(this);
}, 1000);
this.setData({
timer
});
},
getLatestTime() {
let {
time,
status,
timeType,
initAddTime,
countdownType,
} = this.data;
// IOS不支持2019-04-23 的日期格式
let countDownTime = time;
if (countdownType === 'normal') { //当countdownType === normal时不影响之前的代码
if (timeType !== 'second') {
countDownTime = typeof time === 'string' ? countDownTime.replace(/-/g, '/') : countDownTime;
countDownTime = Math.ceil((new Date(countDownTime).getTime() - new Date().getTime()) / 1000);
}
if (countDownTime < 0 && timeType !== 'second') {
this._getTimeValue(0);
this.CountdownEnd();
return;
}
if (countDownTime - initAddTime > 0) {
this.getLatestForCountDown(countDownTime);
} else if (countDownTime - initAddTime < 0) {
this.getLatestForAddTime(countDownTime);
} else if (countDownTime - initAddTime === 0) {
if (initAddTime <= 0) {
this._getTimeValue(countDownTime);
}
this.CountdownEnd();
}
if (status && countDownTime - initAddTime !== 0) {
this.init.call(this);
}
} else if (countdownType === 'anniversary') { // 当countdownType === anniversary时为纪念日模式
if (timeType === 'second') { // 纪念日模式不能设置timeType === second
console.error(`countdownType为${countdownType}类型时不可设置timeType值为second`);
} else {
countDownTime = typeof time === 'string' ? countDownTime.replace(/-/g, '/') : countDownTime;
countDownTime = Math.ceil((new Date().getTime() - new Date(countDownTime).getTime()) / 1000);
if (countDownTime >= 0) { // countDownTime计算结果不能为负数
this.getLatestForCountDown(countDownTime);
this.init.call(this);
} else {
console.error('time传值错误');
}
}
} else { // countdownType 不能设置为 normalanniversary 以外的值
console.error('错误的countdownType类型');
}
},
getLatestForAddTime(countDownTime) {
let {
initAddTime
} = this.data;
if (initAddTime !== Math.abs(countDownTime)) {
initAddTime++;
this._getTimeValue(initAddTime);
this.setData({
initAddTime
});
}
},
getLatestForCountDown(countDownTime) {
this._getTimeValue(countDownTime);
this.setData({
time: this.data.timeType === 'second' ? --countDownTime : this.data.time,
});
},
_getTimeValue(countDownTime) {
const {
format
} = this.data;
const date = [];
const fomatArray = format.split(/(\{.*?\})/);
const formatType = [{
key: '{%d}',
type: 'day',
count: 86400
}, {
key: '{%h}',
type: 'hour',
count: 3600
}, {
key: '{%m}',
type: 'minute',
count: 60
}, {
key: '{%s}',
type: 'second',
count: 1,
}];
let diffSecond = countDownTime;
formatType.forEach(format => {
const index = this._findTimeName(fomatArray, format.key);
if (index === -1) return;
const name = fomatArray[index];
const formatItem = {
type: format.type,
name,
value: parseInt(diffSecond / format.count)
};
if (this.data.isZeroPadd) {
formatItem.value = this.zeroPadding(formatItem.value);
}
diffSecond %= format.count;
date.push(formatItem);
});
this.setData({
date
});
return date;
},
_findTimeName(fomatArray, str) {
const index = fomatArray.indexOf(str);
if (index === -1) return -1;
return index + 1;
},
CountdownEnd() {
this.triggerEvent('linend', {});
},
}
});

View File

@ -1,10 +0,0 @@
// eslint-disable-next-line no-undef
export default Behavior({
behaviors: [],
properties: {
isHover:{
type: Boolean,
value: true
}
}
});

View File

@ -1,144 +0,0 @@
import Schema from '../common/async-validator/index';
import validator from '../behaviors/validator';
/**
* @param tipType String [toast , message , text]
*/
// eslint-disable-next-line no-undef
export default Behavior({
behaviors: [validator],
properties: {
// 校验
rules: {
optionalTypes: [Object, Array],
value: []
},
tipType: {
type: String,
value: 'toast',
options: ['toast', 'message', 'text']
}
},
data: {
schema: '',
tipFun: {
'message': 'showMessage',
'toast': 'showToast',
},
tipContent: {
'message': 'content',
'toast': 'title',
},
errorText: '',
errors: []
},
methods: {
initRules() {
// const rulesName = this.data.name;
const {
rules
} = this.data;
if (!rules) return;
// 如果rule 是单个object
if (Object.prototype.toString.call(rules) === '[object Object]') {
this.data.rules = [rules];
}
this.data.rules.forEach(item => {
if (!item.trigger) {
item.trigger = [];
return;
}
if (typeof item.trigger === 'string') {
item.trigger = [item.trigger];
return;
}
// if(Object.prototype.toString.call(item.trigger) === '[object Object]') {
// item.trigger = ['blur'];
// return;
// }
});
},
getNeedValidateRule(type) {
const rulesName = this.data.name;
const {
rules
} = this.data;
if (!rules) return;
const list = type ? rules.filter(item => {
return item.trigger.indexOf(type) > -1;
}) : rules;
const schema = new Schema({
[rulesName]: list,
});
this.setData({
schema,
});
return list;
},
validatorData(value, type) {
const {
tipType,
tipFun,
tipContent
} = this.data;
const rules = this.getNeedValidateRule(type);
if (!rules) return;
// 把空字符串设置为 undefined ,见 issue 856
// async-validator 对空字符串会进行类型检查与required会冲突
Object.getOwnPropertyNames(value).forEach((key) => {
if (value[key] === '') {
value[key] = undefined;
}
});
this.data.schema.validate(value, (errors) => {
this.setData({
errors: errors || []
});
this.triggerEvent('linvalidate', {
errors,
isError: !!errors
});
if (errors && tipType) {
const funName = tipFun[tipType];
const contentName = tipContent[tipType];
if (tipType === 'text') {
this.setData({
errorText: errors[0].message
});
return errors;
}
if (!wx.lin || !wx.lin[funName]) {
wx.showToast({
icon: 'none',
title: `请在页面内引入${tipType}组件`
});
return errors;
}
wx.lin[funName] && wx.lin[funName]({
[contentName]: errors[0].message,
duration: 1500,
mask: false,
});
return errors;
} else if (!errors && tipType) {
this.setData({
errorText: ''
});
}
});
}
}
});

View File

@ -1,57 +0,0 @@
// eslint-disable-next-line no-undef
export default Behavior({
methods: {
getRect(selector, all = false) {
return new Promise((resolve, reject) => {
const query = wx.createSelectorQuery().in(this);
const type = all ? query.selectAll(selector) : query.select(selector);
type.boundingClientRect((res) => {
if (!res) return reject('找不到元素');
resolve(res);
}).exec();
});
},
queryScrollNode(res, currentIndex, type = 'width') {
if (currentIndex < 0) return;
const currentRect = res[currentIndex];
this.getRect('.l-tabsscroll').then(_ => {
if (!_) return console.error('找不到元素');
const scrollWidth = _[type];
let transformDistance = res
.slice(0, currentIndex)
.reduce((prev, curr) => prev + curr[type], 0);
transformDistance += (currentRect[type] - scrollWidth) / 2;
if (type === 'width') {
this.setData({
transformX: transformDistance,
transformY: 0
});
} else {
this.setData({
transformX: 0,
transformY: transformDistance
});
}
}).catch(err => {
console.error(err);
});
},
queryMultipleNodes() {
const {
placement,
currentIndex
} = this.data;
this.getRect('.l-tabs-item', true)
.then((res) => {
if (['top', 'bottom'].indexOf(placement) !== -1) {
this.queryScrollNode(res, currentIndex);
} else {
this.queryScrollNode(res, currentIndex, 'height');
}
}).catch(err => {
console.error(err);
});
}
}
});

View File

@ -1,122 +0,0 @@
const isObj = (x) => {
const type = typeof x;
return x !== null && (type === 'object' || type === 'function');
};
const getClassNames = (name) => ({
enter: `l-${name}-enter l-${name}-enter-active l-enter-class l-enter-active-class`,
'enter-to': `l-${name}-enter-to l-${name}-enter-active l-enter-to-class l-enter-active-class`,
leave: `l-${name}-leave l-${name}-leave-active l-leave-class l-leave-active-class`,
'leave-to': `l-${name}-leave-to l-${name}-leave-active l-leave-to-class l-leave-active-class`
});
const nextTick = () => new Promise(resolve => setTimeout(resolve, 1000 / 30));
export default (showDefaultValue) => {
// eslint-disable-next-line no-undef
return Behavior({
properties: {
customStyle: String,
show: {
type: Boolean,
value: showDefaultValue,
observer: 'observeShow'
},
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.triggerEvent('linbeforeenter');
Promise.resolve()
.then(nextTick)
.then(() => {
this.checkStatus('enter');
this.triggerEvent('linenter');
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.triggerEvent('linbeforeleave');
Promise.resolve()
.then(nextTick)
.then(() => {
this.checkStatus('leave');
this.triggerEvent('linleave');
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.triggerEvent(`linafter${this.status}`);
const { show, display } = this.data;
if (!show && display) {
this.setData({ display: false });
}
}
}
});
};

View File

@ -1,21 +0,0 @@
// eslint-disable-next-line no-undef
export default Behavior({
definitionFilter(defFields) {
const {
properties
} = defFields;
const propsKey = Object.keys(properties);
propsKey.forEach(name => {
const {
options
} = properties[name];
if (options) {
properties[name].observer = function (newValue) {
if (!options.includes(newValue) && newValue) {
console.error(`${name}: ${newValue} must be in the [${options}]`);
}
};
}
});
}
});

View File

@ -1,26 +0,0 @@
// eslint-disable-next-line no-undef
export default Behavior({
observers: {
'show': function (show) {
show && this.changeStatus();
if (!show) this.setData({
status: show
});
}
},
methods: {
changeStatus() {
this.setData({
status: true
});
if (this.data.timer) clearTimeout(this.data.timer);
this.data.timer = setTimeout(() => {
this.setData({
status: false
});
if (this.data.success) this.data.success();
this.data.timer = null;
}, this.properties.duration);
}
}
});

View File

@ -1,10 +0,0 @@
// eslint-disable-next-line no-undef
export default Behavior({
behaviors: [],
properties: {
zIndex:{
type: Number,
value: 777
}
}
});

View File

@ -1,94 +0,0 @@
import validator from '../behaviors/validator';
Component({
externalClasses: [
'l-class',
'l-label-class',
'l-hover-class',
'l-img-class',
'l-icon-class'
],
behaviors: [validator],
properties: {
// button组建标识
name: {
type: String,
value: 'lin'
},
type: {
type: String,
value: 'default',
options: ['warning', 'success', 'error', 'default']
},
plain: Boolean,
size: {
type: String,
value: 'medium',
options: ['medium', 'large', 'mini', 'long']
},
shape: {
type: String,
value: 'circle',
options: ['square', 'circle', 'semicircle']
},
disabled: {
type: Boolean,
value: false,
},
special: {
type: Boolean,
value: false,
},
loading: {
type: Boolean,
value: false,
},
// 微信原生接口
width: Number,
height: Number,
icon: String,
image: String,
bgColor: String,
iconColor: String,
iconSize: String,
openType: String,
appParameter: String,
lang: String,
hoverStopPropagation: Boolean,
hoverStartTime: {
type: Number,
value: 20
},
hoverStayTime: {
type: Number,
value: 70
},
sessionFrom: {
type: String,
value: ''
},
sendMessageTitle: String,
sendMessagePath: String,
sendMessageImg: String,
showMessageCard: Boolean,
formType: String,
disabledHover: {
type: Boolean,
value: false
}
},
methods: {
// button点击事件
handleTap() {
if (this.data.disabled || this.data.loading) return false;
this.triggerEvent('lintap', {}, {
bubbles: true,
composed: true
});
},
// 开放能力事件回调
openTypeEvent(data) {
this.triggerEvent(data.type, data.detail, {});
}
}
});

View File

@ -1,6 +0,0 @@
{
"component": true,
"usingComponents": {
"l-icon":"../icon/index"
}
}

View File

@ -1,189 +0,0 @@
@import '../styles/_base.less';
@import '../styles/_mixins.less';
.btn-hover::before {
.active();
}
.special-container {
display: flex;
}
.l-btn {
display: inline-flex;
align-items: center;
justify-content: center;
white-space: nowrap;
font-size: 28rpx;
position: relative;
color: #fff;
padding: 0 12rpx;
box-sizing: border-box;
// img-size
&-img {
&-mini {
width: @btn-height-mini / 2;
height: @btn-height-mini / 2;
}
&-medium {
width: @btn-height / 2;
height: @btn-height / 2;
}
&-large {
height: @btn-height-large / 2;
width: @btn-height-large / 2;
}
}
// Size
&-long {
border-radius: 0;
height: 88rpx;
width: 100%;
}
&-medium {
height: @btn-height;
min-width: @btn-width;
}
&-large {
height: @btn-height-large;
min-width: @btn-width-large;
}
&-mini {
height: @btn-height-mini;
min-width: @btn-width-mini;
font-size: @size-font-mini;
}
//Type
&-default {
background-color: @default-color;
}
&-success {
background-color: @success-color;
}
&-warning {
background-color: @warning-color;
color: #333333;
}
&-error {
background-color: @error-color;
}
// Shape
&-square {
border-radius: 0;
}
&-semicircle {
border-radius: @btn-circle-size;
}
&-large&-semicircle {
border-radius: @btn-circle-size-large;
}
&-mini&-semicircle {
border-radius: @btn-circle-size-mini;
}
&-circle {
border-radius: @btn-circle-size / 5;
}
&-large&-circle {
border-radius: @btn-circle-size-large / 5;
}
&-mini&-circle {
border-radius: @btn-circle-size-mini / 5;
}
// Plain
&-plain {
background-color: #fff;
color: @default-color;
border: 2rpx solid @default-color;
}
&-success&-plain {
background-color: #fff;
color: @success-color;
border: 2rpx solid @success-color;
}
&-error&-plain {
background-color: #fff;
color: @error-color;
border: 2rpx solid @error-color;
}
&-warning&-plain {
background-color: #fff;
color: @warning-color;
border: 2rpx solid @warning-color;
}
// Loading
&-loading {
opacity: 0.6;
display: inline-block;
vertical-align: middle;
width: 24rpx;
height: 24rpx;
background: transparent;
border-radius: 50%;
border: 4rpx solid @btn-loading-color;
border-color: @btn-loading-color @btn-loading-color @btn-loading-color
transparent;
animation: btn-spin 0.6s linear;
animation-iteration-count: infinite;
&-default {
border: 4rpx solid @default-color;
border-color: @default-color @default-color @default-color
transparent;
}
&-success {
border: 4rpx solid @success-color;
border-color: @success-color @success-color @success-color
transparent;
}
&-error {
border: 4rpx solid @error-color;
border-color: @error-color @error-color @error-color transparent;
}
&-warning {
border: 4rpx solid @warning-color;
border-color: @warning-color @warning-color @warning-color
transparent;
}
}
// Disabled
&-disabled {
opacity: 0.8;
}
}
.icon {
display: flex !important;
}
.margin {
&-mini {
margin-right: 10rpx;
}
&-medium {
margin-right: 18rpx;
}
&-large {
margin-right: 24rpx;
}
&-long {
margin-right: 24rpx;
}
}
@keyframes btn-spin {
0% {
transform: rotate(0);
}
100% {
transform: rotate(360deg);
}
}

View File

@ -1,40 +0,0 @@
<label for="{{name}}" mut-bind:tap="handleTap" class="l-label-class">
<block wx:if="{{special}}">
<view class="special-container l-class">
<slot/>
</view>
</block>
<block wx:else>
<view class="l-btn {{ 'l-btn-' + size }} {{ 'l-btn-' + type }} {{ 'l-btn-' + shape }} {{plain?'l-btn-plain':''}} {{ disabled ? 'l-btn-disabled' : ''}} l-class "
hover-class="{{disabled?'':disabledHover?'':'btn-hover l-hover-class'}}"
hover-stop-propagation="{{hoverStopPropagation}}"
hover-start-time="{{hoverStartTime}}"
hover-stay-time="{{hoverStayTime}}"
style="{{width?'min-width:'+width+'rpx;':''}} {{height?'height:'+height+'rpx;'+'line-height:'+height+'rpx;':''}} {{size=='long'?'border-radius:0;':''}} {{'background-color:'+bgColor}}">
<view wx:if="{{loading}}" class="l-btn-loading {{'margin-' + size}} {{ plain ?'l-btn-loading-' + type : '' }}"></view>
<l-icon l-class="l-icon-class" class="{{'margin-' + size}}" wx:if="{{icon}}" name="{{icon}}" color="{{iconColor}}" size="{{iconSize}}" />
<slot/>
</view>
</block>
</label>
<button style="position: absolute;top: -999px;left: -999px;"
wx:if="{{openType}}"
id="{{name}}"
lang="{{lang}}"
form-type="{{formType}}"
open-type="{{openType}}"
app-parameter="{{ appParameter }}"
hover-stop-propagation="{{ hoverStopPropagation }}"
hover-start-time="{{ hoverStartTime }}"
hover-stay-time="{{ hoverStayTime }}"
session-from="{{ sessionFrom }}"
send-message-title="{{ sendMessageTitle }}"
send-message-path="{{ sendMessagePath }}"
send-message-img="{{ sendMessageImg }}"
show-message-card="{{ showMessageCard }}"
bindcontact="openTypeEvent"
bindgetuserinfo="openTypeEvent"
bindgetphonenumber="openTypeEvent"
bindopensetting="openTypeEvent"
bindchooseavatar="openTypeEvent">
</button>

View File

@ -1,29 +0,0 @@
<wxs src="./index.wxs" module="computed"></wxs>
<template name="calendar">
<view class="calendar-container">
<header showTitle="{{ showTitle }}" showSubtitle="{{ showSubtitle }}" title="{{ title }}" subTitle="{{ subTitle }}"></header>
<scroll-view class="calendar-body-wrap" scroll-y scroll-into-view="{{ scrollIntoViewIndex }}">
<mounth
wx:for="{{ computed.getMonths(minDate, maxDate) }}"
wx:key="index"
id="month{{ index }}"
class="month"
data-date="{{ item }}"
date="{{ item }}"
minDate="{{ minDate }}"
maxDate="{{ maxDate }}"
currentDate="{{ currentDate }}"
type="{{ type }}"
bind:clickDay="clickDay"
showMonthTitle="{{ index !== 0 }}"
formatter="{{ formatter }}"
color="{{ color }}"
>
</mounth>
</scroll-view>
<view>
<l-button type="default" l-class="bottom-button" size="long" bind:lintap="onClickConfirm" bg-color="{{ color }}">{{confirmText}}</l-button>
</view>
</view>
</template>

View File

@ -1,16 +0,0 @@
Component({
data: {},
properties: {
text: null,
topInfo: null,
bottomInfo: null,
type: null,
color: {
type: String,
value: ''
}
},
methods: {
}
});

View File

@ -1,3 +0,0 @@
{
"component": true
}

View File

@ -1,58 +0,0 @@
@import "../../../styles/_base.less";
.calendar-day-container{
display: flex;
flex-direction: column;
height: 100%;
align-items: center;
position: relative;
color: #666;
&.selected{
background-color: @default-color;
color: #ffffff;
border-radius: 8rpx;
}
&.start{
background-color: @default-color;
color: #ffffff;
border-radius: 8rpx;
}
&.end{
background-color: @default-color;
color: #ffffff;
border-radius: 8rpx;
}
&.disabled{
color: #c8c9cc;
cursor: default;
background: #ffffff;
}
&.middle{
color: @default-color;
&::after{
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: currentColor;
opacity: 0.1;
content: '';
}
}
// background-color: red;
// color: #eff9f0;
.top{
height: 24rpx;
line-height: 24rpx;
font-size: 16rpx;
}
.text{
flex: 1;
font-size: 32rpx;
}
.bottom{
height: 24rpx;
line-height: 24rpx;
font-size: 16rpx;
}
}

View File

@ -1,8 +0,0 @@
<wxs src="./index.wxs" module="computed"></wxs>
<view class="calendar-day-container {{ type }}"
style="{{ computed.getDayStyle(type, color) }}"
>
<view class="top">{{ topInfo }}</view>
<view class="text">{{ text }}</view>
<view class="bottom">{{ bottomInfo }}</view>
</view>

View File

@ -1,27 +0,0 @@
function getDayStyle(type, color) {
var style = [];
if (color) {
if (
type === 'start' ||
type === 'end' ||
type === 'selected'
) {
style.push(['background', color]);
} else if (type === 'middle') {
style.push(['color', color]);
// style.push(['background', color]);
// style.push(['opacity', '0.1']);
}
}
return style
.map(function(item) {
return item.join(':');
})
.join(';');
}
module.exports = {
getDayStyle: getDayStyle,
};

View File

@ -1,15 +0,0 @@
Component({
data: {
weekdays: ['日', '一', '二', '三', '四', '五', '六']
},
properties: {
title: {
type: String,
value: '日期选择'
},
subTitle: String,
showTitle: Boolean,
showSubtitle: Boolean
},
methods: {}
});

View File

@ -1,3 +0,0 @@
{
"component": true
}

View File

@ -1,26 +0,0 @@
.calendar-header-container{
.calendar-header-container_title{
text-align: center;
padding: 20rpx 0;
font-size: 36rpx;
line-height: 44rpx;
}
.calendar-header-container_subtitle{
text-align: center;
font-size: 36rpx;
line-height: 44rpx;
margin-bottom: 30rpx;
}
.calendar-header__weekdays{
display: flex;
justify-content: center;
align-items: center;
margin: 0 20rpx;
padding: 10rpx 0;
border-bottom: 1rpx solid #F3F3F3;
.calendar-header__weekday{
width: 14.285%;
text-align: center;
}
}
}

View File

@ -1,20 +0,0 @@
<view class="calendar-header-container">
<block wx:if="{{ showTitle }}">
<!-- <view class="calendar-header-container_title">
<slot name="title"></slot>
</view> -->
<view class="calendar-header-container_title">
{{ title }}
</view>
</block>
<view wx:if="{{ showSubtitle }}" class="calendar-header-container_subtitle">
{{ subTitle }}
</view>
<view class="calendar-header__weekdays">
<view wx:for="{{ weekdays }}" wx:key="index" class="calendar-header__weekday">
{{ item }}
</view>
</view>
</view>

View File

@ -1,195 +0,0 @@
import { compareDay, getMonthEndDay } from '../../util';
import * as config from '../../config';
Component({
data: {
days: []
},
properties: {
minDate: {
type: Object,
optionalTypes: [String, null],
},
maxDate: {
type: Object,
optionalTypes: [String, null],
},
formatter: {
type: null,
observer: 'setDays'
},
date: {
type: null,
observer: 'setDays'
},
currentDate: {
type: Array,
optionalTypes: [null],
observer() {
this.setDays();
}
},
type: {
type: String,
observer: 'setDays'
},
showMonthTitle: Boolean,
color: {
type: String,
value: ''
}
},
methods: {
/**
* 某一天的点击事件
*/
onClick(event) {
const { item } = event.currentTarget.dataset;
if (item.type !== 'disabled' && item.type !== 'empty') {
this.triggerEvent('clickDay', item);
}
},
debounce(fn) {
let timer;
return () => {
let that = this;
let args = arguments;
if(timer) clearTimeout(timer);
timer = setTimeout(function() {
fn.apply(that, args);
}, 300);
};
},
setDays() {
this.debounce(this.setDay)();
},
/**
* 设置某月分的天数
*/
setDay() {
let days = [];
const startDate = new Date(this.data.date);
const year = startDate.getFullYear();
const month = startDate.getMonth();
const day = new Date(year, month, 1).getDay();
const totalDay = getMonthEndDay(year, month + 1);
for (let day = 1; day <= totalDay; day++) {
const date = new Date(year, month, day).getTime();
const type = this.getDayType(date);
let config = {
date,
type,
text: day,
bottomInfo: this.getBottomInfo(type),
topInfo: ''
};
if (this.data.formatter) {
config = this.data.formatter(config);
}
days.push(config);
}
for(let i = 0; i < day; i++) {
days.unshift({
type: 'empty'
});
}
this.setData({
days
});
},
isDateInCurrent(date) {
const { currentDate } = this.data;
return currentDate.some(item => {
return compareDay(item, date) === 0;
});
},
getMultipleDayType(date) {
const { currentDate } = this.data;
if (!Array.isArray(currentDate)) {
return '';
}
if (this.isDateInCurrent(date)) {
return 'selected';
}
return '';
},
getRangeDayType(day) {
const { currentDate } = this.data;
if (!Array.isArray(currentDate)) {
return;
}
const [startDay, endDay] = currentDate;
if (!startDay) {
return;
}
const compareToStart = compareDay(day, startDay);
if (!endDay) {
return compareToStart === 0 ? 'start' : '';
}
const compareToEnd = compareDay(day, endDay);
if (compareToStart === 0) {
return 'start';
}
if (compareToEnd === 0) {
return 'end';
}
if (compareToStart > 0 && compareToEnd < 0) {
return 'middle';
}
},
// date 循环的某一天
getDayType(date) {
const { type, minDate, maxDate, currentDate } = this.data;
if (compareDay(date, minDate) < 0 || compareDay(date, maxDate) > 0) {
return 'disabled';
}
if (type === config.TYPE_SINGLE) {
return compareDay(date, currentDate) === 0 ? 'selected' : '';
}
if (type === config.TYPE_MULTIPLE) {
return this.getMultipleDayType(date);
}
if (type === config.TYPE_RANGE) {
return this.getRangeDayType(date);
}
},
getBottomInfo(type) {
if (this.data.type === config.TYPE_RANGE) {
if (type === 'start') {
return '开始';
}
if (type === 'end') {
return '结束';
}
return '';
}
return '';
}
}
});

View File

@ -1,6 +0,0 @@
{
"component": true,
"usingComponents": {
"day":"../day/index"
}
}

View File

@ -1,18 +0,0 @@
.calendar-mounth-container{
color:#333;
display: flex;
flex-direction: column;
.title{
text-align: center;
font-weight: 800;
}
.calendar-day-container{
display: flex;
flex-wrap: wrap;
.calendar-day-wrap{
width: 14.285%;
// height: 110rpx;
// padding: 10rpx 0;
}
}
}

View File

@ -1,24 +0,0 @@
<wxs src="./index.wxs" module="computed"></wxs>
<view class="calendar-mounth-container">
<view class="title" wx:if="{{ showMonthTitle }}">
{{ computed.formatMonthTitle(date) }}
</view>
<view class="calendar-day-container">
<view class="calendar-day-wrap"
wx:for="{{ days }}"
wx:key="index"
>
<day
bind:tap="onClick"
data-item="{{ item }}"
wx:if="{{ item.type !== 'empty' }}"
text="{{ item.text }}"
topInfo="{{ item.topInfo }}"
bottomInfo="{{ item.bottomInfo }}"
type="{{ item.type }}"
color=" {{ color }}"
/>
</view>
</view>
</view>

View File

@ -1,12 +0,0 @@
/* eslint-disable */
function formatMonthTitle(date) {
date = getDate(date);
return date.getFullYear() + '年' + (date.getMonth() + 1) + '月';
}
module.exports = {
formatMonthTitle: formatMonthTitle
};

View File

@ -1,3 +0,0 @@
export const TYPE_SINGLE = 'single';
export const TYPE_RANGE = 'range';
export const TYPE_MULTIPLE = 'multiple';

View File

@ -1,42 +0,0 @@
const formatFlags = {
format: function (format, date) {
date = new Date(date);
let ret;
const opt = {
'y+': date.getFullYear().toString(), // 年
'M+': (date.getMonth() + 1).toString(), // 月
'd+': date.getDate().toString(), // 日
};
for (let k in opt) {
ret = new RegExp('(' + k + ')').exec(format);
if (ret) {
format = format.replace(ret[1], (ret[1].length === 1) ? opt[k] : this.padZero(opt[k], ret[1].length));
}
}
return format;
},
/**
* PC 端微信不支持 padStart这里写一个补 0 函数
* 如果测试已兼容则可使用原生 padStart
* issue #1277
*/
padZero(str, length) {
let res = str;
for (let i = 0; i < length - str; i++) {
res = '0' + res;
}
return res;
}
};
formatFlags.format('yyyy/MM/dd', new Date());
formatFlags.format('yyyy-MM-dd', new Date());
formatFlags.format('yyyy-M-dd', new Date());
formatFlags.format('yyyy-M-d', new Date());
// formatFlags.format('yy-M-dd', new Date())
formatFlags.format('M-dd', new Date());
formatFlags.format('MM-dd', new Date());
export default formatFlags;

View File

@ -1,346 +0,0 @@
import eventBus from '../core/utils/event-bus.js';
import validator from '../behaviors/validator';
import rules from '../behaviors/rules';
import * as config from './config';
import formatFlags from './dete';
import { getDayByOffset, getDate, compareDay, calcDateNum, copyDates, getTime, formatMonthTitle, compareMonth, getMonths } from './util';
Component({
externalClasses: [
'l-class'
],
behaviors: ['wx://form-field', validator, rules],
properties: {
show: {
type: Boolean,
value: false,
observer(val) {
if (val) {
this.initRect();
this.scrollIntoView();
}
}
},
type: {
type: String,
value: config.TYPE_SINGLE,
options: [config.TYPE_SINGLE, config.TYPE_MULTIPLE, config.TYPE_RANGE],
observer() {
this.setData({ currentDate: this.initCurrentDate() });
}
},
color: {
type: String,
value: ''
},
defaultDate: {
optionalTypes: [String, Number, Date, Array],
value: '',
observer() {
this.setData({ currentDate: this.initCurrentDate() });
}
},
format: {
type: String,
value: 'timestamp'
},
formatter: {
type: Function,
optionalTypes: [null],
value: null
},
minDate: {
type: String,
optionalTypes: [null, Number],
value: Date.now()
},
maxDate: {
type: String,
optionalTypes: [null, Number],
value: new Date(
new Date().getFullYear(),
new Date().getMonth() + 6,
new Date().getDate()
).getTime()
},
minSelect: {
type: Number,
optionalTypes: [null],
value: null
},
maxSelect: {
type: Number,
optionalTypes: [null],
value: null
},
allowSameDay: Boolean,
showConfirm: {
type: Boolean,
value: true
},
confirmText: {
type: String,
value: '确认'
},
maxLimitMessage: {
type: String
},
minLimitMessage: {
type: String
},
showTitle: {
type: Boolean,
value: true
},
showSubtitle: {
type: Boolean,
value: true
},
title: {
type: String,
value: '日期选择'
}
},
lifetimes: {
attached() {
this.setData({
currentDate: this.initCurrentDate()
});
},
ready() {
if (this.data.show) {
this.initRect();
this.scrollIntoView();
}
}
},
data: {
currentDate: null,
types: config,
subTitle: '',
scrollIntoViewIndex: ''
},
methods: {
clickDay(event) {
const { type, currentDate, maxLimitMessage, maxSelect, allowSameDay } = this.data;
const { date } = event.detail;
if(type === config.TYPE_SINGLE) {
this.setData({
currentDate: getTime(date)
});
this.triggerEvent('linclickday', copyDates(date));
this.triggerEvent('linselect', copyDates(date));
}
if(type === config.TYPE_MULTIPLE) {
let _index = null;
const isSelected = currentDate.some((item, index) => {
const res = compareDay(item, date) === 0;
if(res) {
_index = index;
}
return res;
});
if(isSelected) {
// 取消选择
currentDate.splice(_index, 1);
this.setData({
currentDate: getTime(currentDate)
});
this.triggerEvent('linunselect', copyDates(currentDate));
} else {
if(maxSelect && currentDate.length >= maxSelect) {
wx.lin.showToast({
title: maxLimitMessage || `选择天数不能超过 ${ maxSelect }`
});
this.triggerEvent('linclickday', copyDates(date));
return;
}
// 添加
this.setData({
currentDate: getTime([...currentDate, date])
});
this.triggerEvent('linselect', copyDates([...currentDate, date]));
}
this.triggerEvent('linclickday', copyDates(date));
}
if(type === config.TYPE_RANGE) {
const [startDay, endDay] = currentDate;
if (startDay && !endDay) {
const compareToStart = compareDay(date, startDay);
if (compareToStart === 1) {
if(this.checkSelectRange([startDay, date])) {
this.setData({
currentDate: getTime([startDay, date])
});
this.triggerEvent('linselect', copyDates([startDay, date]));
}
}
else if (compareToStart === -1) {
// 选择结束日期在开始日期之前 重新开始选择
this.setData({
currentDate: getTime([date, null])
});
} else if(allowSameDay){
this.setData({
currentDate: getTime([date, date])
});
}
}
else {
// 重新开始选择
this.setData({
currentDate: getTime([date, null])
});
}
}
},
checkSelectRange(date) {
const { maxSelect, maxLimitMessage, minSelect, minLimitMessage } = this.data;
if (maxSelect && calcDateNum(date) > maxSelect) {
wx.lin.showToast({
title: maxLimitMessage || `选择天数不能超过 ${ maxSelect }`
});
return false;
}
if (minSelect && calcDateNum(date) < minSelect) {
wx.lin.showToast({
title: minLimitMessage || `选择天数不能少于 ${ minSelect }`
});
return false;
}
return true;
},
initCurrentDate() {
const { type, minDate, defaultDate, maxDate } = this.data;
const defaultDateIsArr = Array.isArray(defaultDate);
if (type === config.TYPE_SINGLE) {
if(!defaultDate) {
return minDate;
}
if(defaultDateIsArr) {
return minDate;
}
if(compareDay(defaultDate, minDate) === -1) {
return minDate;
}
if(compareDay(defaultDate, maxDate) === 1) {
return maxDate;
}
return defaultDate;
}
if(type === config.TYPE_MULTIPLE) {
if(!defaultDate) {
return [];
}
if(defaultDateIsArr) {
return defaultDate.filter(item => {
return compareDay(item, minDate) === 1 && compareDay(item, maxDate) === -1;
});
}
if(compareDay(defaultDate, minDate) === -1) {
return [minDate];
}
if(compareDay(defaultDate, maxDate) === 1) {
return [maxDate];
}
return [minDate];
}
if(type === config.TYPE_RANGE) {
if(defaultDateIsArr) {
let [startDay = minDate, endDay] = defaultDate;
if(compareDay(startDay, minDate) === -1 || compareDay(startDay, maxDate) !== -1) {
startDay = minDate;
}
if(!endDay) {
endDay = getDayByOffset(getDate(startDay), 1).getTime();
}
if(compareDay(endDay, maxDate) === 1 || compareDay(endDay, minDate) === -1) {
endDay = getDayByOffset(getDate(startDay), 1).getTime();
}
return [
startDay,
endDay
];
}
return [
minDate,
getDayByOffset(getDate(minDate), 1).getTime()
];
}
},
initRect() {
if (!this.contentObserver !== null && this.contentObserver !== undefined) {
this.contentObserver.disconnect();
}
const contentObserver = this.createIntersectionObserver({
thresholds: [0, 0.1, 0.9, 1],
observeAll: true
});
this.contentObserver = contentObserver;
contentObserver.relativeTo('.calendar-body-wrap');
contentObserver.observe('.month', res => {
if (res.boundingClientRect.top <= res.relativeRect.top) {
// @ts-ignore
this.setData({ subTitle: formatMonthTitle(res.dataset.date) });
}
});
},
scrollIntoView() {
setTimeout(() => {
const { currentDate, type, show, minDate, maxDate } = this.data;
const targetDate = type === 'single' ? currentDate : currentDate[0];
const displayed = show;
if (!targetDate || !displayed) {
return;
}
const months = getMonths(minDate, maxDate);
months.some((month, index) => {
if (compareMonth(month, targetDate) === 0) {
this.setData({ scrollIntoViewIndex: `month${index}` });
return true;
}
return false;
});
}, 100);
},
closePicker() {
this.setData({
show: false
});
},
onClickConfirm() {
const {format, type, currentDate} = this.data;
eventBus.emit(`lin-form-blur-${this.id}`, this.id);
let value = null;
if(type === 'single') {
value = format !== 'timestamp' ? formatFlags.format('yyyy-MM-dd', currentDate) : currentDate;
} else {
value = currentDate.map(item => {
return format !== 'timestamp' ? formatFlags.format('yyyy-MM-dd', item) : item;
});
}
this.triggerEvent('linconfirm', value);
},
getValues() {
return this.data.currentDate;
},
reset() {
this.setData({
currentDate: null
});
}
}
});

View File

@ -1,10 +0,0 @@
{
"component": true,
"usingComponents": {
"header":"./components/header/index",
"mounth":"./components/mounth/index",
"l-toast": "../toast/index",
"l-popup": "../popup/index",
"l-button": "../button/index"
}
}

View File

@ -1,34 +0,0 @@
@import "../styles/_theme.less";
@import "../styles/_mixins.less";
.calendar-container{
display: flex;
height: 1000rpx;
flex-direction: column;
background-color: #ffffff;
.calendar-body-wrap{
flex: 1;
overflow: auto;
padding: 0 20rpx;
width: auto;
}
}
// .bottom {
// width: 100%;
// background: #fff;
// height: 300rpx;
// overflow: hidden;
// text-align: center;
// line-height: 300rpx;
// font-size: 28rpx;
// color: #555;
// border-top-left-radius: 12rpx;
// border-top-right-radius: 12rpx;
// }
.bottom-button {
padding: 0 !important;
.safe-area-inset-bottom();
box-sizing: content-box !important;
}

View File

@ -1,10 +0,0 @@
<import src="./calendar.wxml" />
<l-popup content-align="bottom" show="{{ show }}" bind:lintap="closePicker">
<template
is="calendar"
data="{{ currentDate, type, color, defaultDate, format, formatter, minDate, maxDate, minSelect, maxSelect, showConfirm, confirmText, maxLimitMessage, minLimitMessage, showTitle, showSubtitle, title, subTitle, scrollIntoViewIndex, color }}"
/>
</l-popup>
<l-toast></l-toast>

View File

@ -1,37 +0,0 @@
/* eslint-disable */
var utils = require('./utils.wxs');
function getMonths(minDate, maxDate) {
var months = [];
var cursor = getDate(minDate);
cursor.setDate(1);
do {
months.push(cursor.getTime());
cursor.setMonth(cursor.getMonth() + 1);
} while (utils.compareMonth(cursor, getDate(maxDate)) !== 1);
return months;
}
function getButtonDisabled(type, currentDate) {
if (currentDate == null) {
return true;
}
if (type === 'range') {
return !currentDate[0] || !currentDate[1];
}
if (type === 'multiple') {
return !currentDate.length;
}
return !currentDate;
}
module.exports = {
getMonths: getMonths,
getButtonDisabled: getButtonDisabled
};

View File

@ -1,113 +0,0 @@
export function getMonthEndDay(year, month) {
return new Date(year, month, 0).getDate();
}
export function isTimeTemp(data) {
var reg = /^\d+(\.\d+)?$/;
return reg.test(data);
}
export function getDate(str) {
if (isTimeTemp(str)) {
str = parseInt(str);
}
str = new Date(str);
return str;
}
export function getDayByOffset(date, number) {
date = new Date(date);
date.setDate(date.getDate() + number);
return date;
}
export function compareMonth(date1, date2) {
if (!(date1 instanceof Date)) {
date1 = getDate(date1);
}
if (!(date2 instanceof Date)) {
date2 = getDate(date2);
}
const year1 = date1.getFullYear();
const year2 = date2.getFullYear();
const month1 = date1.getMonth();
const month2 = date2.getMonth();
if (year1 === year2) {
return month1 === month2 ? 0 : month1 > month2 ? 1 : -1;
}
return year1 > year2 ? 1 : -1;
}
export function compareDay(date1, date2) {
if (!(date1 instanceof Date)) {
date1 = getDate(date1);
}
if (!(date2 instanceof Date)) {
date2 = getDate(date2);
}
const compareMonthResult = compareMonth(date1, date2);
if (compareMonthResult === 0) {
const _date1 = date1.getDate();
const _date2 = date2.getDate();
return _date1 === _date2 ? 0 : _date1 > _date2 ? 1 : -1;
}
return compareMonthResult;
}
export function calcDateNum(date) {
const day1 = new Date(date[0]).getTime();
const day2 = new Date(date[1]).getTime();
return (day2 - day1) / (1000 * 60 * 60 * 24) + 1;
}
export function copyDates(dates) {
if (Array.isArray(dates)) {
return dates.map(date => {
if (date === null) {
return date;
}
return new Date(date);
});
}
return new Date(dates);
}
export function getTime (dates) {
if (Array.isArray(dates)) {
return dates.map(date => {
if (date instanceof Date) {
return date.getTime();
}
return date;
});
}
return (dates instanceof Date ? dates.getTime() : dates);
}
export function formatMonthTitle(date) {
if (!(date instanceof Date)) {
date = new Date(date);
}
return `${date.getFullYear()}${date.getMonth() + 1}`;
}
export function getMonths(minDate, maxDate) {
const months = [];
const cursor = new Date(minDate);
cursor.setDate(1);
do {
months.push(cursor.getTime());
cursor.setMonth(cursor.getMonth() + 1);
} while (compareMonth(cursor, maxDate) !== 1);
return months;
}

View File

@ -1,24 +0,0 @@
/* eslint-disable */
function getMonthEndDay(year, month) {
return getDate(year, month - 1, 0).getDate();
}
function compareMonth(date1, date2) {
date1 = getDate(date1);
date2 = getDate(date2);
var year1 = date1.getFullYear();
var year2 = date2.getFullYear();
var month1 = date1.getMonth();
var month2 = date2.getMonth();
if (year1 === year2) {
return month1 === month2 ? 0 : month1 > month2 ? 1 : -1;
}
return year1 > year2 ? 1 : -1;
}
module.exports = {
getMonthEndDay: getMonthEndDay,
compareMonth: compareMonth
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 550 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 552 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 591 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 600 B

View File

@ -1,179 +0,0 @@
import deviceUtil from '../utils/device-util';
import validator from '../behaviors/validator';
import eventUtil from '../core/utils/event-util';
Component({
options: {
multipleSlots: true
},
behaviors: [validator],
externalClasses: ['l-title-class'],
properties: {
// 胶囊栏颜色
bgColor: {
type: String,
value: 'white'
},
// 状态栏颜色
statusBarColor: {
type: String,
value: 'transparent'
},
// 标题栏颜色
titleBarColor: {
type: String,
value: 'transparent'
},
// 标题颜色
titleColor: {
type: String,
value: 'black'
},
// 胶囊按钮颜色
capsuleColor: {
type: String,
value: 'black',
options: ['white', 'black']
},
// 禁用左侧按钮返回上一页
disableBack: {
type: Boolean,
value: false
},
// 禁用右侧按钮返回主页
disableHome: {
type: Boolean,
value: false
},
// 隐藏胶囊按钮
hiddenCapsule: {
type: Boolean,
value: false
},
// 主页路径
homePage: {
type: String,
value: ''
},
// 页面标题
title: {
type: String,
value: ''
},
// 顶部填充
hasPadding: {
type: Boolean,
value: true
},
// 隐藏标题
hiddenTitle: {
type: Boolean,
value: false
},
// 左侧胶囊按钮左侧图标路径
capsuleLeftIconPath: {
type: String,
value: null
},
// 左侧胶囊按钮左侧图标宽度单位rpx
capsuleLeftIconWidth: {
type: Number,
value: null
},
// 左侧胶囊按钮左侧图标高度单位rpx
capsuleLeftIconHeight: {
type: Number,
value: null
},
// 左侧胶囊按钮右侧图标路径
capsuleRightIconPath: {
type: String,
value: null
},
// 左侧胶囊按钮右侧图标宽度单位rpx
capsuleRightIconWidth: {
type: Number,
value: null
},
// 左侧胶囊按钮右侧图标高度单位rpx
capsuleRightIconHeight: {
type: Number,
value: null
}
},
data: {
// 标题栏高度单位px
titleBarHeight: deviceUtil.getTitleBarHeight(),
// 状态栏高度单位px
statusBarHeight: deviceUtil.getStatusBarHeight(),
// 左侧胶囊按钮信息
capsuleButtonInfo: null
},
lifetimes: {
ready: function () {
this.setData({
capsuleButtonInfo: this.getCapsuleButtonInfo()
});
}
},
methods: {
/**
* 获取左侧胶囊按钮信息
*/
getCapsuleButtonInfo() {
const screenWidth = wx.getSystemInfoSync().screenWidth;
const capsuleButtonInfo = wx.getMenuButtonBoundingClientRect();
capsuleButtonInfo.left = screenWidth - capsuleButtonInfo.right;
capsuleButtonInfo.right = capsuleButtonInfo.left + capsuleButtonInfo.width;
return capsuleButtonInfo;
},
/**
* 监听点击左侧按钮
*/
onTapLeftButton() {
eventUtil.emit(this, 'linlefttap');
if (!this.data.disableBack) {
wx.navigateBack();
}
},
/**
* 监听长按左侧按钮
*/
onLongPressLeftButton() {
eventUtil.emit(this, 'linleftlongpress');
},
/**
* 监听点击右侧按钮
*/
async onTapRightButton() {
eventUtil.emit(this, 'linrighttap');
const homePage = this.data.homePage;
if (!this.data.disableHome) {
wx.switchTab({
url: homePage,
fail() {
wx.navigateTo({
url: homePage
});
}
});
}
},
/**
* 监听长按右侧按钮
*/
onLongPressRightButton() {
eventUtil.emit(this, 'linrightlongpress');
}
}
});

View File

@ -1,3 +0,0 @@
{
"component": true
}

View File

@ -1,76 +0,0 @@
.container{
position: relative;
.capsule-bar{
width: 100%;
position: fixed;
display: flex;
flex-direction: column;
top: 0;
left: 0;
z-index: 999;
.status-bar{
width: 100%;
}
.title-bar{
width: 100%;
display: flex;
align-items: center;
justify-content: center;
margin-top: -4rpx;
padding-top: 4rpx;
box-sizing: border-box;
.title{
font-size: 36rpx;
font-weight: bold;
}
}
.capsule-button{
border-radius: 99999px;
display: flex;
align-items: center;
border: 1px solid rgba(0,0,0,0.1);
position: fixed;
.icon-wrapper-hover-black{
background-color: rgba(0,0,0,0.36);
}
.icon-wrapper-hover-white{
background-color: rgba(255,255,255,0.339);
}
.icon-wrapper{
display: flex;
justify-content: center;
align-items: center;
.icon-left{
display: block;
width: 20rpx;
height: 34rpx;
}
.icon-right{
display: block;
width: 38rpx;
height: 34rpx;
}
}
.line{
height: 18px;
width: 1px;
line-height: 1;
background-color: rgba(255,255,255,0.25);
}
}
}
.content-container{
width: 100%;
position: absolute;
left: 0;
}
}

View File

@ -1,60 +0,0 @@
<!--为什么没有设置一个cover-image用来承载背景图因为CapsuleBar在不同机型上大小是动态变化的-->
<!--cover-image又不能设置填充方式所以将此部分开放给用户处理是最佳的选择-->
<view class="container" style="padding-top: {{hasPadding?titleBarHeight+statusBarHeight:'0'}}rpx">
<!--胶囊栏-->
<cover-view class="capsule-bar" style="background-color: {{bgColor}};">
<!--状态栏-->
<!--这里加4是因为不加4的时候statusBar和titleBar之间容易出现一条白线所以加上4让两部分重叠消除白线-->
<cover-view
class="status-bar"
style="height: {{statusBarHeight+4}}rpx;background-color: {{statusBarColor}};"
></cover-view>
<!--标题栏-->
<cover-view
class="title-bar"
style="height: {{titleBarHeight}}rpx;background-color: {{titleBarColor}};"
>
<cover-view wx:if="{{!hiddenTitle}}" class="title l-title-class" style="color: {{titleColor}};">{{title}}</cover-view>
<slot name="title"/>
</cover-view>
<!--胶囊按钮-->
<cover-view
wx:if="{{!hiddenCapsule}}"
class="capsule-button"
style="border-color: rgba({{capsuleColor==='black'?'0,0,0,0.1':'255,255,255,0.25'}});background-color: rgba({{capsuleColor==='black'?'255,255,255,0.6':'0,0,0,0.15'}});width: {{capsuleButtonInfo.width}}px;height: {{capsuleButtonInfo.height}}px;left: {{capsuleButtonInfo.left}}px;top: {{capsuleButtonInfo.top}}px;"
>
<!--左侧按钮-->
<cover-view mut-bind:tap="onTapLeftButton"
catch:longpress="onLongPressLeftButton"
hover-class="icon-wrapper-hover-{{capsuleColor}}"
class="icon-wrapper"
style="width: {{capsuleButtonInfo.width/2}}px;height: {{capsuleButtonInfo.height}}px;">
<cover-image
class="icon-left"
style="width:{{capsuleLeftIconWidth?capsuleLeftIconWidth+'rpx':''}};height:{{capsuleLeftIconHeight?capsuleLeftIconHeight+'rpx':''}};"
src="{{capsuleLeftIconPath?capsuleLeftIconPath:'icons/capsule-left-'+capsuleColor+'.png'}}"></cover-image>
</cover-view>
<!--分割线-->
<cover-view class="line"></cover-view>
<!--右侧按钮-->
<cover-view mut-bind:tap="onTapRightButton"
catch:longpress="onLongPressRightButton"
hover-class="icon-wrapper-hover-{{capsuleColor}}"
class="icon-wrapper"
style="width: {{capsuleButtonInfo.width/2}}px;height: {{capsuleButtonInfo.height}}px;">
<cover-image
class="icon-right"
style="width:{{capsuleRightIconWidth?capsuleRightIconWidth+'rpx':''}};height:{{capsuleRightIconHeight?capsuleRightIconHeight+'rpx':''}}"
src="{{capsuleRightIconPath?capsuleRightIconPath:'icons/capsule-right-'+capsuleColor+'.png'}}"></cover-image>
</cover-view>
</cover-view>
</cover-view>
<view class="content-container">
<slot></slot>
</view>
</view>

View File

@ -1,47 +0,0 @@
import validator from '../behaviors/validator';
Component({
/**
* 组件的属性列表
*/
externalClasses: ['l-class', 'l-img-class', 'l-title-class'],
options: {
multipleSlots: true // 在组件定义时的选项中启用多slot支持
},
behaviors: [validator],
properties: {
image: String,
title: String,
describe: String,
plaintext: Boolean,
full: Boolean,
position: {
type: String,
value: 'left',
options: ['left', 'right']
},
type: {
type: String,
value: 'primary',
options: ['primary', 'avatar','cover']
},
imageMode: {
type: String,
value: 'scaleToFill'
}
},
/**
* 组件的初始数据
*/
data: {
},
/**
* 组件的方法列表
*/
methods: {
}
});

View File

@ -1,4 +0,0 @@
{
"component": true,
"usingComponents": {}
}

View File

@ -1,132 +0,0 @@
.card-container {
margin: 0 auto;
padding: 30rpx;
box-sizing: border-box;
background: #fff;
display: flex;
&-full{
width: 100%;
}
&-unfull{
width: 92%;
box-shadow: 0 4rpx 20rpx 0 rgba(212, 217, 223, 0.5);
border-radius: 4px;
}
&-primary-left {
flex-direction: row;
}
&-primary-right {
flex-direction: row-reverse;
}
&-avatar {
flex-direction: column;
}
&-cover {
flex-direction: column;
}
}
.cover-img{
&-full{
width: 100%;
height: 260rpx;
}
&-unfull{
width: 100%;
height: 260rpx;
}
}
.card-img {
&-primary{
height: 240rpx;
width: 240rpx;
overflow: hidden;
&-left{
margin-right: 40rpx;
}
&-right{
margin-left: 40rpx;
}
}
&-avatar{
height: 60rpx;
width: 60rpx;
border-radius: 50%;
margin-right: 30rpx;
}
}
.card-img-avatar {
height: 60rpx;
width: 60rpx;
border-radius: 50%;
margin-right: 30rpx;
}
.card-content {
position: relative;
display: flex;
flex-direction: column;
flex: 1;
}
.card-title {
overflow: hidden;
text-overflow: ellipsis;
color: #333;
&-primary{
font-size: 32rpx;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
&-avatar{
font-size: 28rpx;
}
&-cover{
font-size: 30rpx;
margin-top: 10rpx;
}
}
.card-title-avatar {
font-size: 28rpx;
}
.card-avatar-top {
display: flex;
flex-direction: row;
height: 100rpx;
align-items: center;
justify-content: space-between;
}
.card-avatar-left {
display: flex;
flex-direction: row;
align-items: center;
}
.card-avatar{
display: flex;
flex-direction: column;
}
.describe {
color: #666;
font-size: 24rpx;
}

View File

@ -1,22 +0,0 @@
<view class="l-class card-container {{'card-container-' + type}} {{'card-container-' + type + '-' + position}} {{full?'card-container-full':'card-container-unfull'}}">
<block wx:if="{{type ==='primary' || type ==='cover'}}">
<image wx:if="{{!plaintext}}" class="l-img-class {{full?'cover-img-full':'cover-img-unfull'}} {{ 'card-img-' + type }} {{ 'card-img-' + type + '-' + position }}" mode="{{imageMode}}" lazy-load src="{{image}}"></image>
<view class="card-content">
<text class="l-title-class card-title {{'card-title-' + type}}">{{title}}</text>
<slot />
</view>
</block>
<block wx:if="{{type ==='avatar'}}">
<view class="card-avatar-top">
<view class="card-avatar-left">
<image mode="aspectFill" class="l-img-class {{ 'card-img-' + type }}" src="{{image}}" mode="{{imageMode}}" lazy-load></image>
<view class="card-avatar">
<text class="l-title-class card-title {{'card-title-' + type}}">{{title}}</text>
<text class="describe">{{describe}}</text>
</view>
</view>
<slot name="more" />
</view>
<slot />
</block>
</view>

View File

@ -1,120 +0,0 @@
import eventBus from '../core/utils/event-bus';
import rules from '../behaviors/rules';
Component({
behaviors: ['wx://form-field',rules],
externalClasses: ['l-class', 'l-error-text', 'l-error-text-class'],
relations: {
'../checkbox/index': {
type: 'child',
linked(target) {
this.init(target);
},
linkChanged() {
},
unlinked() {
// this.init(target);
}
}
},
properties: {
// 选项的排列方式 一行显示 or 多行显示
placement: {
type: String,
value: 'column', //column row
},
// 最多选中值
maxSelected: {
type: Number,
value: null
},
minSelected: {
type: Number,
value: null
},
},
data: {
},
attached() {
let { minSelected, maxSelected} = this.properties;
this.checkMax(minSelected, maxSelected);
},
methods: {
init(target) {
if(this._keys === undefined) this._keys = {};
if(this._selected === undefined) this._selected = {};
this.checkDefaultItem(target);
this.checkedKeyRepeat(target);
},
checkedKeyRepeat(target) {
let { key } = target.properties;
if(this._keys[key]) {
throw new Error(`keys有重复元素, checkbox的key属性不能重复${key}`);
} else {
this._keys[key] = true;
}
},
checkDefaultItem(target) {
const { key, checked, cell } = target.properties;
if(checked) {
this._selected[key] = {...cell,checked:true, value: key};
}
},
checkMax(min, max) {
if(min !== null && min < 0) {
throw new Error('最小选择个数必须大于等于0');
}
if(max !== null && max < 0) {
throw new Error('最多选择个数必须大于0');
}
if(max !== null && min !== null && min >= max) {
throw new Error('最多选择个数必须大于最小选择个数');
}
},
onEmitEventHandle(currentItem) {
currentItem.checked ? this.addSelect (currentItem):this.removeSelect(currentItem.key);
this.validatorData({
[this.data.name]: Object.values(this._selected)
});
this.triggerEvent('linchange', currentItem, {
bubbles: true,
composed: true
});
eventBus.emit(`lin-form-change-${this.id}`,this.id);
},
onEmitOverflowHandle(data){
this.triggerEvent('linout', data, {
bubbles: true,
composed: true
});
},
removeSelect(key) {
delete this._selected[key];
},
addSelect(currentItem) {
let {key, ...obj} = currentItem;
this._selected[key] = {...obj, value: key};
},
getValues() {
return Object.values(this._selected);
},
reset() {
this._selected = {};
const list = this.getRelationNodes('../checkbox/index');
return list.forEach(item => {
return item.setData({
checked: false
});
});
}
}
});

View File

@ -1,7 +0,0 @@
{
"component": true,
"usingComponents": {
"l-error-tip":"../error-tip/index",
"l-checkbox": "../checkbox/index"
}
}

View File

@ -1,17 +0,0 @@
.checkbox-group{
flex-wrap: wrap;
&-row{
display: flex;
flex-direction: row;
}
&-column{
display: flex;
flex-direction: column;
}
}
// .checkbox-group-button{
// display: flex;
// flex-direction: row !important;
// flex-wrap: wrap;
// }

View File

@ -1,4 +0,0 @@
<view class="l-class checkbox-group checkbox-group-{{placement}} ">
<slot></slot>
</view>
<l-error-tip l-error-text-class="l-error-text l-error-text-class" errorText="{{errorText}}" wx:if="{{errorText}}"/>

View File

@ -1,114 +0,0 @@
Component({
behaviors: ['wx://form-field'],
externalClasses: ['l-class', 'l-disabled-class', 'l-icon-class'],
relations: {
'../checkbox-group/index': {
type: 'parent'
}
},
options: {
multipleSlots: true
},
properties: {
// checkbox 按钮的位置
placement: {
type: String,
value: 'left'
},
// 是否自定义图标内容
custom: {
type: Boolean,
value: false
},
key: {
type: String,
value: ''
},
cell: {
type: Object,
value: {}
},
// checkbox的大小
size: {
type: String,
value: '38rpx'
},
// 不可选状态
disabled: {
type: Boolean,
value: false
},
// 选中后的颜色
selectColor: {
type: String,
value: '#3963BC'
},
disabledColor: {
type: String,
value: '#ccc'
},
color: {
type: String,
value: '#ccc'
},
checked: {
type: Boolean,
value: false
}
},
data: {
parentPlacement: ''
},
ready() {
const parent = this.getRelationNodes('../checkbox-group/index')[0];
let {placement: parentPlacement} = parent.properties;
this.setData({parentPlacement});
},
methods: {
// 点击checkbox
onCheckboxChangeTap() {
if (this.properties.disabled || this.data.parentDisabled) {
return;
}
const parent = this.getRelationNodes('../checkbox-group/index')[0];
if (this.properties.checked) {
if (this.isOverflow('minSelected')) return;
} else {
if (this.isOverflow('maxSelected')) return;
}
const item = {
checked: !this.properties.checked,
key: this.properties.key,
cell: this.properties.cell
};
if (parent) {
parent.onEmitEventHandle(item);
}
},
/**
*
* @param {*} type (max/min)
*/
isOverflow(type) {
const parent = this.getRelationNodes('../checkbox-group/index')[0];
const limit = parent.properties[type];
if (!limit) return false;
const selectedLength = Object.values(parent._selected).length;
let isOverflow = type === 'minSelected' ? selectedLength <= limit : selectedLength >= limit;
if (isOverflow) {
let backType = type === 'minSelected' ? 'min_selected' : 'max_selected';
parent.onEmitOverflowHandle && parent.onEmitOverflowHandle({
key: this.properties.key,
limitNumber: limit,
type: `overflow_${backType}`
});
}
return isOverflow;
}
}
});

View File

@ -1,6 +0,0 @@
{
"component": true,
"usingComponents": {
"l-button": "../button/index"
}
}

View File

@ -1,58 +0,0 @@
@import "../styles/_theme.less";
.label{
display : flex;
flex : 1;
align-items : center;
font-size : 30rpx;
color : #333333;
width : 100%;
box-sizing : border-box;
&-left{
flex-direction : row;
}
&-right{
flex-direction : row-reverse;
justify-content : space-between;
}
&-disabled{
color : #CCCCCC;
}
&-placement-row{
padding-right : 30rpx;
}
}
.checkbox-left{
margin-right : 20rpx;
}
.checkbox-right{
margin-left : 20rpx;
}
.iconfont{
font-family : "iconfont" !important;
display : inline-flex;
font-style : normal;
-webkit-font-smoothing : antialiased;
-moz-osx-font-smoothing : grayscale;
}
@font-face{
font-family : "iconfont";
src : url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAMMAAsAAAAABxgAAAK9AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDBgqBeIFdATYCJAMMCwgABCAFhG0HQBstBlGUzMkA2c8E020e0uBCKA1ReoTOr2jhX60Fez8evvb7nbu7X40GSTTS8S6aRBOpkCB1plMyIWkJb/+nLTemUXn+tjy1proDbGd+u9OXhuW20ygDQoJwOPhjfw50kxP0dlsW4tKSEtLyKhWqIpT/3MKy5KTZgMvpr8TnWZbTWts2jgmYYEBjDHuKrEQCzjUF2R2BWvJ9Am0LeioHm9MVtBXOskC8RIED7VJMUaRiU6i37C3iHV4zvaZPKG/x5+OfLdoktcxZe/S89mH27bv8VD0phAT5ch5Ih8jYBApx3eq7Uktzm2rahqZu1oO6IqSlklVFLDMN9YP+8RJR55R2wSrNJ775IoLvWEgggzoKDoFYipp4U38JhsVnsZqMDSLDTR9O5v6lxM+emWKnJ0j1WkJfv81PpvtdvqfbrTPuXw1+/Yswbx81bvFu4GNdLq7/WnYQrkR7OT7DTrwSHIOw0QhHGI+BEQb/TCiV/n/7MQFAQ9mO3iwSi9Gz9MCEpIu0tWgZiFkilLN8tRFgA1SnfMgz8o0Kgo9Q+Gcx3f/tTgFfe45JtDoVFO7QvAt/8FflYE8xlY49F13my+xAtjTRk6ASOahCOaGxn+mGGVxKaJrlSBrmkTUtkoWziZqOLdQ1baNtw/Zwx4SoidLCuneCMPSBpO8T2dAXWTjfqJnzi7ph1NB2EdwzO5Yj6oaEHCUf3UeMPM6N59RuUn6m4DZ1pKiMuTckZZTE8WBULW4pJ1liQ3kXTFQNGuEMN+QxSlPGQjgmTwehajEdDk3biwYeZ9C1TxCHIj7keoQiHpYz4XDVrb3/jARupRzS09AQv0FEKRodjQ2MAHKry6GGR2FTuhOYUMpAhmAZtCEekro5hor2WTHiUQPhhExhasgGGVQ32N6Q/UCp1ILzXI4UOYrOQ0he4vKDxXk7twIAAAAA') format('woff2'),
}
.icon-unselect:before{
content : "\e727";
}
.icon-select:before{
content : "\e725";
}

View File

@ -1,8 +0,0 @@
<view mut-bind:lintap="onCheckboxChangeTap" mut-bind:tap="onCheckboxChangeTap"
class="label label-{{placement}} label-placement-{{parentPlacement}} {{disabled ? 'label-disabled l-disabled-class' : 'l-class'}}">
<view class="checkbox-{{placement}} l-icon-class" style="color:{{checked ? selectColor : (disabled ? disabledColor : color)}};font-size: {{size}}">
<slot wx:if="{{custom}}" name="icon"/>
<view wx:else class="iconfont {{checked? 'icon-select': 'icon-unselect'}}"></view>
</view>
<slot />
</view>

View File

@ -1,133 +0,0 @@
// miniprogram_npm/lin-ui/circle/index.js
Component({
/**
* 组件的属性列表
*/
externalClasses: ['l-value-class'],
properties: {
percent: {
type: Number,
value: 0
},
outerDiameter: {
type: Number,
value: 220
},
innerDiameter: {
type: Number,
value: 170
},
activeColor: {
type: String
},
backgroundColor: {
type: String,
value: '#EBEBEB',
},
innerColor: {
type: String,
value: '#FFFFFF',
},
active: {
type: Boolean,
value: false
},
duration: {
type: Number,
value: 30
},
showValue: {
type: Boolean,
value: false
},
valueColor: {
type: String,
},
valueSize: {
type: Number,
value: 25
}
},
options: {
multipleSlots: true,
pureDataPattern: /^_/ // 指定所有 _ 开头的数据字段为纯数据字段
},
/**
* 组件的初始数据
*/
data: {
displayPercent: 0,
},
observers: {
'percent': async function (percent) {
if (percent > 100) {
this.setData({
percent: 100
});
return;
}
if (percent < 0) {
this.setData({
percent: 0
});
return;
}
if (this.data.active) {
let displayPercent = this.data.displayPercent;
if (displayPercent < percent) {
while (displayPercent < percent) {
await this.sleep(this.data.duration);
displayPercent += 1;
this.setData({
displayPercent: displayPercent
});
}
} else if (displayPercent > percent) {
while (displayPercent > percent) {
await this.sleep(this.data.duration);
displayPercent -= 1;
this.setData({
displayPercent
});
}
}
} else {
this.setData({
displayPercent: percent
});
}
},
'outerDiameter': function (outerDiameter) {
if (outerDiameter < this.data.innerDiameter) {
outerDiameter = this.data.innerDiameter;
this.setData({
outerDiameter
});
}
},
'innerDiameter': function (innerDiameter) {
if (innerDiameter < 0) {
this.setData({
innerDiameter: 0
});
}
}
},
/**
* 组件的方法列表
*/
methods: {
sleep(milSec) {
return new Promise(resolve => {
setTimeout(resolve, milSec);
});
}
}
});

View File

@ -1,4 +0,0 @@
{
"component": true,
"usingComponents": {}
}

View File

@ -1,45 +0,0 @@
/* miniprogram_npm/lin-ui/circle/index.wxss */
@import "../styles/_base.less";
.sector {
position: relative;
border-radius: 50%;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
}
.sx1,
.sx2 {
position: absolute;
top: 0;
left: 0;
}
.sx1 {
z-index: 1;
}
.sx2 {
z-index: 2;
}
.sx_t {
border-radius: 50%;
z-index: 3;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
.sector1 {
background: @progress-active-color;
}
.sector2 .sx1,
.sector2 .sx2 {
background: @progress-active-color;
transform: rotate(180deg);
}

View File

@ -1,10 +0,0 @@
<view class="sector {{((displayPercent < 50 && displayPercent !== 0) || displayPercent === 100) ? 'sector1' : 'sector2'}}" style="height:{{outerDiameter}}rpx;width:{{outerDiameter}}rpx;{{((displayPercent < 50 && displayPercent !== 0) || displayPercent === 100) ?activeColor?'background:'+activeColor:'':'background:'+backgroundColor}}">
<view wx:if="{{displayPercent !== 0 && displayPercent !== 100}}" class="sx1" style="height:{{outerDiameter}}rpx;width:{{outerDiameter}}rpx;clip: rect(0rpx, {{outerDiameter/2}}rpx, {{outerDiameter}}rpx, 0rpx);background:{{((displayPercent < 50 && displayPercent !== 0) || displayPercent === 100) ?backgroundColor:activeColor?activeColor:''}}"></view>
<view wx:if="{{displayPercent !== 50 && displayPercent !== 0 && displayPercent !== 100}}" class="sx2" style="transform: rotate({{displayPercent < 50 ? ((360 * displayPercent / 100) - 180):(360 * (displayPercent - 100) / 100)}}deg);height:{{outerDiameter}}rpx;width:{{outerDiameter}}rpx;clip: rect(0rpx, {{outerDiameter/2}}rpx, {{outerDiameter}}rpx, 0rpx);background:{{((displayPercent < 50 && displayPercent !== 0) || displayPercent === 100) ?backgroundColor:activeColor}}"></view>
<view class="sx_t" style="width:{{innerDiameter}}rpx;height:{{innerDiameter}}rpx;background:{{innerColor}}">
<view wx:if="{{showValue}}" class="l-value-class" style="color:{{valueColor?valueColor:''}};font-size:{{valueSize}}rpx">
{{displayPercent}}%
</view>
<slot></slot>
</view>
</view>

View File

@ -1,137 +0,0 @@
import nodeUtil from '../core/utils/node-util';
Component({
externalClasses: ['l-class', 'l-title-class', 'l-body-class'],
relations: {
'../collapse/index': {
type: 'parent'
}
},
options: {
multipleSlots: true,
pureDataPattern: /^_/
},
properties: {
/**
* 折叠面板子项自定义id
*/
itemId: {
type: String,
value: 'default'
},
/**
* 标题文字
*/
title: {
type: String,
value: '默认标题'
},
/**
* 是否开启自定义标题
*/
customTitle: {
type: Boolean,
value: false
},
/**
* 是否禁用内容区展开
*/
disable: {
type: Boolean,
value: false
},
/**
* 内容区域展开动画速度
*/
animationTime: {
type: String,
value: '0.3'
}
},
data: {
/**
* 内容区高度
*/
bodyHeight: '0',
/**
* 内容区是否展开
*/
isExpandContent: false,
/**
* 默认id
*/
_idDefault: -1,
},
methods: {
/**
* 点击标题
*/
async onTapTitle() {
if (this.data.disable) {
return;
}
let parents = this.getRelationNodes('../collapse/index');
await parents[0].onTapCollapseItem(this);
},
/**
* 折叠内容区
*/
async foldContent() {
// 获取 container-body-wrapper 的 css 属性信息
const containerBodyWrapperRect =
await nodeUtil.getNodeRectFromComponent(this, '.container-body-wrapper');
// 这里很重要先把高度改为固定高度transition 才会生效
if (this.data.isExpandContent) {
this.setData({
bodyHeight: containerBodyWrapperRect.height + 'px'
});
setTimeout(() => {
this.setData({
isExpandContent: false,
bodyHeight: '0px'
});
}, 20);
} else {
this.setData({
isExpandContent: false,
bodyHeight: '0px'
});
}
},
/**
* 展开内容区
*/
async expandContent() {
// 获取 container-body-wrapper 的 css 属性信息
const containerBodyWrapperRect =
await nodeUtil.getNodeRectFromComponent(this, '.container-body-wrapper');
this.setData({
isExpandContent: true,
bodyHeight: containerBodyWrapperRect.height + 'px'
});
},
/**
* 过渡效果结束后把高度改为 auto
* 不然内容改变时由于高度固定内容会显示不全
*/
onTransitionend() {
if (this.data.isExpandContent) {
this.setData({
bodyHeight: 'auto'
});
}
}
}
});

View File

@ -1,7 +0,0 @@
{
"component": true,
"usingComponents": {
"l-list": "../list/index",
"l-icon": "../icon/index"
}
}

View File

@ -1 +0,0 @@
.container{display:flex;flex-direction:column;width:100%;box-sizing:border-box}.container-title{display:flex;justify-content:space-between;padding:10rpx;align-items:center;font-size:32rpx;color:#333}.container-title-l-icon{transition:.3s}.container-body{width:100%;color:#888;box-sizing:border-box;font-size:28rpx;transition:height .3s ease-in-out;overflow:hidden}.container-body-wrapper{position:relative;padding:10rpx}

View File

@ -1,13 +0,0 @@
<view class="container l-class">
<view mut-bind:tap="onTapTitle" class="container-title l-title-class">
<view style="{{disable?'color:#DEE2E6':''}}" wx:if="{{!customTitle}}">{{title}}</view>
<l-icon class="container-title-icon" wx:if="{{!customTitle}}" style="{{isExpandContent?'transform:rotate(-180deg);':''}}" name="down" size="28"
color="{{disable?'#DEE2E6':'#333'}}"></l-icon>
<slot name="title"></slot>
</view>
<view catch:transitionend="onTransitionend" class="container-body" style="height:{{bodyHeight}};transition-duration:{{animationTime}}s">
<view class="container-body-wrapper l-body-class">
<slot></slot>
</view>
</view>
</view>

View File

@ -1,133 +0,0 @@
Component({
options: {
pureDataPattern: /^_/
},
relations: {
'../collapse-item/index': {
type: 'child',
linked: function () {
this._setAllItemId();
},
linkChanged: function () {
this._setAllItemId();
},
unlinked: function () {
this._setAllItemId();
}
}
},
lifetimes: {
ready: function () {
this.updateView();
}
},
properties: {
/**
* 折叠面板类型
*/
type: {
type: String,
value: 'normal'
},
/**
* 需要展开的 collapse-item 的id
*/
expandItemId: {
type: Array,
value: []
}
},
data: {
/**
* 当前展开的collapse-item节点列表
*/
_expandItems: []
},
observers: {
'expandItemId': function () {
this.updateView();
}
},
methods: {
async updateView() {
let expandItemId;
if (this.data.type === 'accordion') {
expandItemId = this.data.expandItemId.slice(0, 1);
} else {
expandItemId = this.data.expandItemId;
}
let children = this.getRelationNodes('../collapse-item/index');
for (let i = 0; i < children.length; i++) {
let item = children[i];
let id = item.data.itemId === 'default' ? i : item.data.itemId;
if (expandItemId.indexOf(id) > -1 && !item.isExpandContent) {
await this.setCollapseItemStatus(item, true);
} else if (item.isExpandContent || this.data.type === 'accordion') {
await this.setCollapseItemStatus(item, false);
}
}
},
/**
* 点击折叠面板子项回调函数
* @param collapseItem
*/
async onTapCollapseItem(collapseItem) {
if (this.data.type === 'accordion') {
await this.foldAllExpandItem(collapseItem);
}
this.setCollapseItemStatus(collapseItem, !collapseItem.data.isExpandContent);
if (!collapseItem.data.isExpandContent) {
this.triggerEvent('linexpand', { id: collapseItem.data.itemId ? collapseItem.data.itemId : collapseItem.data._idDefault });
} else {
this.triggerEvent('linfold', { id: collapseItem.data.itemId ? collapseItem.data.itemId : collapseItem.data._idDefault });
}
},
/**
* 设置子组件状态
*/
async setCollapseItemStatus(collapseItem, isExpand) {
if (isExpand) {
collapseItem.expandContent();
this.data._expandItems.push(collapseItem);
} else {
await collapseItem.foldContent();
for (let i = 0; i < this.data._expandItems.length; i++) {
if (this.data._expandItems[i] === collapseItem) {
this.data._expandItems.splice(i, 1);
}
}
}
},
/**
* 关闭所有打开的collapse-item
*/
foldAllExpandItem(collapseItem) {
for (let i = 0; i < this.data._expandItems.length; i++) {
if (collapseItem !== this.data._expandItems[i]) {
this.data._expandItems[i].foldContent();
}
}
this.data._expandItems = [];
},
/**
* 重新设置子项组件的默认id
*/
_setAllItemId() {
let children = this.getRelationNodes('../collapse-item/index');
children.forEach((item, index) => {
item.data._idDefault = index;
});
}
}
});

View File

@ -1,5 +0,0 @@
{
"component": true,
"usingComponents": {
}
}

View File

@ -1,3 +0,0 @@
<view class="container">
<slot></slot>
</view>

View File

@ -1,256 +0,0 @@
import nodeUtil from '../core/utils/node-util';
Component({
externalClasses: [
'l-class-header',
'l-class-active',
'l-class-inactive',
'l-class-line',
'l-class-tabimage',
'l-header-class',
'l-active-class',
'l-inactive-class',
'l-line-class',
'l-tabimage-class',
'l-content-class'
],
relations: {
'../tabpanel/index': {
type: 'child'
},
linked() {
// 每次有子节点被插入时执行target是该节点实例对象触发在该节点attached生命周期之后
this.initTabs();
}
},
options: {
multipleSlots: true // 在组件定义时的选项中启用多slot支持
},
/**
* 组件的属性列表
*/
properties: {
activeKey: {
type: String,
value: '',
observer: 'changeCurrent'
},
placement: {
type: String,
value: 'top'
},
aminmated: Boolean,
scrollable: Boolean,
swipeable: {
type: Boolean,
value: true
},
hasLine: {
type: Boolean,
value: true
},
activeColor: {
type: String,
value: '#333333'
},
inactiveColor: {
type: String,
value: '#bbbbbb'
}
},
data: {
tabList: [],
currentIndex: 0,
transformX: 0,
transformY: 0
},
ready() {
this.initTabs();
},
/**
* 组件的方法列表
*/
methods: {
initTabs() {
this.initTabList();
this.initActiveIndex();
},
initActiveIndex(val = this.data.activeKey) {
let activeKey = val,
currentIndex = this.data.currentIndex;
this.data.tabList.forEach((item, index) => {
activeKey = !val && index === 0 ? item.key : activeKey;
currentIndex = item.key === activeKey ? index : currentIndex;
});
this.setData(
{
activeKey,
currentIndex
},
() => {
if (this.data.scrollable) {
this.queryMultipleNodes();
}
}
);
},
initTabList() {
let items = this.getRelationNodes('../tabpanel/index');
if (items.length > 0) {
const tabList = [];
items.forEach(item => {
const tabIndex = tabList.findIndex(
tabItem => tabItem.tab === item.data.tab
);
let tab = {};
if (tabIndex === -1) {
tab = {
tab: item.data.tab,
key: item.data.key,
icon: item.data.icon,
iconStyle: item.data.iconStyle,
image: item.data.image,
subTabs: []
};
tabList.push(tab);
}
const targetTab = tabIndex === -1 ? tab : tabList[tabIndex];
if (item.data.subTab) {
targetTab.subTabs = targetTab.subTabs || [];
const subTabItem = {
tab: item.data.subTab,
key: item.data.subKey
};
targetTab.subTabs.push(subTabItem);
targetTab.activeSubKey =
this.data.subActiveKey || targetTab.subTabs[0].key;
targetTab.subCurrentIndex = 0;
}
});
this.setData({
tabList
});
}
},
swiperChange(e) {
const {source, current} = e.detail;
if (source === 'touch') {
const currentIndex = current;
const activeKey = this.data.tabList[current].key;
const subCurrentIndex = this.data.tabList[currentIndex].subCurrentIndex;
const activeSubKey = this.data.tabList[currentIndex].activeSubKey;
this._setChangeData({
activeKey,
currentIndex,
subCurrentIndex,
activeSubKey
});
}
},
subSwiperChange(e) {
const {source, current} = e.detail;
if (source === 'touch') {
const {currentIndex, activeKey} = this.data;
const subCurrentIndex = current;
const activeSubKey = this.data.tabList[currentIndex].subTabs[
subCurrentIndex
].key;
const tabs = this.data.tabList[currentIndex];
tabs.activeSubKey = activeSubKey;
tabs.subCurrentIndex = subCurrentIndex;
this.setData({
[`tabList[${currentIndex}]`]: tabs
});
this._setChangeData({
activeKey,
currentIndex,
activeSubKey,
subCurrentIndex
});
}
},
handleChange(e) {
const isSubHeader = e.currentTarget.dataset.headerType === 'subTab';
const {currentIndex, activeKey} = this.data;
const clickIndex = e.currentTarget.dataset.index;
const subCurrentIndex = isSubHeader
? clickIndex
: this.data.tabList[clickIndex].subCurrentIndex;
const activeSubKey = isSubHeader
? this.data.tabList[currentIndex].subTabs[subCurrentIndex].key
: this.data.tabList[clickIndex].activeSubKey;
if (isSubHeader) {
const tabs = this.data.tabList[currentIndex];
tabs.activeSubKey = activeSubKey;
tabs.subCurrentIndex = subCurrentIndex;
this.setData({
[`tabList[${currentIndex}]`]: tabs
});
this._setChangeData({
activeKey,
currentIndex,
activeSubKey,
subCurrentIndex
});
} else {
const activeKey = e.currentTarget.dataset.key;
this._setChangeData({
activeKey,
currentIndex: clickIndex,
subCurrentIndex,
activeSubKey
});
}
},
_setChangeData({
activeKey,
currentIndex,
activeSubKey = '',
subCurrentIndex = null
}) {
this.setData(
{
activeKey,
currentIndex
},
() => {
if (this.data.scrollable) {
this.queryMultipleNodes();
}
}
);
this.triggerEvent('linchange', {
activeKey,
currentIndex,
activeSubKey,
subCurrentIndex
});
},
async queryMultipleNodes() {
const {placement, activeKey, tabList} = this.data;
const res = await nodeUtil.getNodeRectFromComponent(this, '#' + activeKey);
if (['top', 'bottom'].indexOf(placement) !== -1) {
this.setData({
transformX: res.left - (tabList.length / 2) * res.width,
transformY: 0
});
} else {
const navRect = await nodeUtil.getNodeRectFromComponent(this, '.l-tabs-header');
const transformY = res.top - navRect.top - navRect.height / 2;
this.setData({
transformX: 0,
transformY: transformY
});
}
}
}
});

View File

@ -1,7 +0,0 @@
{
"component": true,
"usingComponents": {
"l-icon":"../icon/index",
"l-badge":"../badge/index"
}
}

View File

@ -1,252 +0,0 @@
/* components/tabs/index.wxss */
.l-tabs {
display: flex;
border-radius: 8rpx;
box-sizing: border-box;
overflow: hidden;
flex-direction: column;
background: #fff;
height: 100%;
.l-tabs-header {
display: flex;
width: 100%;
flex-direction: row;
background: rgba(255, 255, 255, 1);
align-items: center;
.l-tabs-item {
flex: 1;
font-size: 28rpx;
text-align: center;
box-sizing: border-box;
display: flex;
justify-content: center;
align-items: center;
}
.l-icon-active,
.l-tabs-active {
color: #333333;
font-size: 28rpx;
}
.l-icon-inactive,
.l-tabs-inactive {
font-size: 28rpx;
color: #bbbbbb;
}
.l-tabsitems-row {
flex-direction: row;
.l-icon-inactive,
.l-icon-active {
margin-right: 10rpx;
}
}
.l-tabsitems-row-reverse {
flex-direction: row-reverse;
.l-icon-inactive,
.l-icon-active {
margin-left: 10rpx;
}
}
}
}
.l-placement-top {
.l-tabs-header {
height: 80rpx;
.l-tabs-item {
min-height: 100%;
}
}
}
.l-sub-placement-left {
flex-direction: row;
.l-tabs-header {
flex-direction: column;
width: 160rpx;
& > .l-tabs-item {
width: 100%;
height: 80rpx;
background: #f6f8fa;
}
& > .l-tabs-active {
background: #fff;
}
}
}
.l-sub-placement-left .l-tabs-main .l-tabpanel-content{
width: 100%;
flex-direction: column;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
flex-direction: column;
position: relative;
will-change: transform;
will-change: transform;
transition: transform 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
}
.l-placement-top .l-tabpanel-content {
width: 100%;
height: 100%;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
}
.l-subpanel-content {
width: 100%;
height: 100%;
}
.l-tabpanel {
width: 100%;
height: 100%;
-webkit-flex-shrink: 0;
-ms-flex-negative: 0;
flex-shrink: 0;
-webkit-transition: opacity 0.45s;
transition: opacity 0.45s;
opacity: 1;
text-overflow: ellipsis;
}
.l-tabpanel-inactive {
opacity: 0;
height: 0;
padding: 0 !important;
pointer-events: none;
}
.l-subpanel {
height: 100%;
}
// 滚动标签栏-水平
.l-tabs-scroll.l-tabs-horizontal {
.l-tabs-header {
-webkit-overflow-scrolling: touch;
white-space: nowrap;
.l-tabs-item {
overflow: visible;
min-width: 160rpx;
}
}
.l-tabpanel-content {
height: 150px;
}
}
.l-tabs-vertical {
.l-tabsscroll {
width: 160rpx;
}
.l-tabs-header {
height: 100%;
min-height: 80rpx;
-webkit-overflow-scrolling: touch;
white-space: nowrap;
.l-tabs-item {
overflow: visible;
min-height: 80rpx;
}
}
}
// 下划线
.l-tabs-item {
position: relative;
}
.l-tab-line {
position: absolute;
bottom: 0;
left: 0;
right: 0;
width: 0;
background: #000;
}
.l-tabs-horizontal {
.l-tab-line {
height: 4rpx;
margin: 0 auto;
}
.l-tabs-active {
.l-tab-line {
width: 100%;
transition-delay: 0.1s;
}
}
}
.l-placement-top {
.l-tab-line {
bottom: 0
}
.l-tabs-header-line {
border-bottom: 1px solid #F3F3F3
}
}
.l-tabs-vertical {
.l-tabs-active {
.l-tab-line {
width: 6rpx !important;
height: 40rpx !important;
border-radius: 0 6rpx 6rpx 0;
top: 0;
left: 0;
margin: auto 0;
transition-delay: 0.1s;
}
}
}
.l-sub-placement-left {
.l-tab-line {
left: 0;
right: auto;
}
.l-tabs-header-line {
border-right: 1px solid #F3F3F3
}
}
.l-tab-image {
width: 100rpx;
height: 100rpx;
}
.l-tab-image-placement-top {
flex-direction: column;
}
.l-tab-image-placement-left {
flex-direction: row;
}
.l-tabs-main {
flex:1;
}
.l-combined-tabs-main {
display: flex
}

Some files were not shown because too many files have changed in this diff Show More