Browse Source

原纸商城小程序的项目创建,version 1.0.1

master
xpz2018 6 years ago
parent
commit
eac59d75a5
172 changed files with 16181 additions and 0 deletions
  1. 40
      app.js
  2. 23
      app.json
  3. 28
      app.wxss
  4. BIN
      assets/image/icon_address.png
  5. BIN
      assets/image/icon_kefu.png
  6. BIN
      assets/image/icon_share.png
  7. BIN
      assets/image/list_empty.png
  8. BIN
      assets/image/login_logo.png
  9. BIN
      assets/image/me_logo.png
  10. BIN
      assets/raw/ding.mp3
  11. 184
      colorui/animation.wxss
  12. 58
      colorui/components/cu-custom.js
  13. 4
      colorui/components/cu-custom.json
  14. 16
      colorui/components/cu-custom.wxml
  15. 1
      colorui/components/cu-custom.wxss
  16. 1226
      colorui/icon.wxss
  17. 2624
      colorui/main.wxss
  18. 382
      components/animation-group/index.js
  19. 3
      components/animation-group/index.json
  20. 3
      components/animation-group/index.wxml
  21. 206
      components/animation-group/index.wxss
  22. 62
      components/backdrop/index.js
  23. 6
      components/backdrop/index.json
  24. 1
      components/backdrop/index.wxml
  25. 15
      components/backdrop/index.wxss
  26. 146
      components/button/index.js
  27. 3
      components/button/index.json
  28. 26
      components/button/index.wxml
  29. 356
      components/button/index.wxss
  30. 68
      components/cell-group/index.js
  31. 3
      components/cell-group/index.json
  32. 7
      components/cell-group/index.wxml
  33. 31
      components/cell-group/index.wxss
  34. 187
      components/cell/index.js
  35. 3
      components/cell/index.json
  36. 42
      components/cell/index.wxml
  37. 98
      components/cell/index.wxss
  38. 264
      components/dialog/index.js
  39. 6
      components/dialog/index.json
  40. 56
      components/dialog/index.wxml
  41. 115
      components/dialog/index.wxss
  42. 42
      components/divider/index.js
  43. 3
      components/divider/index.json
  44. 6
      components/divider/index.wxml
  45. 53
      components/divider/index.wxss
  46. 1
      components/helpers/arrayTreeFilter.js
  47. 1
      components/helpers/baseComponent.js
  48. 1
      components/helpers/checkIPhoneX.js
  49. 1
      components/helpers/classNames.js
  50. 1
      components/helpers/compareVersion.js
  51. 1
      components/helpers/computedBehavior.js
  52. 1
      components/helpers/debounce.js
  53. 1
      components/helpers/eventsMixin.js
  54. 1
      components/helpers/funcBehavior.js
  55. 1
      components/helpers/isEmpty.js
  56. 1
      components/helpers/relationsBehavior.js
  57. 1
      components/helpers/safeAreaBehavior.js
  58. 1
      components/helpers/safeSetDataBehavior.js
  59. 1
      components/helpers/shallowEqual.js
  60. 1
      components/helpers/styleToCssString.js
  61. 47
      components/icon/index.js
  62. 3
      components/icon/index.json
  63. 1
      components/icon/index.wxml
  64. 2820
      components/icon/index.wxss
  65. 153
      components/image/index.js
  66. 3
      components/image/index.json
  67. 24
      components/image/index.wxml
  68. 87
      components/image/index.wxss
  69. 20
      components/index.js
  70. 287
      components/input-number/index.js
  71. 6
      components/input-number/index.json
  72. 9
      components/input-number/index.wxml
  73. 118
      components/input-number/index.wxss
  74. 135
      components/input-number/utils.js
  75. 78
      components/password-box/index.js
  76. 4
      components/password-box/index.json
  77. 17
      components/password-box/index.wxml
  78. 73
      components/password-box/index.wxss
  79. 193
      components/popup/index.js
  80. 7
      components/popup/index.json
  81. 26
      components/popup/index.wxml
  82. 114
      components/popup/index.wxss
  83. 56
      components/refresh-view/index.js
  84. 4
      components/refresh-view/index.json
  85. 9
      components/refresh-view/index.wxml
  86. 158
      components/refresh-view/index.wxs
  87. 68
      components/refresh-view/index.wxss
  88. 110
      components/result/index.js
  89. 6
      components/result/index.json
  90. 58
      components/result/index.wxml
  91. 36
      components/result/index.wxss
  92. 88
      components/step/index.js
  93. 4
      components/step/index.json
  94. 21
      components/step/index.wxml
  95. 122
      components/step/index.wxss
  96. 49
      components/steps/index.js
  97. 3
      components/steps/index.json
  98. 3
      components/steps/index.wxml
  99. 4
      components/steps/index.wxss
  100. 126
      components/tab/index.js

40
app.js

@ -0,0 +1,40 @@
//app.js
App({
release: false,
httpUrl: 'http://192.168.0.106:9000',
globalData: {
userInfo: {},
openId: null,
token: null
},
onLaunch: function () {
// 获取全局尺寸的一些配置
// var sysInfo = wx.getAccountInfoSync()
// if (sysInfo.miniProgram.appId == 'wx9e774103645f5c54') {
// this.httpUrl = 'http://192.168.0.106:9000'
// } else if (sysInfo.miniProgram.appId == 'wx5371934de00d6215') {
// this.httpUrl = 'https://mini.qniao.cn'
// }
if (this.release) {
this.httpUrl = 'https://mini.qniao.cn'
} else {
this.httpUrl = 'http://192.168.0.106:9000'
}
wx.getSystemInfo({
success: e => {
this.globalData.StatusBar = e.statusBarHeight;
let custom = wx.getMenuButtonBoundingClientRect();
this.globalData.Custom = custom;
this.globalData.CustomBar = custom.bottom + custom.top - e.statusBarHeight;
let windowHeight = e.windowHeight * (750 / e.windowWidth);
let statusBarHeight = this.globalData.CustomBar * (750 / e.windowWidth);
this.globalData.fragmentHeight = windowHeight - statusBarHeight
// console.log('fragmentHeight>>>' + this.globalData.fragmentHeight + ',windowHeight=' + windowHeight)
}
})
}
})

23
app.json

@ -0,0 +1,23 @@
{
"pages": [
"pages/mall/shops/index",
"pages/index/index",
"pages/mall/search-list/index",
"pages/mall/order-list/index",
"pages/mall/order-info/index",
"pages/mall/order-offer/index",
"pages/mall/order-result/index",
"pages/mall/order-detail/index",
"pages/home/password/index"
],
"window": {
"navigationBarBackgroundColor": "#009EE0",
"navigationBarTitleText": "",
"navigationStyle": "custom",
"navigationBarTextStyle": "black"
},
"usingComponents": {
"cu-custom": "/colorui/components/cu-custom"
},
"sitemapLocation": "sitemap.json"
}

28
app.wxss

@ -0,0 +1,28 @@
@import "colorui/main.wxss";
@import "colorui/icon.wxss";
@import "colorui/animation.wxss";
/**app.wxss**/
.scrollPage {
height: 100vh;
}
.flex-center{
align-items: center;
justify-content: center;
}
.flex-column {
-webkit-box-orient: vertical;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
}
.flex-justify {
align-items: center;
-webkit-box-pack: justify;
-webkit-justify-content: space-between;
-ms-flex-pack: justify;
justify-content: space-between;
}

BIN
assets/image/icon_address.png

Before After
Width: 32  |  Height: 32  |  Size: 1.7 KiB

BIN
assets/image/icon_kefu.png

Before After
Width: 48  |  Height: 48  |  Size: 1.9 KiB

BIN
assets/image/icon_share.png

Before After
Width: 28  |  Height: 28  |  Size: 739 B

BIN
assets/image/list_empty.png

Before After
Width: 128  |  Height: 128  |  Size: 3.7 KiB

BIN
assets/image/login_logo.png

Before After
Width: 786  |  Height: 112  |  Size: 15 KiB

BIN
assets/image/me_logo.png

Before After
Width: 146  |  Height: 36  |  Size: 2.6 KiB

BIN
assets/raw/ding.mp3

184
colorui/animation.wxss

@ -0,0 +1,184 @@
/*
Animation 微动画
基于ColorUI组建库的动画模块 by 文晓港 2019年3月26日19:52:28
*/
/* css 滤镜 控制黑白底色gif的 */
.gif-black{
mix-blend-mode: screen;
}
.gif-white{
mix-blend-mode: multiply;
}
/* Animation css */
[class*=animation-] {
animation-duration: .5s;
animation-timing-function: ease-out;
animation-fill-mode: both
}
.animation-fade {
animation-name: fade;
animation-duration: .8s;
animation-timing-function: linear
}
.animation-scale-up {
animation-name: scale-up
}
.animation-scale-down {
animation-name: scale-down
}
.animation-slide-top {
animation-name: slide-top
}
.animation-slide-bottom {
animation-name: slide-bottom
}
.animation-slide-left {
animation-name: slide-left
}
.animation-slide-right {
animation-name: slide-right
}
.animation-shake {
animation-name: shake
}
.animation-reverse {
animation-direction: reverse
}
@keyframes fade {
0% {
opacity: 0
}
100% {
opacity: 1
}
}
@keyframes scale-up {
0% {
opacity: 0;
transform: scale(.2)
}
100% {
opacity: 1;
transform: scale(1)
}
}
@keyframes scale-down {
0% {
opacity: 0;
transform: scale(1.8)
}
100% {
opacity: 1;
transform: scale(1)
}
}
@keyframes slide-top {
0% {
opacity: 0;
transform: translateY(-100%)
}
100% {
opacity: 1;
transform: translateY(0)
}
}
@keyframes slide-bottom {
0% {
opacity: 0;
transform: translateY(100%)
}
100% {
opacity: 1;
transform: translateY(0)
}
}
@keyframes shake {
0%,
100% {
transform: translateX(0)
}
10% {
transform: translateX(-9px)
}
20% {
transform: translateX(8px)
}
30% {
transform: translateX(-7px)
}
40% {
transform: translateX(6px)
}
50% {
transform: translateX(-5px)
}
60% {
transform: translateX(4px)
}
70% {
transform: translateX(-3px)
}
80% {
transform: translateX(2px)
}
90% {
transform: translateX(-1px)
}
}
@keyframes slide-left {
0% {
opacity: 0;
transform: translateX(-100%)
}
100% {
opacity: 1;
transform: translateX(0)
}
}
@keyframes slide-right {
0% {
opacity: 0;
transform: translateX(100%)
}
100% {
opacity: 1;
transform: translateX(0)
}
}

58
colorui/components/cu-custom.js

@ -0,0 +1,58 @@
const app = getApp();
Component({
/**
* 组件的一些选项
*/
options: {
addGlobalClass: true,
multipleSlots: true
},
/**
* 组件的对外属性
*/
properties: {
bgColor: {
type: String,
default: ''
},
isCustom: {
type: [Boolean, String],
default: false
},
isBack: {
type: [Boolean, String],
default: false
},
bgImage: {
type: String,
default: ''
},
},
/**
* 组件的初始数据
*/
data: {
StatusBar: app.globalData.StatusBar,
CustomBar: app.globalData.CustomBar,
Custom: app.globalData.Custom
},
/**
* 组件的方法列表
*/
methods: {
BackPage() {
if(getCurrentPages().length == 1){
this.toHome()
} else {
wx.navigateBack({
delta: 1
});
}
},
toHome(){
wx.reLaunch({
url: '/pages/mall/shops/index',
})
}
}
})

4
colorui/components/cu-custom.json

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

16
colorui/components/cu-custom.wxml

@ -0,0 +1,16 @@
<view class="cu-custom" style="height:{{CustomBar}}px">
<view class="cu-bar fixed {{bgImage!=''?'none-bg text-white bg-img':''}} {{bgColor}}" style="height:{{CustomBar}}px;padding-top:{{StatusBar}}px;{{bgImage?'background-image:url(' + bgImage+')':''}}">
<view class="action" bindtap="BackPage" wx:if="{{isBack}}">
<text class="cuIcon-back"></text>
<slot name="backText"></slot>
</view>
<view class="action border-custom" wx:if="{{isCustom}}" style="width:{{Custom.width}}px;height:{{Custom.height}}px;margin-left:calc(750rpx - {{Custom.right}}px)">
<text class="cuIcon-back" bindtap="BackPage"></text>
<text class="cuIcon-homefill" bindtap="toHome"></text>
</view>
<view class="content" style="top:{{StatusBar}}px">
<slot name="content"></slot>
</view>
<slot name="right"></slot>
</view>
</view>

1
colorui/components/cu-custom.wxss

@ -0,0 +1 @@
/* colorui/components/cu-custom.wxss */

1226
colorui/icon.wxss
File diff suppressed because it is too large
View File

2624
colorui/main.wxss
File diff suppressed because it is too large
View File

382
components/animation-group/index.js

@ -0,0 +1,382 @@
import baseComponent from '../helpers/baseComponent'
import styleToCssString from '../helpers/styleToCssString'
const ENTER = 'enter'
const ENTERING = 'entering'
const ENTERED = 'entered'
const EXIT = 'exit'
const EXITING = 'exiting'
const EXITED = 'exited'
const UNMOUNTED = 'unmounted'
const TRANSITION = 'transition'
const ANIMATION = 'animation'
const TIMEOUT = 1000 / 60
const defaultClassNames = {
enter: '', // 进入过渡的开始状态,在过渡过程完成之后移除
enterActive: '', // 进入过渡的结束状态,在过渡过程完成之后移除
enterDone: '', // 进入过渡的完成状态
exit: '', // 离开过渡的开始状态,在过渡过程完成之后移除
exitActive: '', // 离开过渡的结束状态,在过渡过程完成之后移除
exitDone: '', // 离开过渡的完成状态
}
baseComponent({
properties: {
// 触发组件进入或离开过渡的状态
in: {
type: Boolean,
value: false,
observer(newVal) {
if (this.data.isMounting) {
this.updated(newVal)
}
},
},
// 过渡的类名
classNames: {
type: null,
value: defaultClassNames,
},
// 过渡持续时间
duration: {
type: null,
value: null,
},
// 过渡动效的类型
type: {
type: String,
value: TRANSITION,
},
// 首次挂载时是否触发进入过渡
appear: {
type: Boolean,
value: false,
},
// 是否启用进入过渡
enter: {
type: Boolean,
value: true,
},
// 是否启用离开过渡
exit: {
type: Boolean,
value: true,
},
// 首次进入过渡时是否懒挂载组件
mountOnEnter: {
type: Boolean,
value: true,
},
// 离开过渡完成时是否卸载组件
unmountOnExit: {
type: Boolean,
value: true,
},
// 自定义类名
wrapCls: {
type: String,
value: '',
},
// 自定义样式
wrapStyle: {
type: [String, Object],
value: '',
observer(newVal) {
this.setData({
extStyle: styleToCssString(newVal),
})
},
},
disableScroll: {
type: Boolean,
value: false,
},
},
data: {
animateCss: '', // 动画样式
animateStatus: EXITED, // 动画状态,可选值 entering、entered、exiting、exited
isMounting: false, // 是否首次挂载
extStyle: '', // 组件样式
},
methods: {
/**
* 监听过渡或动画的回调函数
*/
addEventListener() {
const { animateStatus } = this.data
const { enter, exit } = this.getTimeouts()
if (animateStatus === ENTERING && !enter && this.data.enter) {
this.performEntered()
}
if (animateStatus === EXITING && !exit && this.data.exit) {
this.performExited()
}
},
/**
* 会在 WXSS transition wx.createAnimation 动画结束后触发
*/
onTransitionEnd() {
if (this.data.type === TRANSITION) {
this.addEventListener()
}
},
/**
* 会在一个 WXSS animation 动画完成时触发
*/
onAnimationEnd() {
if (this.data.type === ANIMATION) {
this.addEventListener()
}
},
/**
* 更新组件状态
* @param {String} nextStatus 下一状态ENTERING EXITING
* @param {Boolean} mounting 是否首次挂载
*/
updateStatus(nextStatus, mounting = false) {
if (nextStatus !== null) {
this.cancelNextCallback()
this.isAppearing = mounting
if (nextStatus === ENTERING) {
this.performEnter()
} else {
this.performExit()
}
}
},
/**
* 进入过渡
*/
performEnter() {
const { className, activeClassName } = this.getClassNames(ENTER)
const { enter } = this.getTimeouts()
const enterParams = {
animateStatus: ENTER,
animateCss: className,
}
const enteringParams = {
animateStatus: ENTERING,
animateCss: `${className} ${activeClassName}`,
}
// 若已禁用进入过渡,则更新状态至 ENTERED
if (!this.isAppearing && !this.data.enter) {
return this.performEntered()
}
// 第一阶段:设置进入过渡的开始状态,并触发 ENTER 事件
// 第二阶段:延迟一帧后,设置进入过渡的结束状态,并触发 ENTERING 事件
// 第三阶段:若已设置过渡的持续时间,则延迟指定时间后触发进入过渡完成 performEntered,否则等待触发 onTransitionEnd 或 onAnimationEnd
this.safeSetData(enterParams, () => {
this.triggerEvent('change', { animateStatus: ENTER })
this.triggerEvent(ENTER, { isAppearing: this.isAppearing })
// 由于有些时候不能正确的触发动画完成的回调,具体原因未知
// 所以采用延迟一帧的方式来确保可以触发回调
this.delayHandler(TIMEOUT, () => {
this.safeSetData(enteringParams, () => {
this.triggerEvent('change', { animateStatus: ENTERING })
this.triggerEvent(ENTERING, { isAppearing: this.isAppearing })
if (enter) {
this.delayHandler(enter, this.performEntered)
}
})
})
})
},
/**
* 进入过渡完成
*/
performEntered() {
const { doneClassName } = this.getClassNames(ENTER)
const enteredParams = {
animateStatus: ENTERED,
animateCss: doneClassName,
}
// 第三阶段:设置进入过渡的完成状态,并触发 ENTERED 事件
this.safeSetData(enteredParams, () => {
this.triggerEvent('change', { animateStatus: ENTERED })
this.triggerEvent(ENTERED, { isAppearing: this.isAppearing })
})
},
/**
* 离开过渡
*/
performExit() {
const { className, activeClassName } = this.getClassNames(EXIT)
const { exit } = this.getTimeouts()
const exitParams = {
animateStatus: EXIT,
animateCss: className,
}
const exitingParams = {
animateStatus: EXITING,
animateCss: `${className} ${activeClassName}`,
}
// 若已禁用离开过渡,则更新状态至 EXITED
if (!this.data.exit) {
return this.performExited()
}
// 第一阶段:设置离开过渡的开始状态,并触发 EXIT 事件
// 第二阶段:延迟一帧后,设置离开过渡的结束状态,并触发 EXITING 事件
// 第三阶段:若已设置过渡的持续时间,则延迟指定时间后触发离开过渡完成 performExited,否则等待触发 onTransitionEnd 或 onAnimationEnd
this.safeSetData(exitParams, () => {
this.triggerEvent('change', { animateStatus: EXIT })
this.triggerEvent(EXIT)
this.delayHandler(TIMEOUT, () => {
this.safeSetData(exitingParams, () => {
this.triggerEvent('change', { animateStatus: EXITING })
this.triggerEvent(EXITING)
if (exit) {
this.delayHandler(exit, this.performExited)
}
})
})
})
},
/**
* 离开过渡完成
*/
performExited() {
const { doneClassName } = this.getClassNames(EXIT)
const exitedParams = {
animateStatus: EXITED,
animateCss: doneClassName,
}
// 第三阶段:设置离开过渡的完成状态,并触发 EXITED 事件
this.safeSetData(exitedParams, () => {
this.triggerEvent('change', { animateStatus: EXITED })
this.triggerEvent(EXITED)
// 判断离开过渡完成时是否卸载组件
if (this.data.unmountOnExit) {
this.setData({ animateStatus: UNMOUNTED }, () => {
this.triggerEvent('change', { animateStatus: UNMOUNTED })
})
}
})
},
/**
* 获取指定状态下的类名
* @param {String} type 过渡类型enter exit
*/
getClassNames(type) {
const { classNames } = this.data
const className = typeof classNames !== 'string' ? classNames[type] : `${classNames}-${type}`
const activeClassName = typeof classNames !== 'string' ? classNames[`${type}Active`] : `${classNames}-${type}-active`
const doneClassName = typeof classNames !== 'string' ? classNames[`${type}Done`] : `${classNames}-${type}-done`
return {
className,
activeClassName,
doneClassName,
}
},
/**
* 获取过渡持续时间
*/
getTimeouts() {
const { duration } = this.data
if (duration !== null && typeof duration === 'object') {
return {
enter: duration.enter,
exit: duration.exit,
}
} else if (typeof duration === 'number') {
return {
enter: duration,
exit: duration,
}
}
return {}
},
/**
* 属性值 in 被更改时的响应函数
* @param {Boolean} newVal 触发组件进入或离开过渡的状态
*/
updated(newVal) {
let { animateStatus } = this.pendingData || this.data
let nextStatus = null
if (newVal) {
if (animateStatus === UNMOUNTED) {
animateStatus = EXITED
this.setData({ animateStatus: EXITED }, () => {
this.triggerEvent('change', { animateStatus: EXITED })
})
}
if (animateStatus !== ENTER && animateStatus !== ENTERING && animateStatus !== ENTERED) {
nextStatus = ENTERING
}
} else {
if (animateStatus === ENTER || animateStatus === ENTERING || animateStatus === ENTERED) {
nextStatus = EXITING
}
}
this.updateStatus(nextStatus)
},
/**
* 延迟一段时间触发回调
* @param {Number} timeout 延迟时间
* @param {Function} handler 回调函数
*/
delayHandler(timeout, handler) {
if (timeout) {
this.setNextCallback(handler)
setTimeout(this.nextCallback, timeout)
}
},
/**
* 点击事件
*/
onTap() {
this.triggerEvent('click')
},
/**
* 阻止移动触摸
*/
noop() {},
},
attached() {
let animateStatus = null
let appearStatus = null
if (this.data.in) {
if (this.data.appear) {
animateStatus = EXITED
appearStatus = ENTERING
} else {
animateStatus = ENTERED
}
} else {
if (this.data.unmountOnExit || this.data.mountOnEnter) {
animateStatus = UNMOUNTED
} else {
animateStatus = EXITED
}
}
// 由于小程序组件首次挂载时 observer 事件总是优先于 attached 事件
// 所以使用 isMounting 来强制优先触发 attached 事件
this.safeSetData({ animateStatus, isMounting: true }, () => {
this.triggerEvent('change', { animateStatus })
this.updateStatus(appearStatus, true)
})
},
})

3
components/animation-group/index.json

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

3
components/animation-group/index.wxml

@ -0,0 +1,3 @@
<view class="wux-class {{ wrapCls }} {{ animateCss }}" bindtap="onTap" catchtouchmove="{{ disableScroll ? 'noop' : '' }}" bindtransitionend="onTransitionEnd" bindanimationend="onAnimationEnd" wx:if="{{ animateStatus !== 'unmounted' }}" style="{{ extStyle }}">
<slot></slot>
</view>

206
components/animation-group/index.wxss

@ -0,0 +1,206 @@
.wux-animate--fadeIn-enter {
transition: opacity .3s;
opacity: 0
}
.wux-animate--fadeIn-enter-active,
.wux-animate--fadeIn-enter-done {
opacity: 1
}
.wux-animate--fadeIn-exit {
transition: opacity .3s;
opacity: 1
}
.wux-animate--fadeIn-exit-active,
.wux-animate--fadeIn-exit-done {
opacity: 0
}
.wux-animate--fadeInDown-enter {
transition: opacity .3s,transform .3s;
opacity: 0;
transform: translate3d(0,-100%,0)
}
.wux-animate--fadeInDown-enter-active,
.wux-animate--fadeInDown-enter-done {
opacity: 1;
transform: none
}
.wux-animate--fadeInDown-exit {
transition: opacity .3s,transform .3s;
opacity: 1;
transform: none
}
.wux-animate--fadeInDown-exit-active,
.wux-animate--fadeInDown-exit-done {
opacity: 0;
transform: translate3d(0,-100%,0)
}
.wux-animate--fadeInLeft-enter {
transition: opacity .3s,transform .3s;
opacity: 0;
transform: translate3d(-100%,0,0)
}
.wux-animate--fadeInLeft-enter-active,
.wux-animate--fadeInLeft-enter-done {
opacity: 1;
transform: none
}
.wux-animate--fadeInLeft-exit {
transition: opacity .3s,transform .3s;
opacity: 1;
transform: none
}
.wux-animate--fadeInLeft-exit-active,
.wux-animate--fadeInLeft-exit-done {
opacity: 0;
transform: translate3d(-100%,0,0)
}
.wux-animate--fadeInRight-enter {
transition: opacity .3s,transform .3s;
opacity: 0;
transform: translate3d(100%,0,0)
}
.wux-animate--fadeInRight-enter-active,
.wux-animate--fadeInRight-enter-done {
opacity: 1;
transform: none
}
.wux-animate--fadeInRight-exit {
transition: opacity .3s,transform .3s;
opacity: 1;
transform: none
}
.wux-animate--fadeInRight-exit-active,
.wux-animate--fadeInRight-exit-done {
opacity: 0;
transform: translate3d(100%,0,0)
}
.wux-animate--fadeInUp-enter {
transition: opacity .3s,transform .3s;
opacity: 0;
transform: translate3d(0,100%,0)
}
.wux-animate--fadeInUp-enter-active,
.wux-animate--fadeInUp-enter-done {
opacity: 1;
transform: none
}
.wux-animate--fadeInUp-exit {
transition: opacity .3s,transform .3s;
opacity: 1;
transform: none
}
.wux-animate--fadeInUp-exit-active,
.wux-animate--fadeInUp-exit-done {
opacity: 0;
transform: translate3d(0,100%,0)
}
.wux-animate--slideInUp-enter {
transition: transform .3s;
transform: translate3d(0,100%,0);
visibility: visible
}
.wux-animate--slideInUp-enter-active,
.wux-animate--slideInUp-enter-done {
transform: translateZ(0)
}
.wux-animate--slideInUp-exit {
transition: transform .3s;
transform: translateZ(0)
}
.wux-animate--slideInUp-exit-active,
.wux-animate--slideInUp-exit-done {
transform: translate3d(0,100%,0);
visibility: visible
}
.wux-animate--slideInDown-enter {
transition: transform .3s;
transform: translate3d(0,-100%,0);
visibility: visible
}
.wux-animate--slideInDown-enter-active,
.wux-animate--slideInDown-enter-done {
transform: translateZ(0)
}
.wux-animate--slideInDown-exit {
transition: transform .3s;
transform: translateZ(0)
}
.wux-animate--slideInDown-exit-active,
.wux-animate--slideInDown-exit-done {
transform: translate3d(0,-100%,0);
visibility: visible
}
.wux-animate--slideInLeft-enter {
transition: transform .3s;
transform: translate3d(-100%,0,0);
visibility: visible
}
.wux-animate--slideInLeft-enter-active,
.wux-animate--slideInLeft-enter-done {
transform: translateZ(0)
}
.wux-animate--slideInLeft-exit {
transition: transform .3s;
transform: translateZ(0)
}
.wux-animate--slideInLeft-exit-active,
.wux-animate--slideInLeft-exit-done {
transform: translate3d(-100%,0,0);
visibility: visible
}
.wux-animate--slideInRight-enter {
transition: transform .3s;
transform: translate3d(100%,0,0);
visibility: visible
}
.wux-animate--slideInRight-enter-active,
.wux-animate--slideInRight-enter-done {
transform: none
}
.wux-animate--slideInRight-exit {
transition: transform .3s;
transform: none
}
.wux-animate--slideInRight-exit-active,
.wux-animate--slideInRight-exit-done {
transform: translate3d(100%,0,0);
visibility: visible
}
.wux-animate--zoom-enter {
transition: all .3s cubic-bezier(.215,.61,.355,1);
opacity: .01;
transform: scale(.75)
}
.wux-animate--zoom-enter-active,
.wux-animate--zoom-enter-done {
opacity: 1;
transform: none
}
.wux-animate--zoom-exit {
transition: all .25s linear;
transform: none
}
.wux-animate--zoom-exit-active,
.wux-animate--zoom-exit-done {
opacity: .01;
transform: scale(.75)
}
.wux-animate--punch-enter {
transition: all .3s cubic-bezier(.215,.61,.355,1);
opacity: .01;
transform: scale(1.35)
}
.wux-animate--punch-enter-active,
.wux-animate--punch-enter-done {
opacity: 1;
transform: none
}
.wux-animate--punch-exit {
transition: all .25s linear;
transform: none
}
.wux-animate--punch-exit-active,
.wux-animate--punch-exit-done {
opacity: .01;
transform: scale(1.35)
}

62
components/backdrop/index.js

@ -0,0 +1,62 @@
import baseComponent from '../helpers/baseComponent'
baseComponent({
properties: {
prefixCls: {
type: String,
value: 'wux-backdrop',
},
transparent: {
type: Boolean,
value: false,
},
zIndex: {
type: Number,
value: 1000,
},
classNames: {
type: null,
value: 'wux-animate--fadeIn',
},
},
computed: {
classes: ['prefixCls, transparent', function(prefixCls, transparent) {
const wrap = transparent ? `${prefixCls}--transparent` : prefixCls
return {
wrap,
}
}],
},
methods: {
/**
* 保持锁定
*/
retain() {
if (typeof this.backdropHolds !== 'number' || !this.backdropHolds) {
this.backdropHolds = 0
}
this.backdropHolds = this.backdropHolds + 1
if (this.backdropHolds === 1) {
this.setData({ in: true })
}
},
/**
* 释放锁定
*/
release() {
if (this.backdropHolds === 1) {
this.setData({ in: false })
}
this.backdropHolds = Math.max(0, this.backdropHolds - 1)
},
/**
* 点击事件
*/
onClick() {
this.triggerEvent('click')
},
},
})

6
components/backdrop/index.json

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

1
components/backdrop/index.wxml

@ -0,0 +1 @@
<wux-animation-group wux-class="{{ classes.wrap }}" in="{{ in }}" classNames="{{ classNames }}" bind:click="onClick" wrapStyle="{{ { zIndex } }}" disableScroll />

15
components/backdrop/index.wxss

@ -0,0 +1,15 @@
.wux-backdrop {
background: rgba(0,0,0,.4)
}
.wux-backdrop,
.wux-backdrop--transparent {
position: fixed;
z-index: 1000;
top: 0;
right: 0;
left: 0;
bottom: 0
}
.wux-backdrop--transparent {
background: 0 0
}

146
components/button/index.js

@ -0,0 +1,146 @@
import baseComponent from '../helpers/baseComponent'
import classNames from '../helpers/classNames'
baseComponent({
properties: {
prefixCls: {
type: String,
value: 'wux-button',
},
type: {
type: String,
value: 'stable',
},
clear: {
type: Boolean,
value: false,
},
round: {
type: Boolean,
value: false,
},
block: {
type: Boolean,
value: false,
},
full: {
type: Boolean,
value: false,
},
outline: {
type: Boolean,
value: false,
},
bordered: {
type: Boolean,
value: true,
},
size: {
type: String,
value: 'default',
},
disabled: {
type: Boolean,
value: false,
},
loading: {
type: Boolean,
value: false,
},
formType: {
type: String,
value: '',
},
openType: {
type: String,
value: '',
},
hoverClass: {
type: String,
value: 'default',
},
hoverStopPropagation: {
type: Boolean,
value: false,
},
hoverStartTime: {
type: Number,
value: 20,
},
hoverStayTime: {
type: Number,
value: 70,
},
lang: {
type: String,
value: 'en',
},
sessionFrom: {
type: String,
value: '',
},
sendMessageTitle: {
type: String,
value: '',
},
sendMessagePath: {
type: String,
value: '',
},
sendMessageImg: {
type: String,
value: '',
},
showMessageCard: {
type: Boolean,
value: false,
},
appParameter: {
type: String,
value: '',
},
},
computed: {
classes: ['prefixCls, hoverClass, type, size, block, full, clear, outline, round, bordered, disabled', function (prefixCls, hoverClass, type, size, block, full, clear, outline, round, bordered, disabled) {
const wrap = classNames(prefixCls, {
[`${prefixCls}--${type}`]: type,
[`${prefixCls}--${size}`]: size,
[`${prefixCls}--block`]: block,
[`${prefixCls}--full`]: full,
[`${prefixCls}--clear`]: clear,
[`${prefixCls}--round`]: round,
[`${prefixCls}--outline`]: outline,
[`${prefixCls}--bordered`]: bordered,
[`${prefixCls}--disabled`]: disabled,
})
const hover = hoverClass && hoverClass !== 'default' ? hoverClass : `${prefixCls}--hover`
return {
wrap,
hover,
}
}],
},
methods: {
onTap() {
if (!this.data.disabled && !this.data.loading) {
this.triggerEvent('click')
}
},
bindgetuserinfo(e) {
this.triggerEvent('getuserinfo', e.detail)
},
bindcontact(e) {
this.triggerEvent('contact', e.detail)
},
bindgetphonenumber(e) {
this.triggerEvent('getphonenumber', e.detail)
},
bindopensetting(e) {
this.triggerEvent('opensetting', e.detail)
},
onError(e) {
this.triggerEvent('error', e.detail)
},
},
})

3
components/button/index.json

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

26
components/button/index.wxml

@ -0,0 +1,26 @@
<button
class="wux-class {{ classes.wrap }}"
disabled="{{ disabled }}"
loading="{{ loading }}"
form-type="{{ formType }}"
open-type="{{ openType }}"
hover-class="wux-hover-class {{ !disabled ? classes.hover : 'none' }}"
hover-stop-propagation="{{ hoverStopPropagation }}"
hover-start-time="{{ hoverStartTime }}"
hover-stay-time="{{ hoverStayTime }}"
lang="{{ lang }}"
bindgetuserinfo="bindgetuserinfo"
session-from="{{ sessionFrom }}"
send-message-title="{{ sendMessageTitle }}"
send-message-path="{{ sendMessagePath }}"
send-message-img="{{ sendMessageImg }}"
show-message-card="{{ showMessageCard }}"
bindcontact="bindcontact"
bindgetphonenumber="bindgetphonenumber"
app-parameter="{{ appParameter }}"
binderror="onError"
bindopensetting="bindopensetting"
bindtap="onTap"
>
<slot></slot>
</button>

356
components/button/index.wxss

@ -0,0 +1,356 @@
.wux-button {
color: inherit!important;
background: 0 0!important;
font-weight: 400;
text-decoration: none;
overflow: visible;
width: auto!important;
-webkit-tap-highlight-color: transparent;
position: relative;
display: inline-block;
box-sizing: border-box;
margin: 0;
padding: 0 24rpx;
min-width: 104rpx;
min-height: 88rpx!important;
border: none;
border-radius: 8rpx;
vertical-align: middle;
text-align: center;
text-overflow: ellipsis;
font-size: 32rpx;
line-height: 84rpx;
cursor: pointer
}
.wux-button:after {
display: block;
position: static;
top: auto;
left: auto;
width: auto;
height: auto;
border: none;
border-radius: 0;
transform: none;
transform-origin: 0 0
}
.wux-button:after {
content: " ";
width: 100%;
height: 100%;
position: absolute;
top: -12rpx;
right: -12rpx;
bottom: -12rpx;
left: -12rpx;
border: none;
transform: none;
transform-origin: 0 0;
box-sizing: border-box;
border-radius: 0
}
.wux-button--bordered {
border: 2rpx solid transparent
}
.wux-button--disabled {
opacity: .4!important
}
.wux-button--small {
padding: 4rpx 8rpx 2rpx;
min-width: 56rpx;
min-height: 60rpx!important;
font-size: 24rpx;
line-height: 52rpx
}
.wux-button--large {
padding: 0 32rpx;
min-width: 136rpx;
min-height: 118rpx!important;
font-size: 40rpx;
line-height: 106rpx
}
.wux-button--block,
.wux-button--full {
width: 100%!important;
margin-top: 20rpx;
margin-bottom: 20rpx
}
.wux-button--block {
display: block;
clear: both
}
.wux-button--block:after {
clear: both
}
.wux-button--full {
display: block;
margin-right: 0!important;
margin-left: 0!important;
border-right-width: 0;
border-left-width: 0;
border-radius: 0
}
.wux-button--outline.wux-button--hover {
color: #fff!important
}
.wux-button--light,
.wux-button--light--disabled {
border-color: transparent!important;
background-color: #fff!important;
color: #fff!important
}
.wux-button--light.wux-button--outline,
.wux-button--light.wux-button--outline.wux-button--disabled {
border-color: #fff!important;
background-color: transparent!important;
color: #fff!important
}
.wux-button--light.wux-button--clear,
.wux-button--light.wux-button--clear.wux-button--disabled {
background-color: transparent!important;
color: #e6e6e6!important
}
.wux-button--light.wux-button--clear.wux-button--hover {
background-color: rgba(0,0,0,0)!important;
color: #fff!important
}
.wux-button--light.wux-button--hover {
background-color: #e6e6e6!important;
color: #fff!important
}
.wux-button--stable,
.wux-button--stable--disabled {
border-color: transparent!important;
background-color: #f8f8f8!important;
color: #fff!important
}
.wux-button--stable.wux-button--outline,
.wux-button--stable.wux-button--outline.wux-button--disabled {
border-color: #f8f8f8!important;
background-color: transparent!important;
color: #f8f8f8!important
}
.wux-button--stable.wux-button--clear,
.wux-button--stable.wux-button--clear.wux-button--disabled {
background-color: transparent!important;
color: #dfdfdf!important
}
.wux-button--stable.wux-button--clear.wux-button--hover {
background-color: rgba(0,0,0,0)!important;
color: #f8f8f8!important
}
.wux-button--stable.wux-button--hover {
background-color: #dfdfdf!important;
color: #fff!important
}
.wux-button--positive,
.wux-button--positive--disabled {
border-color: transparent!important;
background-color: #008AFF!important;
color: #fff!important
}
.wux-button--positive.wux-button--outline,
.wux-button--positive.wux-button--outline.wux-button--disabled {
border-color: #008AFF!important;
background-color: transparent!important;
color: #008AFF!important
}
.wux-button--positive.wux-button--clear,
.wux-button--positive.wux-button--clear.wux-button--disabled {
background-color: transparent!important;
color: #0c60ee!important
}
.wux-button--positive.wux-button--clear.wux-button--hover {
background-color: rgba(0,0,0,0)!important;
color: #008AFF!important
}
.wux-button--positive.wux-button--hover {
background-color: #0c60ee!important;
color: #fff!important
}
.wux-button--calm,
.wux-button--calm--disabled {
border-color: transparent!important;
background-color: #11c1f3!important;
color: #fff!important
}
.wux-button--calm.wux-button--outline,
.wux-button--calm.wux-button--outline.wux-button--disabled {
border-color: #11c1f3!important;
background-color: transparent!important;
color: #11c1f3!important
}
.wux-button--calm.wux-button--clear,
.wux-button--calm.wux-button--clear.wux-button--disabled {
background-color: transparent!important;
color: #0a9dc7!important
}
.wux-button--calm.wux-button--clear.wux-button--hover {
background-color: rgba(0,0,0,0)!important;
color: #11c1f3!important
}
.wux-button--calm.wux-button--hover {
background-color: #0a9dc7!important;
color: #fff!important
}
.wux-button--assertive,
.wux-button--assertive--disabled {
border-color: transparent!important;
background-color: #ef473a!important;
color: #fff!important
}
.wux-button--assertive.wux-button--outline,
.wux-button--assertive.wux-button--outline.wux-button--disabled {
border-color: #ef473a!important;
background-color: transparent!important;
color: #ef473a!important
}
.wux-button--assertive.wux-button--clear,
.wux-button--assertive.wux-button--clear.wux-button--disabled {
background-color: transparent!important;
color: #e42112!important
}
.wux-button--assertive.wux-button--clear.wux-button--hover {
background-color: rgba(0,0,0,0)!important;
color: #ef473a!important
}
.wux-button--assertive.wux-button--hover {
background-color: #e42112!important;
color: #fff!important
}
.wux-button--balanced,
.wux-button--balanced--disabled {
border-color: transparent!important;
background-color: #33cd5f!important;
color: #fff!important
}
.wux-button--balanced.wux-button--outline,
.wux-button--balanced.wux-button--outline.wux-button--disabled {
border-color: #33cd5f!important;
background-color: transparent!important;
color: #33cd5f!important
}
.wux-button--balanced.wux-button--clear,
.wux-button--balanced.wux-button--clear.wux-button--disabled {
background-color: transparent!important;
color: #28a54c!important
}
.wux-button--balanced.wux-button--clear.wux-button--hover {
background-color: rgba(0,0,0,0)!important;
color: #33cd5f!important
}
.wux-button--balanced.wux-button--hover {
background-color: #28a54c!important;
color: #fff!important
}
.wux-button--energized,
.wux-button--energized--disabled {
border-color: transparent!important;
background-color: #ffc900!important;
color: #fff!important
}
.wux-button--energized.wux-button--outline,
.wux-button--energized.wux-button--outline.wux-button--disabled {
border-color: #ffc900!important;
background-color: transparent!important;
color: #ffc900!important
}
.wux-button--energized.wux-button--clear,
.wux-button--energized.wux-button--clear.wux-button--disabled {
background-color: transparent!important;
color: #cca100!important
}
.wux-button--energized.wux-button--clear.wux-button--hover {
background-color: rgba(0,0,0,0)!important;
color: #ffc900!important
}
.wux-button--energized.wux-button--hover {
background-color: #cca100!important;
color: #fff!important
}
.wux-button--royal,
.wux-button--royal--disabled {
border-color: transparent!important;
background-color: #886aea!important;
color: #fff!important
}
.wux-button--royal.wux-button--outline,
.wux-button--royal.wux-button--outline.wux-button--disabled {
border-color: #886aea!important;
background-color: transparent!important;
color: #886aea!important
}
.wux-button--royal.wux-button--clear,
.wux-button--royal.wux-button--clear.wux-button--disabled {
background-color: transparent!important;
color: #643de4!important
}
.wux-button--royal.wux-button--clear.wux-button--hover {
background-color: rgba(0,0,0,0)!important;
color: #886aea!important
}
.wux-button--royal.wux-button--hover {
background-color: #643de4!important;
color: #fff!important
}
.wux-button--dark,
.wux-button--dark--disabled {
border-color: transparent!important;
background-color: #444!important;
color: #fff!important
}
.wux-button--dark.wux-button--outline,
.wux-button--dark.wux-button--outline.wux-button--disabled {
border-color: #444!important;
background-color: transparent!important;
color: #444!important
}
.wux-button--dark.wux-button--clear,
.wux-button--dark.wux-button--clear.wux-button--disabled {
background-color: transparent!important;
color: #2b2b2b!important
}
.wux-button--dark.wux-button--clear.wux-button--hover {
background-color: rgba(0,0,0,0)!important;
color: #444!important
}
.wux-button--dark.wux-button--hover {
background-color: #2b2b2b!important;
color: #fff!important
}
.wux-button--light {
border-color: transparent!important;
background-color: #fff!important;
color: #444!important
}
.wux-button--light.wux-button--outline {
border-color: #ddd!important;
background-color: transparent!important;
color: #ddd!important
}
.wux-button--light.wux-button--clear.wux-button--hover {
background-color: rgba(0,0,0,0)!important;
color: #ddd!important
}
.wux-button--light.wux-button--hover {
background-color: #e6e6e6!important;
color: #fff!important
}
.wux-button--stable {
border-color: transparent!important;
background-color: #f8f8f8!important;
color: #444!important
}
.wux-button--stable.wux-button--outline {
border-color: #b2b2b2!important;
background-color: transparent!important;
color: #b2b2b2!important
}
.wux-button--stable.wux-button--clear.wux-button--hover {
background-color: rgba(0,0,0,0)!important;
color: #b2b2b2!important
}
.wux-button--stable.wux-button--hover {
background-color: #dfdfdf!important;
color: #fff!important
}

68
components/cell-group/index.js

@ -0,0 +1,68 @@
import baseComponent from '../helpers/baseComponent'
import classNames from '../helpers/classNames'
baseComponent({
options: {
multipleSlots: false,
},
relations: {
'../cell/index': {
type: 'descendant',
observer() {
this.debounce(this.updateIsLastElement)
},
},
},
properties: {
prefixCls: {
type: String,
value: 'wux-cell-group',
},
title: {
type: String,
value: '',
},
label: {
type: String,
value: '',
},
},
computed: {
classes: ['prefixCls', function(prefixCls) {
const wrap = classNames(prefixCls)
const hd = `${prefixCls}__hd`
const bd = `${prefixCls}__bd`
const ft = `${prefixCls}__ft`
return {
wrap,
hd,
bd,
ft,
}
}],
},
methods: {
updateIsLastElement() {
const elements = this.getRelationNodes('../cell/index')
if (elements.length > 0) {
const lastIndex = elements.length - 1
elements.forEach((element, index) => {
element.updateIsLastElement(index === lastIndex)
})
}
},
getBoundingClientRect(callback) {
const className = `.${this.data.prefixCls}`
wx
.createSelectorQuery()
.in(this)
.select(className)
.boundingClientRect((rect) => {
if (!rect) return
callback.call(this, rect.height)
})
.exec()
},
},
})

3
components/cell-group/index.json

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

7
components/cell-group/index.wxml

@ -0,0 +1,7 @@
<view class="wux-class {{ classes.wrap }}">
<view class="{{ classes.hd }}" wx:if="{{ title }}">{{ title }}</view>
<view class="{{ classes.bd }}">
<slot></slot>
</view>
<view class="{{ classes.ft }}" wx:if="{{ label }}">{{ label }}</view>
</view>

31
components/cell-group/index.wxss

@ -0,0 +1,31 @@
.wux-cell-group__hd {
padding: 30rpx 30rpx 18rpx;
font-size: 28rpx;
color: #888;
width: 100%;
box-sizing: border-box
}
.wux-cell-group__bd {
position: relative;
background-color: #fff
}
.wux-cell-group__bd:after {
content: " ";
position: absolute;
top: 0;
left: 0;
width: 200%;
height: 200%;
transform: scale(.5);
transform-origin: 0 0;
pointer-events: none;
box-sizing: border-box;
/* border: 0 solid #d9d9d9;
border-top-width: 1rpx;
border-bottom-width: 1rpx */
}
.wux-cell-group__ft {
padding: 18rpx 30rpx 30rpx;
font-size: 28rpx;
color: #888
}

187
components/cell/index.js

@ -0,0 +1,187 @@
import baseComponent from '../helpers/baseComponent'
import classNames from '../helpers/classNames'
import eventsMixin from '../helpers/eventsMixin'
const defaultEvents = {
onClick() {},
onError() {},
}
baseComponent({
behaviors: [eventsMixin({ defaultEvents })],
relations: {
'../cell-group/index': {
type: 'ancestor',
},
'../picker/index': {
type: 'parent',
},
'../date-picker/index': {
type: 'parent',
},
'../popup-select/index': {
type: 'parent',
},
},
properties: {
prefixCls: {
type: String,
value: 'wux-cell',
},
disabled: {
type: Boolean,
value: false,
},
hoverClass: {
type: String,
value: 'default',
},
hoverStopPropagation: {
type: Boolean,
value: false,
},
hoverStartTime: {
type: Number,
value: 20,
},
hoverStayTime: {
type: Number,
value: 70,
},
lang: {
type: String,
value: 'en',
},
sessionFrom: {
type: String,
value: '',
},
sendMessageTitle: {
type: String,
value: '',
},
sendMessagePath: {
type: String,
value: '',
},
sendMessageImg: {
type: String,
value: '',
},
showMessageCard: {
type: Boolean,
value: false,
},
appParameter: {
type: String,
value: '',
},
thumb: {
type: String,
value: '',
},
title: {
type: String,
value: '',
},
label: {
type: String,
value: '',
},
extra: {
type: String,
value: '',
},
isLink: {
type: Boolean,
value: false,
},
openType: {
type: String,
value: 'navigateTo',
},
url: {
type: String,
value: '',
},
delta: {
type: Number,
value: 1,
},
},
data: {
isLast: false,
},
computed: {
classes: ['prefixCls, hoverClass, isLast, isLink, disabled', function(prefixCls, hoverClass, isLast, isLink, disabled) {
const wrap = classNames(prefixCls, {
[`${prefixCls}--last`]: isLast,
[`${prefixCls}--access`]: isLink,
[`${prefixCls}--disabled`]: disabled,
})
const hd = `${prefixCls}__hd`
const thumb = `${prefixCls}__thumb`
const bd = `${prefixCls}__bd`
const text = `${prefixCls}__text`
const desc = `${prefixCls}__desc`
const ft = `${prefixCls}__ft`
const hover = hoverClass && hoverClass !== 'default' ? hoverClass : `${prefixCls}--hover`
return {
wrap,
hd,
thumb,
bd,
text,
desc,
ft,
hover,
}
}],
},
methods: {
onTap() {
if (!this.data.disabled) {
this.triggerEvent('click')
this.linkTo()
}
},
bindgetuserinfo(e) {
this.triggerEvent('getuserinfo', e.detail)
},
bindcontact(e) {
this.triggerEvent('contact', e.detail)
},
bindgetphonenumber(e) {
this.triggerEvent('getphonenumber', e.detail)
},
bindopensetting(e) {
this.triggerEvent('opensetting', e.detail)
},
onError(e) {
this.triggerEvent('error', e.detail)
},
linkTo() {
const { url, isLink, openType, delta } = this.data
const navigate = [
'navigateTo',
'redirectTo',
'switchTab',
'navigateBack',
'reLaunch',
]
// openType 属性可选值为 navigateTo、redirectTo、switchTab、navigateBack、reLaunch
if (!isLink || !url || !navigate.includes(openType)) {
return false
} else if (openType === 'navigateBack') {
return wx[openType].call(wx, { delta })
} else {
return wx[openType].call(wx, { url })
}
},
updateIsLastElement(isLast) {
this.setData({ isLast })
},
},
})

3
components/cell/index.json

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

42
components/cell/index.wxml

@ -0,0 +1,42 @@
<button
class="wux-class {{ classes.wrap }}"
disabled="{{ disabled }}"
open-type="{{ openType }}"
hover-class="{{ !disabled ? classes.hover : 'none' }}"
hover-stop-propagation="{{ hoverStopPropagation }}"
hover-start-time="{{ hoverStartTime }}"
hover-stay-time="{{ hoverStayTime }}"
lang="{{ lang }}"
bindgetuserinfo="bindgetuserinfo"
session-from="{{ sessionFrom }}"
send-message-title="{{ sendMessageTitle }}"
send-message-path="{{ sendMessagePath }}"
send-message-img="{{ sendMessageImg }}"
show-message-card="{{ showMessageCard }}"
bindcontact="bindcontact"
bindgetphonenumber="bindgetphonenumber"
app-parameter="{{ appParameter }}"
binderror="onError"
bindopensetting="bindopensetting"
bindtap="onTap"
>
<view class="{{ classes.hd }}">
<block wx:if="{{ thumb }}">
<image class="{{ classes.thumb }}" src="{{ thumb }}" />
</block>
<block wx:else>
<slot name="header"></slot>
</block>
</view>
<view class="{{ classes.bd }}">
<view wx:if="{{ title }}" class="{{ classes.text }}">{{ title }}</view>
<view wx:if="{{ label }}" class="{{ classes.desc }}">{{ label }}</view>
<slot></slot>
</view>
<view class="{{ classes.ft }}">
<block wx:if="{{ extra }}">{{ extra }}</block>
<block wx:else>
<slot name="footer"></slot>
</block>
</view>
</button>

98
components/cell/index.wxss

@ -0,0 +1,98 @@
.wux-cell {
margin: 0;
border-radius: 0;
color: inherit!important;
background: 0 0!important;
font-size: inherit;
font-weight: 400;
line-height: inherit;
text-align: inherit;
text-decoration: none;
overflow: visible;
min-height: 100rpx!important;
width: auto!important;
box-sizing: border-box;
-webkit-tap-highlight-color: transparent;
padding: 20rpx 30rpx;
position: relative;
display: -ms-flexbox;
display: flex;
-ms-flex-align: center;
align-items: center;
background: #fff
}
.wux-cell:after {
display: block;
position: static;
top: auto;
left: auto;
width: auto;
height: auto;
border: none;
border-radius: 0;
transform: none;
transform-origin: 0 0
}
.wux-cell:after {
content: " ";
position: absolute;
bottom: 0;
right: 0;
height: 1rpx;
border-bottom: 1rpx solid #d9d9d9;
color: #d9d9d9;
transform-origin: 0 100%;
transform: scaleY(.5);
left: 30rpx
}
.wux-cell--last:after {
display: none
}
.wux-cell--hover {
background-color: #ececec!important
}
.wux-cell--disabled {
opacity: .3
}
.wux-cell__thumb {
display: block;
width: 40rpx;
height: 40rpx;
margin-right: 10rpx
}
.wux-cell__bd {
-ms-flex: 1;
flex: 1
}
.wux-cell__text {
text-align: left
}
.wux-cell__desc {
text-align: left;
line-height: 1.2;
font-size: 24rpx;
color: grey
}
.wux-cell__ft {
text-align: right;
color: grey
}
.wux-cell--access .wux-cell__ft {
padding-right: 26rpx;
position: relative
}
.wux-cell--access .wux-cell__ft:after {
content: " ";
display: inline-block;
height: 16rpx;
width: 16rpx;
border-width: 2rpx 2rpx 0 0;
border-color: #999999;
border-style: solid;
transform: matrix(.71,.71,-.71,.71,0,0);
top: -4rpx;
position: absolute;
top: 50%;
margin-top: -8rpx;
right: 4rpx
}

264
components/dialog/index.js

@ -0,0 +1,264 @@
import baseComponent from '../helpers/baseComponent'
import classNames from '../helpers/classNames'
const defaults = {
prefixCls: 'wux-dialog',
title: '',
content: '',
buttons: [],
verticalButtons: !1,
resetOnClose: false,
closable: false,
mask: true,
maskClosable: true,
zIndex: 1000,
}
const defaultOptions = {
onCancel() {},
cancelText: '取消',
cancelType: 'default',
onConfirm() {},
confirmText: '确定',
confirmType: 'primary',
}
baseComponent({
useFunc: true,
data: defaults,
computed: {
classes: ['prefixCls, buttons, verticalButtons', function(prefixCls, btns, verticalButtons) {
const prompt = `${prefixCls}__prompt`
const input = `${prefixCls}__input`
const buttons = classNames(`${prefixCls}__buttons`, {
[`${prefixCls}__buttons--${verticalButtons ? 'vertical' : 'horizontal'}`]: true,
})
const button = btns.map((button) => {
const wrap = classNames(`${prefixCls}__button`, {
[`${prefixCls}__button--${button.type || 'default'}`]: button.type || 'default',
[`${prefixCls}__button--bold`]: button.bold,
[`${prefixCls}__button--disabled`]: button.disabled,
[`${button.className}`]: button.className,
})
const hover = button.hoverClass && button.hoverClass !== 'default' ? button.hoverClass : `${prefixCls}__button--hover`
return {
wrap,
hover,
}
})
return {
prompt,
input,
buttons,
button,
}
}],
},
methods: {
/**
* 组件关闭时重置其内部数据
*/
onClosed() {
if (this.data.resetOnClose) {
const params = {
...this.$$mergeOptionsToData(defaults),
prompt: null,
}
this.$$setData(params)
}
},
/**
* 点击 x mask 回调
*/
onClose() {
this.hide()
},
/**
* 隐藏
*/
hide(cb) {
this.$$setData({ in: false })
if (typeof cb === 'function') {
cb.call(this)
}
},
/**
* 显示
*/
show(opts = {}) {
const options = this.$$mergeOptionsAndBindMethods(Object.assign({}, defaults, opts))
this.$$setData({ in: true, ...options })
this.originalButtons = options.buttons
return this.hide.bind(this)
},
/**
* 触发事件
*/
runCallbacks(e, method) {
const { index } = e.currentTarget.dataset
const button = this.originalButtons[index]
if (!button.disabled) {
this.hide(() => typeof button[method] === 'function' && button[method](e))
}
},
/**
* 按钮点击事件
*/
buttonTapped(e) {
this.runCallbacks(e, 'onTap')
},
/**
* 用户点击该按钮时会返回获取到的用户信息回调的detail数据与wx.getUserInfo返回的一致open-type="getUserInfo"时有效
*/
bindgetuserinfo(e) {
this.runCallbacks(e, 'onGetUserInfo')
},
/**
* 客服消息回调open-type="contact"时有效
*/
bindcontact(e) {
this.runCallbacks(e, 'onContact')
},
/**
* 获取用户手机号回调open-type=getPhoneNumber时有效
*/
bindgetphonenumber(e) {
this.runCallbacks(e, 'onGotPhoneNumber')
},
/**
* 在打开授权设置页后回调open-type=openSetting时有效
*/
bindopensetting(e) {
this.runCallbacks(e, 'onOpenSetting')
},
/**
* 当使用开放能力时发生错误的回调open-type=launchApp时有效
*/
onError(e) {
this.runCallbacks(e, 'onError')
},
/**
* 当键盘输入时触发 input 事件
*/
bindinput(e) {
this.$$setData({
'prompt.response': e.detail.value,
})
},
/**
* 显示dialog组件
* @param {Object} opts 配置项
* @param {String} opts.title 提示标题
* @param {String} opts.content 提示文本
* @param {Boolean} opts.verticalButtons 是否显示垂直按钮布局
* @param {Array} opts.buttons 按钮
* @param {String} opts.buttons.text 按钮的文字
* @param {String} opts.buttons.type 按钮的类型
* @param {Boolean} opts.buttons.bold 是否加粗按钮的文字
* @param {Function} opts.buttons.onTap 按钮的点击事件
*/
open(opts = {}) {
return this.show(opts)
},
/**
* 显示dialog组件
* @param {Object} opts 配置项
* @param {String} opts.title 提示标题
* @param {String} opts.content 提示文本
* @param {String} opts.confirmText 确定按钮的文字默认为"确定"
* @param {String} opts.confirmType 确定按钮的类型
* @param {Function} opts.onConfirm 确定按钮的点击事件
*/
alert(opts = {}) {
return this.open(Object.assign({
buttons: [{
text: opts.confirmText || defaultOptions.confirmText,
type: opts.confirmType || defaultOptions.confirmType,
onTap: (e) => {
typeof opts.onConfirm === 'function' && opts.onConfirm(e)
},
}, ],
}, opts))
},
/**
* 显示dialog组件
* @param {Object} opts 配置项
* @param {String} opts.title 提示标题
* @param {String} opts.content 提示文本
* @param {String} opts.confirmText 确定按钮的文字默认为"确定"
* @param {String} opts.confirmType 确定按钮的类型
* @param {Function} opts.onConfirm 确定按钮的点击事件
* @param {String} opts.cancelText 取消按钮的文字默认为"取消"
* @param {String} opts.cancelType 取消按钮的类型
* @param {Function} opts.onCancel 取消按钮的点击事件
*/
confirm(opts = {}) {
return this.open(Object.assign({
buttons: [{
text: opts.cancelText || defaultOptions.cancelText,
type: opts.cancelType || defaultOptions.cancelType,
onTap: (e) => {
typeof opts.onCancel === 'function' && opts.onCancel(e)
},
},
{
text: opts.confirmText || defaultOptions.confirmText,
type: opts.confirmType || defaultOptions.confirmType,
onTap: (e) => {
typeof opts.onConfirm === 'function' && opts.onConfirm(e)
},
},
],
}, opts))
},
/**
* 显示dialog组件
* @param {Object} opts 配置项
* @param {String} opts.title 提示标题
* @param {String} opts.content 提示文本
* @param {String} opts.fieldtype input 的类型有效值text, number, idcard, digit
* @param {Boolean} opts.password 是否是密码类型
* @param {String} opts.defaultText 默认值
* @param {String} opts.placeholder 输入框为空时占位符
* @param {Number} opts.maxlength 最大输入长度设置为 -1 的时候不限制最大长度
* @param {String} opts.confirmText 确定按钮的文字默认为"确定"
* @param {String} opts.confirmType 确定按钮的类型
* @param {Function} opts.onConfirm 确定按钮的点击事件
* @param {String} opts.cancelText 取消按钮的文字默认为"取消"
* @param {String} opts.cancelType 取消按钮的类型
* @param {Function} opts.onCancel 取消按钮的点击事件
*/
prompt(opts = {}) {
const prompt = {
fieldtype: opts.fieldtype ? opts.fieldtype : 'text',
password: !!opts.password,
response: opts.defaultText ? opts.defaultText : '',
placeholder: opts.placeholder ? opts.placeholder : '',
maxlength: opts.maxlength ? parseInt(opts.maxlength) : '',
}
return this.open(Object.assign({
prompt: prompt,
buttons: [{
text: opts.cancelText || defaultOptions.cancelText,
type: opts.cancelType || defaultOptions.cancelType,
onTap: (e) => {
typeof opts.onCancel === 'function' && opts.onCancel(e)
},
},
{
text: opts.confirmText || defaultOptions.confirmText,
type: opts.confirmType || defaultOptions.confirmType,
onTap: (e) => {
typeof opts.onConfirm === 'function' && opts.onConfirm(e, this.data.prompt.response)
},
},
],
}, opts))
},
},
})

6
components/dialog/index.json

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

56
components/dialog/index.wxml

@ -0,0 +1,56 @@
<wux-popup
visible="{{ in }}"
z-index="{{ zIndex }}"
closable="{{ closable }}"
mask="{{ mask }}"
mask-closable="{{ maskClosable }}"
bind:close="onClose"
bind:closed="onClosed"
>
<view slot="header" class="text-xl">{{ title }}</view>
<view wx:if="{{ content || prompt }}">
<text>{{ content }}</text>
<view class="{{ classes.prompt }}" wx:if="{{ prompt }}">
<label>
<input
type="{{ prompt.fieldtype }}"
class="{{ classes.input }}"
value="{{ prompt.response }}"
password="{{ prompt.password }}"
placeholder="{{ prompt.placeholder }}"
maxlength="{{ maxlength }}"
bindinput="bindinput"
/>
</label>
</view>
</view>
<view slot="footer" class="{{ classes.buttons }}">
<block wx:for="{{ buttons }}" wx:for-item="button" wx:key="index">
<button
class="{{ classes.button[index].wrap }}"
disabled="{{ button.disabled }}"
open-type="{{ button.openType }}"
hover-class="{{ !button.disabled ? classes.button[index].hover : 'none' }}"
hover-stop-propagation="{{ button.hoverStopPropagation }}"
hover-start-time="{{ button.hoverStartTime || 20 }}"
hover-stay-time="{{ button.hoverStayTime || 70 }}"
lang="{{ button.lang || 'en' }}"
bindgetuserinfo="bindgetuserinfo"
session-from="{{ button.sessionFrom }}"
send-message-title="{{ button.sendMessageTitle }}"
send-message-path="{{ button.sendMessagePath }}"
send-message-img="{{ button.sendMessageImg }}"
show-message-card="{{ button.showMessageCard }}"
bindcontact="bindcontact"
bindgetphonenumber="bindgetphonenumber"
app-parameter="{{ button.appParameter }}"
binderror="onError"
bindopensetting="bindopensetting"
data-index="{{ index }}"
bindtap="buttonTapped"
>
{{ button.text }}
</button>
</block>
</view>
</wux-popup>

115
components/dialog/index.wxss

@ -0,0 +1,115 @@
.wux-dialog__button {
padding: 0;
margin: 0;
border-radius: 0;
background: 0 0!important;
font-size: inherit;
font-weight: 400;
line-height: inherit;
text-align: inherit;
text-decoration: none;
overflow: visible;
min-height: 0!important;
width: auto!important;
box-sizing: border-box;
-webkit-tap-highlight-color: transparent;
display: block;
-ms-flex: 1;
flex: 1;
color: #33cd5f!important;
position: relative
}
.wux-dialog__button:after {
display: block;
position: static;
top: auto;
left: auto;
width: auto;
height: auto;
border: none;
border-radius: 0;
transform: none;
transform-origin: 0 0
}
.wux-dialog__button--default {
color: #353535!important
}
.wux-dialog__button--primary {
color: #009ddf!important
}
.wux-dialog__button--bold {
font-weight: 500!important
}
.wux-dialog__button--hover {
background-color: #ececec!important
}
.wux-dialog__button--disabled {
opacity: .3
}
.wux-dialog__prompt {
position: relative;
margin-top: 20rpx
}
.wux-dialog__prompt:after {
content: " ";
position: absolute;
top: 0;
left: 0;
width: 200%;
height: 200%;
transform: scale(.5);
transform-origin: 0 0;
pointer-events: none;
box-sizing: border-box;
border: 0 solid #d5d5d6;
border-top-width: 2rpx;
border-right-width: 2rpx;
border-bottom-width: 2rpx;
border-left-width: 2rpx;
border-radius: 12rpx
}
.wux-dialog__input {
padding: 8rpx 12rpx;
height: 72rpx;
line-height: 1;
width: 100%;
text-align: left;
box-sizing: border-box
}
.wux-dialog__buttons {
display: -ms-flexbox;
display: flex;
-ms-flex: 1;
flex: 1
}
.wux-dialog__buttons--horizontal .wux-dialog__button:after {
content: " ";
position: absolute;
left: 0;
top: 0;
width: 2rpx;
bottom: 0;
border-left: 2rpx solid #d5d5d6;
color: #d5d5d6;
transform-origin: 0 0;
transform: scaleX(.5)
}
.wux-dialog__buttons--horizontal .wux-dialog__button:first-child:after {
display: none
}
.wux-dialog__buttons--vertical {
display: block;
height: auto
}
.wux-dialog__buttons--vertical .wux-dialog__button:after {
content: " ";
position: absolute;
left: 0;
top: 0;
right: 0;
height: 2rpx;
border-top: 2rpx solid #d5d5d6;
color: #d5d5d6;
transform-origin: 0 0;
transform: scaleY(.5)
}

42
components/divider/index.js

@ -0,0 +1,42 @@
import baseComponent from '../helpers/baseComponent'
import classNames from '../helpers/classNames'
baseComponent({
properties: {
prefixCls: {
type: String,
value: 'wux-divider',
},
position: {
type: String,
value: 'center',
},
dashed: {
type: Boolean,
value: false,
},
text: {
type: String,
value: '',
},
showText: {
type: Boolean,
value: true,
},
},
computed: {
classes: ['prefixCls, dashed, showText, position', function(prefixCls, dashed, showText, position) {
const wrap = classNames(prefixCls, {
[`${prefixCls}--dashed`]: dashed,
[`${prefixCls}--text`]: showText,
[`${prefixCls}--text-${position}`]: showText && position,
})
const text = `${prefixCls}__text`
return {
wrap,
text,
}
}],
},
})

3
components/divider/index.json

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

6
components/divider/index.wxml

@ -0,0 +1,6 @@
<view class="wux-class {{ classes.wrap }}">
<view class="{{ classes.text }}" wx:if="{{ showText }}">
{{ text }}
<slot></slot>
</view>
</view>

53
components/divider/index.wxss

@ -0,0 +1,53 @@
.wux-divider {
display: block;
height: 2rpx;
width: 100%;
margin: 30rpx 0;
clear: both;
border-top: 2rpx solid #e8e8e8
}
.wux-divider--text {
display: table;
white-space: nowrap;
text-align: center;
background: 0 0;
font-weight: 500;
color: rgba(0,0,0,.85);
font-size: 32rpx;
border-top: none!important
}
.wux-divider--text:after,
.wux-divider--text:before {
content: '';
display: table-cell;
position: relative;
top: 50%;
width: 50%;
border-top-width: 2rpx;
border-top-style: solid;
border-top-color: #e8e8e8;
transform: translateY(50%)
}
.wux-divider--dashed {
border-top: 2rpx dashed #e8e8e8
}
.wux-divider--dashed.wux-divider--text:after,
.wux-divider--dashed.wux-divider--text:before {
border-top-style: dashed
}
.wux-divider--text-left:before {
width: 5%
}
.wux-divider--text-left:after {
width: 95%
}
.wux-divider--text-right:before {
width: 95%
}
.wux-divider--text-right:after {
width: 5%
}
.wux-divider__text {
display: inline-block;
padding: 0 30rpx
}

1
components/helpers/arrayTreeFilter.js

@ -0,0 +1 @@
"use strict";function arrayTreeFilter(e,r,t){(t=t||{}).childrenKeyName=t.childrenKeyName||"children";var a=e||[],l=[],i=0;do{var d=a.filter(function(e){return r(e,i)})[0];if(!d)break;l.push(d),a=d[t.childrenKeyName]||[],i+=1}while(0<a.length);return l}Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=void 0;var _default=arrayTreeFilter;exports.default=_default;

1
components/helpers/baseComponent.js

@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=void 0;var _computedBehavior=_interopRequireDefault(require("./computedBehavior")),_relationsBehavior=_interopRequireDefault(require("./relationsBehavior")),_safeAreaBehavior=_interopRequireDefault(require("./safeAreaBehavior")),_safeSetDataBehavior=_interopRequireDefault(require("./safeSetDataBehavior")),_funcBehavior=_interopRequireDefault(require("./funcBehavior")),_compareVersion=_interopRequireDefault(require("./compareVersion"));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}function ownKeys(r,e){var t=Object.keys(r);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(r);e&&(o=o.filter(function(e){return Object.getOwnPropertyDescriptor(r,e).enumerable})),t.push.apply(t,o)}return t}function _objectSpread(r){for(var e=1;e<arguments.length;e++){var t=null!=arguments[e]?arguments[e]:{};e%2?ownKeys(t,!0).forEach(function(e){_defineProperty(r,e,t[e])}):Object.getOwnPropertyDescriptors?Object.defineProperties(r,Object.getOwnPropertyDescriptors(t)):ownKeys(t).forEach(function(e){Object.defineProperty(r,e,Object.getOwnPropertyDescriptor(t,e))})}return r}function _defineProperty(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function _toConsumableArray(e){return _arrayWithoutHoles(e)||_iterableToArray(e)||_nonIterableSpread()}function _nonIterableSpread(){throw new TypeError("Invalid attempt to spread non-iterable instance")}function _iterableToArray(e){if(Symbol.iterator in Object(e)||"[object Arguments]"===Object.prototype.toString.call(e))return Array.from(e)}function _arrayWithoutHoles(e){if(Array.isArray(e)){for(var r=0,t=new Array(e.length);r<e.length;r++)t[r]=e[r];return t}}var _wx$getSystemInfoSync=wx.getSystemInfoSync(),platform=_wx$getSystemInfoSync.platform,SDKVersion=_wx$getSystemInfoSync.SDKVersion,libVersion="2.6.6";"devtools"===platform&&(0,_compareVersion.default)(SDKVersion,libVersion)<0&&wx&&wx.showModal&&wx.showModal({title:"提示",content:"当前基础库版本(".concat(SDKVersion,")过低,无法使用 Wux Weapp 组件库,请更新基础库版本 >=").concat(libVersion," 后重试。")});var baseComponent=function(e){var r=0<arguments.length&&void 0!==e?e:{};return r.externalClasses=["wux-class","wux-hover-class"].concat(_toConsumableArray(r.externalClasses=r.externalClasses||[])),r.behaviors=[_relationsBehavior.default,_safeSetDataBehavior.default].concat(_toConsumableArray(r.behaviors=r.behaviors||[]),[_computedBehavior.default]),r.useSafeArea&&(r.behaviors=[].concat(_toConsumableArray(r.behaviors),[_safeAreaBehavior.default]),delete r.useSafeArea),r.useFunc&&(r.behaviors=[].concat(_toConsumableArray(r.behaviors),[_funcBehavior.default]),delete r.useFunc),r.useField&&(r.behaviors=[].concat(_toConsumableArray(r.behaviors),["wx://form-field"]),delete r.useField),r.useExport&&(r.behaviors=[].concat(_toConsumableArray(r.behaviors),["wx://component-export"]),r.methods=_objectSpread({export:function(){return this}},r.methods),delete r.useExport),r.options=_objectSpread({multipleSlots:!0,addGlobalClass:!0},r.options),Component(r)},_default=baseComponent;exports.default=_default;

1
components/helpers/checkIPhoneX.js

@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.checkIPhoneX=exports.safeAreaInset=exports.getSystemInfo=void 0;var systemInfo=null,getSystemInfo=function(e){if(!systemInfo||e)try{systemInfo=wx.getSystemInfoSync()}catch(e){}return systemInfo};exports.getSystemInfo=getSystemInfo;var safeAreaInset={top:88,left:0,right:0,bottom:34};exports.safeAreaInset=safeAreaInset;var isIPhoneX=function(e){var t=e.model,o=e.platform;return/iPhone X/.test(t)&&"ios"===o},checkIPhoneX=function(e){return isIPhoneX(getSystemInfo(e))};exports.checkIPhoneX=checkIPhoneX;

1
components/helpers/classNames.js

@ -0,0 +1 @@
"use strict";function _typeof(e){return(_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=void 0;var hasOwn={}.hasOwnProperty;function classNames(){for(var e=[],t=0;t<arguments.length;t++){var o=arguments[t];if(o){var r=_typeof(o);if("string"===r||"number"===r)e.push(o);else if(Array.isArray(o)&&o.length){var n=classNames.apply(null,o);n&&e.push(n)}else if("object"===r)for(var s in o)hasOwn.call(o,s)&&o[s]&&e.push(s)}}return e.join(" ")}var _default=classNames;exports.default=_default;

1
components/helpers/compareVersion.js

@ -0,0 +1 @@
"use strict";function compareVersion(e,r){for(var t=e.split("."),a=r.split("."),n=Math.max(t.length,a.length);t.length<n;)t.push("0");for(;a.length<n;)a.push("0");for(var o=0;o<n;o++){var s=parseInt(t[o]),u=parseInt(a[o]);if(u<s)return 1;if(s<u)return-1}return 0}Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=void 0;var _default=compareVersion;exports.default=_default;

1
components/helpers/computedBehavior.js

@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=void 0;var _isEmpty=_interopRequireDefault(require("./isEmpty")),_shallowEqual=_interopRequireDefault(require("./shallowEqual"));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}function _toConsumableArray(e){return _arrayWithoutHoles(e)||_iterableToArray(e)||_nonIterableSpread()}function _nonIterableSpread(){throw new TypeError("Invalid attempt to spread non-iterable instance")}function _iterableToArray(e){if(Symbol.iterator in Object(e)||"[object Arguments]"===Object.prototype.toString.call(e))return Array.from(e)}function _arrayWithoutHoles(e){if(Array.isArray(e)){for(var r=0,t=new Array(e.length);r<e.length;r++)t[r]=e[r];return t}}function ownKeys(r,e){var t=Object.keys(r);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(r);e&&(n=n.filter(function(e){return Object.getOwnPropertyDescriptor(r,e).enumerable})),t.push.apply(t,n)}return t}function _objectSpread(r){for(var e=1;e<arguments.length;e++){var t=null!=arguments[e]?arguments[e]:{};e%2?ownKeys(t,!0).forEach(function(e){_defineProperty(r,e,t[e])}):Object.getOwnPropertyDescriptors?Object.defineProperties(r,Object.getOwnPropertyDescriptors(t)):ownKeys(t).forEach(function(e){Object.defineProperty(r,e,Object.getOwnPropertyDescriptor(t,e))})}return r}function _defineProperty(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function _slicedToArray(e,r){return _arrayWithHoles(e)||_iterableToArrayLimit(e,r)||_nonIterableRest()}function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}function _iterableToArrayLimit(e,r){var t=[],n=!0,o=!1,i=void 0;try{for(var a,u=e[Symbol.iterator]();!(n=(a=u.next()).done)&&(t.push(a.value),!r||t.length!==r);n=!0);}catch(e){o=!0,i=e}finally{try{n||null==u.return||u.return()}finally{if(o)throw i}}return t}function _arrayWithHoles(e){if(Array.isArray(e))return e}var ALL_DATA_KEY="**",trim=function(e){return(0<arguments.length&&void 0!==e?e:"").replace(/\s/g,"")},_default=Behavior({lifetimes:{attached:function(){this.initComputed()}},definitionFilter:function(e){var r=e.computed,n=void 0===r?{}:r,a=Object.keys(n).reduce(function(e,i){var r=_slicedToArray(Array.isArray(n[i])?n[i]:[ALL_DATA_KEY,n[i]],2),t=r[0],a=r[1];return _objectSpread({},e,_defineProperty({},t,function(){if("function"==typeof a){for(var e=arguments.length,r=new Array(e),t=0;t<e;t++)r[t]=arguments[t];var n=a.apply(this,r),o=this.data[i];(0,_isEmpty.default)(n)||(0,_shallowEqual.default)(n,o)||this.setData(_defineProperty({},i,n))}}))},{});Object.assign(e.observers=e.observers||{},a),Object.assign(e.methods=e.methods||{},{initComputed:function(e,r){var t=0<arguments.length&&void 0!==e?e:{},n=1<arguments.length&&void 0!==r&&r;if(!this.runInitComputed||n){this.runInitComputed=!1;var o=this,i=_objectSpread({},this.data,{},t);Object.keys(a).forEach(function(e){var r=trim(e).split(",").reduce(function(e,r){return[].concat(_toConsumableArray(e),[i[r]])},[]);a[e].apply(o,r)}),this.runInitComputed=!0}}})}});exports.default=_default;

1
components/helpers/debounce.js

@ -0,0 +1 @@
"use strict";function debounce(t,o,i){var n,u,r,a,c;function d(){var e=+new Date-a;e<o&&0<=e?n=setTimeout(d,o-e):(n=void 0,i||(c=t.apply(r,u),n||(u=r=void 0)))}function e(){r=this,u=arguments,a=+new Date;var e=i&&!n;return n=n||setTimeout(d,o),e&&(c=t.apply(r,u),u=r=void 0),c}return e.cancel=function(){void 0!==n&&(clearTimeout(n),n=void 0),u=r=void 0},e}Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=debounce;

1
components/helpers/eventsMixin.js

@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=eventsMixin;var defaultEvents={onChange:function(){}};function eventsMixin(){return Behavior({lifetimes:{created:function(){this._oriTriggerEvent=this.triggerEvent,this.triggerEvent=this._triggerEvent}},properties:{events:{type:Object,value:defaultEvents}},data:{inputEvents:defaultEvents},definitionFilter:function(t){Object.assign(t.data=t.data||{},{inputEvents:Object.assign({},defaultEvents,t.inputEvents)}),Object.assign(t.methods=t.methods||{},{_triggerEvent:function(t,e,n,i){var s=!(2<arguments.length&&void 0!==n)||n,a=3<arguments.length?i:void 0,r=this.data.inputEvents["on".concat(t[0].toUpperCase()).concat(t.slice(1))];s&&"function"==typeof r&&r.call(this,e),this._oriTriggerEvent(t,e,a)}}),Object.assign(t.observers=t.observers||{},{events:function(t){this.setData({inputEvents:Object.assign({},defaultEvents,this.data.inputEvents,t)})}})}})}

1
components/helpers/funcBehavior.js

@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=void 0;var mergeOptionsToData=function(t){var e=0<arguments.length&&void 0!==t?t:{},n=Object.assign({},e);for(var r in n)n.hasOwnProperty(r)&&"function"==typeof n[r]&&delete n[r];return n},bind=function(r,i){return function(){for(var t=arguments.length,e=new Array(t),n=0;n<t;n++)e[n]=arguments[n];return e.length?r.apply(i,e):r.call(i)}},assign=function(){for(var t=arguments.length,e=new Array(t),n=0;n<t;n++)e[n]=arguments[n];return Object.assign.apply(Object,[{}].concat(e))},_default=Behavior({definitionFilter:function(t){t.data=mergeOptionsToData(t.data),t.data.in=!1,t.data.visible=!1},methods:{$$mergeOptionsToData:mergeOptionsToData,$$mergeOptionsAndBindMethods:function(t,e){var n=0<arguments.length&&void 0!==t?t:{},r=1<arguments.length&&void 0!==e?e:this.fns,i=Object.assign({},n);for(var a in i)i.hasOwnProperty(a)&&"function"==typeof i[a]&&(r[a]=bind(i[a],this),delete i[a]);return i},$$setData:function(){for(var e=this,t=arguments.length,n=new Array(t),r=0;r<t;r++)n[r]=arguments[r];var i=assign.apply(void 0,[{}].concat(n));return new Promise(function(t){e.setData(i,t)})},$$requestAnimationFrame:function(t,e){var n=0<arguments.length&&void 0!==t?t:function(){},r=1<arguments.length&&void 0!==e?e:1e3/60;return new Promise(function(t){return setTimeout(t,r)}).then(n)}},created:function(){this.fns={}},detached:function(){this.fns={}}});exports.default=_default;

1
components/helpers/isEmpty.js

@ -0,0 +1 @@
"use strict";function _typeof(t){return(_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function isEmpty(t){if(Array.isArray(t))return 0===t.length;if("object"!==_typeof(t))return!t;if(t)for(var e in t)return!1;return!0}Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=void 0;var _default=isEmpty;exports.default=_default;

1
components/helpers/relationsBehavior.js

@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=void 0;var _isEmpty=_interopRequireDefault(require("./isEmpty")),_debounce2=_interopRequireDefault(require("./debounce"));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}function _defineProperty(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function bindFunc(e,t,n){var i=e[t];e[t]=function(e){n&&n.call(this,e,_defineProperty({},t,!0)),i&&i.call(this,e)}}var methods=["linked","linkChanged","unlinked"],extProps=["observer"],_default=Behavior({lifetimes:{created:function(){this._debounce=null},detached:function(){this._debounce&&this._debounce.cancel&&this._debounce.cancel()}},definitionFilter:function(e){var n=e.relations;if(!(0,_isEmpty.default)(n)){var t=function(e){var t=n[e];methods.forEach(function(e){return bindFunc(t,e,t.observer)}),extProps.forEach(function(e){return delete t[e]})};for(var i in n)t(i)}Object.assign(e.methods=e.methods||{},{getRelationsName:function(e){var t=0<arguments.length&&void 0!==e?e:["parent","child","ancestor","descendant"];return Object.keys(n||{}).map(function(e){return n[e]&&t.includes(n[e].type)?e:null}).filter(function(e){return!!e})},debounce:function(e,t,n){var i=1<arguments.length&&void 0!==t?t:0,r=2<arguments.length&&void 0!==n&&n;return(this._debounce=this._debounce||(0,_debounce2.default)(e.bind(this),i,r)).call(this)}})}});exports.default=_default;

1
components/helpers/safeAreaBehavior.js

@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=void 0;var _checkIPhoneX=require("./checkIPhoneX");function _defineProperty(e,t,o){return t in e?Object.defineProperty(e,t,{value:o,enumerable:!0,configurable:!0,writable:!0}):e[t]=o,e}function _typeof(e){return(_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}var defaultSafeArea={top:!1,bottom:!1},setSafeArea=function(e){return"boolean"==typeof e?Object.assign({},defaultSafeArea,{top:e,bottom:e}):null!==e&&"object"===_typeof(e)?Object.assign({},defaultSafeArea):"string"==typeof e?Object.assign({},defaultSafeArea,_defineProperty({},e,!0)):defaultSafeArea},_default=Behavior({properties:{safeArea:{type:[Boolean,String,Object],value:!1}},observers:{safeArea:function(e){this.setData({safeAreaConfig:setSafeArea(e)})}},definitionFilter:function(e){var t=((0,_checkIPhoneX.getSystemInfo)()||{}).statusBarHeight,o=(0,_checkIPhoneX.checkIPhoneX)();Object.assign(e.data=e.data||{},{safeAreaConfig:defaultSafeArea,statusBarHeight:t,isIPhoneX:o})}});exports.default=_default;

1
components/helpers/safeSetDataBehavior.js

@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=void 0;var _default=Behavior({lifetimes:{created:function(){this.nextCallback=null},detached:function(){this.cancelNextCallback()}},methods:{safeSetData:function(t,a){var e=this;this.pendingData=Object.assign({},this.data,t),a=this.setNextCallback(a),this.setData(t,function(){e.pendingData=null,a()})},setNextCallback:function(a){var e=this,l=!0;return this.nextCallback=function(t){l&&(l=!1,e.nextCallback=null,a.call(e,t))},this.nextCallback.cancel=function(){l=!1},this.nextCallback},cancelNextCallback:function(){null!==this.nextCallback&&(this.nextCallback.cancel(),this.nextCallback=null)}}});exports.default=_default;

1
components/helpers/shallowEqual.js

@ -0,0 +1 @@
"use strict";function _typeof(t){return(_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=void 0;var hasOwnProperty=Object.prototype.hasOwnProperty;function is(t,e){return t===e?0!==t||0!==e||1/t==1/e:t!=t&&e!=e}function shallowEqual(t,e){if(is(t,e))return!0;if("object"!==_typeof(t)||null===t||"object"!==_typeof(e)||null===e)return!1;var o=Object.keys(t),r=Object.keys(e);if(o.length!==r.length)return!1;for(var n=0;n<o.length;n++)if(!hasOwnProperty.call(e,o[n])||!is(t[o[n]],e[o[n]]))return!1;return!0}var _default=shallowEqual;exports.default=_default;

1
components/helpers/styleToCssString.js

@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var isUnitlessNumber={boxFlex:!(exports.default=void 0),boxFlexGroup:!0,columnCount:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,strokeDashoffset:!0,strokeOpacity:!0,strokeWidth:!0};function prefixKey(e,t){return e+t.charAt(0).toUpperCase()+t.substring(1)}var prefixes=["Webkit","ms","Moz","O"];Object.keys(isUnitlessNumber).forEach(function(t){prefixes.forEach(function(e){isUnitlessNumber[prefixKey(e,t)]=isUnitlessNumber[t]})});var msPattern=/^ms-/,_uppercasePattern=/([A-Z])/g;function hyphenate(e){return e.replace(_uppercasePattern,"-$1").toLowerCase()}function hyphenateStyleName(e){return hyphenate(e).replace(msPattern,"-ms-")}var isArray=Array.isArray,keys=Object.keys,counter=1,unquotedContentValueRegex=/^(normal|none|(\b(url\([^)]*\)|chapter_counter|attr\([^)]*\)|(no-)?(open|close)-quote|inherit)((\b\s*)|$|\s+))+)$/;function buildRule(e,t){return isUnitlessNumber[e]||"number"!=typeof t?"content"!==e||unquotedContentValueRegex.test(t)||(t="'"+t.replace(/'/g,"\\'")+"'"):t+="px",hyphenateStyleName(e)+": "+t+"; "}function styleToCssString(e){var t="";if("string"==typeof e)return e;if(!e||0===keys(e).length)return t;for(var r=keys(e),n=0,s=r.length;n<s;n++){var o=r[n],i=e[o];if(isArray(i))for(var a=0,u=i.length;a<u;a++)t+=buildRule(o,i[a]);else t+=buildRule(o,i)}return t}var _default=styleToCssString;exports.default=_default;

47
components/icon/index.js

@ -0,0 +1,47 @@
Component({
externalClasses: ['wux-class'],
properties: {
type: {
type: String,
value: '',
},
size: {
type: [String, Number],
value: 32,
observer: 'updated',
},
color: {
type: String,
value: '',
},
hidden: {
type: Boolean,
value: false,
},
},
data: {
fontSize: '',
},
methods: {
updated(size = this.data.size) {
let fontSize = size
if (typeof size === 'number') {
fontSize = `${size}px`
} else if (typeof size === 'string') {
if (!isNaN(Number(size))) {
fontSize = `${size}px`
}
}
if (this.data.fontSize !== fontSize) {
this.setData({
fontSize,
})
}
},
},
attached() {
this.updated()
},
})

3
components/icon/index.json

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

1
components/icon/index.wxml

@ -0,0 +1 @@
<view class="wux-class ion {{ type ? 'ion-' + type : '' }}" style="font-size: {{ fontSize }}; {{ color ? 'color: ' + color : '' }}" hidden="{{ hidden }}"></view>

2820
components/icon/index.wxss
File diff suppressed because it is too large
View File

153
components/image/index.js

@ -0,0 +1,153 @@
import baseComponent from '../helpers/baseComponent'
import classNames from '../helpers/classNames'
const EMPTY = 'empty'
const LOADING = 'loading'
const LOADED = 'loaded'
const ERROR = 'error'
const UNMOUNTED = 'unmounted'
const calcStyle = (value) => typeof value === 'number' ? `${value}px` : value
baseComponent({
properties: {
prefixCls: {
type: String,
value: 'wux-image',
},
src: {
type: String,
value: '',
},
mode: {
type: String,
value: 'aspectFill',
},
lazyLoad: {
type: Boolean,
value: true,
},
shape: {
type: String,
value: 'normal',
},
width: {
type: null,
value: 300,
},
height: {
type: null,
value: 225,
},
unmountOnEmpty: {
type: Boolean,
value: false,
},
unmountOnError: {
type: Boolean,
value: false,
},
empty: {
type: String,
value: '',
},
loading: {
type: String,
value: '',
},
error: {
type: String,
value: '',
},
},
data: {
status: '',
},
computed: {
classes: ['prefixCls, shape, mode, status, empty, loading, error', function(prefixCls, shape, mode, status, empty, loading, error) {
const wrap = classNames(prefixCls, {
[`${prefixCls}--${shape}`]: shape,
[`${prefixCls}--${mode}`]: mode,
[`${prefixCls}--${status}`]: status,
})
const inner = `${prefixCls}__inner`
const thumb = `${prefixCls}__thumb`
const mask = classNames(`${prefixCls}__mask`, {
[`${prefixCls}__mask--text`]: empty || loading || error,
})
const text = `${prefixCls}__text`
return {
wrap,
inner,
thumb,
mask,
text,
}
}],
},
observers: {
src(newVal) {
this.updated(newVal)
},
['width, height'](...args) {
this.updateStyle(...args)
},
},
methods: {
/**
* 更新资源地址
*/
updated(src) {
this.updateStatus(!!src ? LOADING : this.data.unmountOnEmpty ? UNMOUNTED : EMPTY)
},
/**
* 更新组件样式
*/
updateStyle(width, height) {
const style = `width: ${calcStyle(width)}; height: ${calcStyle(height)}`
this.setData({
style,
})
},
/**
* 更新组件状态
*/
updateStatus(status) {
if (this.data.status !== status) {
this.setData({
status,
})
}
this.triggerEvent('change', { status })
},
/**
* 资源加载完成时的回调函数
*/
onLoad(e) {
this.updateStatus(LOADED)
this.triggerEvent('load', { ...e.detail, status: LOADED })
},
/**
* 资源加载失败时的回调函数
*/
onError(e) {
const status = this.data.unmountOnError ? UNMOUNTED : ERROR
this.updateStatus(status)
this.triggerEvent('error', { ...e.detail, status })
},
/**
* 点击事件
*/
onTap(e) {
this.triggerEvent('click', { ...e.detail, status: this.data.status })
},
},
attached() {
const { width, height, src } = this.data
this.updateStyle(width, height)
this.updated(src)
},
})

3
components/image/index.json

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

24
components/image/index.wxml

@ -0,0 +1,24 @@
<view class="wux-class {{ classes.wrap }}" style="{{ style }}" bindtap="onTap" wx:if="{{ status !== 'unmounted' }}">
<view class="{{ classes.inner }}">
<image class="{{ classes.thumb }}" lazy-load="{{ lazyLoad }}" mode="{{ mode }}" src="{{ src }}" bindload="onLoad" binderror="onError" wx:if="{{ src }}" />
<slot></slot>
</view>
<view class="{{ classes.mask }}" wx:if="{{ status === 'empty' }}">
<view class="{{ classes.text }}" wx:if="{{ empty }}">{{ empty }}</view>
<block wx:else>
<slot name="empty"></slot>
</block>
</view>
<view class="{{ classes.mask }}" wx:elif="{{ status === 'loading' }}">
<view class="{{ classes.text }}" wx:if="{{ loading }}">{{ loading }}</view>
<block wx:else>
<slot name="loading"></slot>
</block>
</view>
<view class="{{ classes.mask }}" wx:elif="{{ status === 'error' }}">
<view class="{{ classes.text }}" wx:if="{{ error }}">{{ error }}</view>
<block wx:else>
<slot name="error"></slot>
</block>
</view>
</view>

87
components/image/index.wxss

@ -0,0 +1,87 @@
.wux-image {
position: relative;
overflow: hidden;
display: -ms-flexbox;
display: flex;
box-sizing: border-box
}
.wux-image--rounded {
border-radius: 8rpx
}
.wux-image--circle {
border-radius: 50%
}
.wux-image--thumbnail {
background-color: #fff;
border-radius: 8rpx
}
.wux-image--thumbnail:after {
content: " ";
position: absolute;
top: 0;
left: 0;
width: 200%;
height: 200%;
transform: scale(.5);
transform-origin: 0 0;
pointer-events: none;
box-sizing: border-box;
border: 0 solid #d9d9d9;
border-width: 2rpx;
border-radius: 16rpx
}
.wux-image--thumbnail .wux-image__inner,
.wux-image--thumbnail .wux-image__mask {
top: 8rpx;
right: 8rpx;
bottom: 8rpx;
left: 8rpx;
width: calc(100% - 16rpx)!important;
height: calc(100% - 16rpx)!important
}
.wux-image--widthFix .wux-image__inner {
position: relative
}
.wux-image image,
.wux-image__thumb {
display: inline-block;
overflow: hidden;
width: 100%;
height: 100%;
vertical-align: middle
}
.wux-image__inner {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 10;
width: 100%;
height: 100%;
opacity: 0
}
.wux-image--loaded .wux-image__inner {
opacity: 1
}
.wux-image__mask {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 20
}
.wux-image__mask--text {
display: -ms-flexbox;
display: flex;
-ms-flex-align: center;
align-items: center;
-ms-flex-pack: center;
justify-content: center
}
.wux-image__text {
color: #373a3c;
text-align: center;
padding: 20rpx
}

20
components/index.js

@ -0,0 +1,20 @@
/**
* 使用选择器选择组件实例节点返回匹配到的第一个组件实例对象
* @param {String} selector 节点选择器
* @param {Object} ctx 页面栈或组件的实例默认为当前页面栈实例
*/
const getCtx = (selector, ctx = getCurrentPages()[getCurrentPages().length - 1]) => {
const componentCtx = ctx.selectComponent(selector)
if (!componentCtx) {
throw new Error('无法找到对应的组件,请按文档说明使用组件')
}
return componentCtx
}
const $wuxBackdrop = (selector = '#wux-backdrop', ctx) => getCtx(selector, ctx)
const $wuxDialog = (selector = '#wux-dialog', ctx) => getCtx(selector, ctx)
export {
$wuxBackdrop,
$wuxDialog
}

287
components/input-number/index.js

@ -0,0 +1,287 @@
import baseComponent from '../helpers/baseComponent'
import classNames from '../helpers/classNames'
import eventsMixin from '../helpers/eventsMixin'
import NP from './utils'
const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || Math.pow(2, 53) - 1
const toNumberWhenUserInput = (num) => {
if (/\.\d*0$/.test(num) || num.length > 16) {
return num
}
if (isNaN(num)) {
return num
}
return Number(num)
}
const getValidValue = (value, min, max) => {
let val = parseFloat(value)
if (isNaN(val)) {
return value
}
if (val < min) {
val = min
}
if (val > max) {
val = max
}
return val
}
const defaultEvents = {
onChange() {},
onFocus() {},
onBlur() {},
}
baseComponent({
behaviors: [eventsMixin({ defaultEvents })],
externalClasses: ['wux-sub-class', 'wux-input-class', 'wux-add-class'],
relations: {
'../field/index': {
type: 'ancestor',
},
},
properties: {
prefixCls: {
type: String,
value: 'wux-input-number',
},
shape: {
type: String,
value: 'square',
},
min: {
type: Number,
value: -MAX_SAFE_INTEGER,
},
max: {
type: Number,
value: MAX_SAFE_INTEGER,
},
step: {
type: Number,
value: 1,
},
defaultValue: {
type: Number,
value: 0,
},
value: {
type: Number,
value: 0,
},
disabled: {
type: Boolean,
value: true,
},
longpress: {
type: Boolean,
value: false,
},
color: {
type: String,
value: 'balanced',
},
controlled: {
type: Boolean,
value: false,
},
},
data: {
inputValue: 0,
disabledMin: false,
disabledMax: false,
},
computed: {
classes: ['prefixCls, shape, color, disabledMin, disabledMax', function(prefixCls, shape, color, disabledMin, disabledMax) {
const wrap = classNames(prefixCls, {
[`${prefixCls}--${shape}`]: shape,
})
const sub = classNames(`${prefixCls}__selector`, {
[`${prefixCls}__selector--sub`]: true,
[`${prefixCls}__selector--${color}`]: color,
[`${prefixCls}__selector--disabled`]: disabledMin,
})
const add = classNames(`${prefixCls}__selector`, {
[`${prefixCls}__selector--add`]: true,
[`${prefixCls}__selector--${color}`]: color,
[`${prefixCls}__selector--disabled`]: disabledMax,
})
const icon = `${prefixCls}__icon`
const input = `${prefixCls}__input`
return {
wrap,
sub,
add,
icon,
input,
}
}],
},
observers: {
value(newVal) {
if (this.data.controlled) {
this.setValue(newVal, false)
}
},
'inputValue, min, max'(inputValue, min, max) {
const disabledMin = inputValue <= min
const disabledMax = inputValue >= max
this.setData({
disabledMin,
disabledMax,
})
},
},
methods: {
/**
* 更新值
*/
updated(inputValue) {
if (this.hasFieldDecorator) return
if (this.data.inputValue !== inputValue) {
this.setData({ inputValue })
}
},
/**
* 设置值
*/
setValue(value, runCallbacks = true) {
const { min, max } = this.data
const inputValue = NP.strip(getValidValue(value, min, max))
this.updated(inputValue)
if (runCallbacks) {
this.triggerEvent('change', { value: inputValue })
}
},
/**
* 数字计算函数
*/
calculation(type, isLoop) {
const {
disabledMax,
disabledMin,
inputValue,
step,
longpress,
controlled,
} = this.data
// add
if (type === 'add') {
if (disabledMax) return
this.setValue(NP.plus(inputValue, step))
}
// sub
if (type === 'sub') {
if (disabledMin) return
this.setValue(NP.minus(inputValue, step))
}
// longpress
if (longpress && isLoop) {
this.timeout = setTimeout(() => this.calculation(type, isLoop), 100)
}
},
/**
* 当键盘输入时触发 input 事件
*/
onInput(e) {
this.clearInputTimer()
this.inputTime = setTimeout(() => {
const value = toNumberWhenUserInput(e.detail.value)
this.setValue(value)
}, 300)
},
/**
* 输入框聚焦时触发
*/
onFocus(e) {
this.triggerEvent('focus', e.detail)
},
/**
* 输入框失去焦点时触发
*/
onBlur(e) {
// always set input value same as value
this.setData({
inputValue: this.data.inputValue,
})
this.triggerEvent('blur', e.detail)
},
/**
* 手指触摸后超过350ms再离开
*/
onLongpress(e) {
const { type } = e.currentTarget.dataset
const { longpress } = this.data
if (longpress) {
this.calculation(type, true)
}
},
/**
* 手指触摸后马上离开
*/
onTap(e) {
const { type } = e.currentTarget.dataset
const { longpress } = this.data
if (!longpress || longpress && !this.timeout) {
this.calculation(type, false)
}
},
/**
* 手指触摸动作结束
*/
onTouchEnd() {
this.clearTimer()
},
/**
* 手指触摸动作被打断如来电提醒弹窗
*/
onTouchCancel() {
this.clearTimer()
},
/**
* 清除长按的定时器
*/
clearTimer() {
if (this.timeout) {
clearTimeout(this.timeout)
this.timeout = null
}
},
/**
* 清除输入框的定时器
*/
clearInputTimer() {
if (this.inputTime) {
clearTimeout(this.inputTime)
this.inputTime = null
}
},
},
attached() {
const { defaultValue, value, controlled } = this.data
const inputValue = controlled ? value : defaultValue
this.setValue(inputValue, false)
},
detached() {
this.clearTimer()
this.clearInputTimer()
},
})

6
components/input-number/index.json

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

9
components/input-number/index.wxml

@ -0,0 +1,9 @@
<view class="wux-class {{ classes.wrap }}">
<view bindlongpress="onLongpress" bindtap="onTap" bindtouchend="onTouchEnd" touchcancel="onTouchCancel" data-type="sub" class="wux-sub-class {{ classes.sub }}">
<wux-icon wux-class="{{ classes.icon }}" type="ios-remove"></wux-icon>
</view>
<input bindinput="onInput" bindfocus="onFocus" bindblur="onBlur" value="{{ inputValue }}" disabled="{{ disabled }}" type="number" class="wux-input-class {{ classes.input }}" />
<view bindlongpress="onLongpress" bindtap="onTap" bindtouchend="onTouchEnd" touchcancel="onTouchCancel" data-type="add" class="wux-add-class {{ classes.add }}">
<wux-icon wux-class="{{ classes.icon }}" type="ios-add"></wux-icon>
</view>
</view>

118
components/input-number/index.wxss

@ -0,0 +1,118 @@
.wux-input-number {
position: relative;
display: -ms-flexbox;
display: flex
}
.wux-input-number__input {
width: 96rpx;
height: 52rpx;
font-size: 32rpx;
line-height: 52rpx;
color: #666;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
border: 2rpx solid #ececec;
padding: 6rpx 0;
text-align: center;
min-height: inherit;
box-sizing: border-box
}
.wux-input-number__selector {
width: 68rpx;
height: 52rpx;
font-size: 48rpx;
line-height: 52rpx;
color: #33cd5f;
border: 2rpx solid #ececec;
box-sizing: border-box;
display: -ms-flexbox;
display: flex;
-ms-flex-align: center;
align-items: center;
-ms-flex-pack: center;
justify-content: center
}
.wux-input-number__selector--disabled {
color: #ccc!important
}
.wux-input-number__selector--sub {
border-right: none;
padding: 6rpx 20rpx;
border-radius: 4rpx 0 0 4rpx
}
.wux-input-number__selector--add {
border-left: none;
padding: 6rpx 16rpx;
border-radius: 0 4rpx 4rpx 0
}
.wux-input-number__icon {
font-size: inherit!important;
vertical-align: middle;
line-height: inherit
}
.wux-input-number--circle .wux-input-number__input {
border-color: transparent
}
.wux-input-number--circle .wux-input-number__selector {
width: 52rpx;
border-radius: 50%;
border: 2rpx solid #33cd5f
}
.wux-input-number--circle .wux-input-number__selector--disabled {
border-color: #ccc!important
}
.wux-input-number .wux-input-number__selector--light {
color: #ddd
}
.wux-input-number--circle .wux-input-number__selector--light {
border-color: #ddd
}
.wux-input-number .wux-input-number__selector--stable {
color: #b2b2b2
}
.wux-input-number--circle .wux-input-number__selector--stable {
border-color: #b2b2b2
}
.wux-input-number .wux-input-number__selector--positive {
color: #387ef5
}
.wux-input-number--circle .wux-input-number__selector--positive {
border-color: #387ef5
}
.wux-input-number .wux-input-number__selector--calm {
color: #11c1f3
}
.wux-input-number--circle .wux-input-number__selector--calm {
border-color: #11c1f3
}
.wux-input-number .wux-input-number__selector--assertive {
color: #ef473a
}
.wux-input-number--circle .wux-input-number__selector--assertive {
border-color: #ef473a
}
.wux-input-number .wux-input-number__selector--balanced {
color: #33cd5f
}
.wux-input-number--circle .wux-input-number__selector--balanced {
border-color: #33cd5f
}
.wux-input-number .wux-input-number__selector--energized {
color: #ffc900
}
.wux-input-number--circle .wux-input-number__selector--energized {
border-color: #ffc900
}
.wux-input-number .wux-input-number__selector--royal {
color: #886aea
}
.wux-input-number--circle .wux-input-number__selector--royal {
border-color: #886aea
}
.wux-input-number .wux-input-number__selector--dark {
color: #444
}
.wux-input-number--circle .wux-input-number__selector--dark {
border-color: #444
}

135
components/input-number/utils.js

@ -0,0 +1,135 @@
/**
* https://github.com/nefe/number-precision
*/
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
/**
* @desc 解决浮动运算问题避免小数点后产生多位数和计算精度损失
* 问题示例2.3 + 2.4 = 4.6999999999999991.0 - 0.9 = 0.09999999999999998
*/
/**
* 把错误的数据转正
* strip(0.09999999999999998)=0.1
*/
function strip(num, precision) {
if (precision === void 0) { precision = 12; }
return +parseFloat(num.toPrecision(precision));
}
/**
* Return digits length of a number
* @param {*number} num Input number
*/
function digitLength(num) {
// Get digit length of e
var eSplit = num.toString().split(/[eE]/);
var len = (eSplit[0].split('.')[1] || '').length - (+(eSplit[1] || 0));
return len > 0 ? len : 0;
}
/**
* 把小数转成整数支持科学计数法如果是小数则放大成整数
* @param {*number} num 输入数
*/
function float2Fixed(num) {
if (num.toString().indexOf('e') === -1) {
return Number(num.toString().replace('.', ''));
}
var dLen = digitLength(num);
return dLen > 0 ? strip(num * Math.pow(10, dLen)) : num;
}
/**
* 检测数字是否越界如果越界给出提示
* @param {*number} num 输入数
*/
function checkBoundary(num) {
if (_boundaryCheckingState) {
if (num > Number.MAX_SAFE_INTEGER || num < Number.MIN_SAFE_INTEGER) {
console.warn(num + " is beyond boundary when transfer to integer, the results may not be accurate");
}
}
}
/**
* 精确乘法
*/
function times(num1, num2) {
var others = [];
for (var _i = 2; _i < arguments.length; _i++) {
others[_i - 2] = arguments[_i];
}
if (others.length > 0) {
return times.apply(void 0, [times(num1, num2), others[0]].concat(others.slice(1)));
}
var num1Changed = float2Fixed(num1);
var num2Changed = float2Fixed(num2);
var baseNum = digitLength(num1) + digitLength(num2);
var leftValue = num1Changed * num2Changed;
checkBoundary(leftValue);
return leftValue / Math.pow(10, baseNum);
}
/**
* 精确加法
*/
function plus(num1, num2) {
var others = [];
for (var _i = 2; _i < arguments.length; _i++) {
others[_i - 2] = arguments[_i];
}
if (others.length > 0) {
return plus.apply(void 0, [plus(num1, num2), others[0]].concat(others.slice(1)));
}
var baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
return (times(num1, baseNum) + times(num2, baseNum)) / baseNum;
}
/**
* 精确减法
*/
function minus(num1, num2) {
var others = [];
for (var _i = 2; _i < arguments.length; _i++) {
others[_i - 2] = arguments[_i];
}
if (others.length > 0) {
return minus.apply(void 0, [minus(num1, num2), others[0]].concat(others.slice(1)));
}
var baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
return (times(num1, baseNum) - times(num2, baseNum)) / baseNum;
}
/**
* 精确除法
*/
function divide(num1, num2) {
var others = [];
for (var _i = 2; _i < arguments.length; _i++) {
others[_i - 2] = arguments[_i];
}
if (others.length > 0) {
return divide.apply(void 0, [divide(num1, num2), others[0]].concat(others.slice(1)));
}
var num1Changed = float2Fixed(num1);
var num2Changed = float2Fixed(num2);
checkBoundary(num1Changed);
checkBoundary(num2Changed);
return times((num1Changed / num2Changed), Math.pow(10, digitLength(num2) - digitLength(num1)));
}
/**
* 四舍五入
*/
function round(num, ratio) {
var base = Math.pow(10, ratio);
return divide(Math.round(times(num, base)), base);
}
var _boundaryCheckingState = true;
/**
* 是否进行边界检查默认开启
* @param flag 标记开关true 为开启false 为关闭默认为 true
*/
function enableBoundaryChecking(flag) {
if (flag === void 0) { flag = true; }
_boundaryCheckingState = flag;
}
var index = { strip: strip, plus: plus, minus: minus, times: times, divide: divide, round: round, digitLength: digitLength, float2Fixed: float2Fixed, enableBoundaryChecking: enableBoundaryChecking };
export default index;

78
components/password-box/index.js

@ -0,0 +1,78 @@
// components/password-box.js
Component({
/**
* 组件的属性列表
*/
properties: {
// 输入框的数量
inputLength: {
type: Number,
value: 6
},
// 单个输入框的宽度
inputWidth: {
type: String,
value: '100rpx'
},
inputHeight: {
type: String,
value: '100rpx'
},
// 是否显示输入的值,默认隐藏
showValue: {
type: Boolean,
value: false
}
},
/**
* 组件的初始数据
*/
data: {
// input是否获取焦点
inputFocus: false,
// 初始input值为空
currentValue: ''
},
/**
* 组件的方法列表
*/
methods: {
// 设置当前的值
_setCurrentValue(e) {
// 在此处判断满6(inputLength)位,把值返回给上级父组件或页面
let currentValue = e.detail.value
// 改变时,派发一个事件,如果父组件或页面中需要实时获取改变后的值,可以监听这个事件。
this.triggerEvent('change', e.detail.value)
this.setData({
currentValue
})
if (currentValue.length >= this.data.inputLength) {
this._complate()
}
},
// 点击伪装的input时,让隐藏的input获得焦点
_focusInput() {
this.setData({
inputFocus: true
})
},
_complate() {
this.triggerEvent('inputComplate', this.data.currentValue)
},
// 提供给外部调用的方法,显示/隐藏密码。接收一个参数,可以显性修改展示的状态。
toggleValue(state) {
this.setData({
showValue: state != undefined ? state : !this.data.showValue
})
},
// 清除input当前的值
clearCurrentValue() {
this.setData({
currentValue: ''
})
}
}
})

4
components/password-box/index.json

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

17
components/password-box/index.wxml

@ -0,0 +1,17 @@
<!--components/password-box.wxml-->
<view class="password-box">
<view class='password-wrapper'>
<!-- 伪装的input -->
<block wx:for="{{inputLength}}" wx:key="item">
<!-- 宽高可以由外部指定 -->
<view class="{{item===(inputLength-1)?'password-item-last':'password-item'}}" style="width: {{inputWidth}}; height: {{inputHeight}}" catchtap='_focusInput'>
<!-- 隐藏密码时显示的小圆点【自定义】 -->
<view wx:if="{{!showValue && currentValue.length>=index+1}}" class="hidden"></view>
<!-- 显示密码时显示对应的值 -->
<view wx:if="{{showValue}}" class="show">{{currentValue.length>=index+1?currentValue[index]:''}}</view>
</view>
</block>
</view>
<!-- 隐藏的输入框 -->
<input type="number" password="{{true}}" value="{{currentValue}}" class='hidden-input' maxlength="{{inputLength}}" focus="{{inputFocus}}" bindinput="_setCurrentValue"></input>
</view>

73
components/password-box/index.wxss

@ -0,0 +1,73 @@
/* components/password-box.wxss */
.password-box .password-wrapper {
display: flex;
justify-content: center;
align-items: center;
}
.password-box .password-item {
position: relative;
display: flex;
justify-content: center;
align-items: center;
}
.password-box .password-item::after {
display: block;
content: '';
position: absolute;
top: 0;
left: 0;
border-left: 2px solid #999;
border-top: 2px solid #999;
border-bottom: 2px solid #999;
border-spacing: 0;
box-sizing: border-box;
width: 200%;
height: 200%;
border-radius: 0rpx;
transform: scale(0.5);
transform-origin: left top;
}
.password-box .password-item-last {
position: relative;
display: flex;
justify-content: center;
align-items: center;
}
.password-box .password-item-last::after {
display: block;
content: '';
position: absolute;
top: 0;
left: 0;
border-left: 2px solid #999;
border-top: 2px solid #999;
border-right: 2px solid #999;
border-bottom: 2px solid #999;
border-spacing: 0;
box-sizing: border-box;
width: 200%;
height: 200%;
border-radius: 0rpx;
transform: scale(0.5);
transform-origin: left top;
}
.password-box .password-item + .password-item {
margin-left: -1rpx;
}
.password-box .password-wrapper .hidden {
width: 36rpx;
height: 36rpx;
border-radius: 50%;
background: #999;
}
.password-box .password-wrapper .show {
color: #333333;
font-size: 48rpx;
}
.password-box .hidden-input {
width: 0;
height: 0;
min-height: 0;
}

193
components/popup/index.js

@ -0,0 +1,193 @@
import baseComponent from '../helpers/baseComponent'
import classNames from '../helpers/classNames'
import styleToCssString from '../helpers/styleToCssString'
import { $wuxBackdrop } from '../../utils/index'
baseComponent({
useSafeArea: true,
externalClasses: ['wux-content-class', 'wux-header-class', 'wux-body-class', 'wux-footer-class', 'wux-close-class'],
properties: {
prefixCls: {
type: String,
value: 'wux-popup',
},
animationPrefixCls: {
type: String,
value: 'wux-animate',
},
title: {
type: String,
value: '',
},
content: {
type: String,
value: '',
},
extra: {
type: String,
value: '',
},
position: {
type: String,
value: 'center',
observer: 'getTransitionName',
},
wrapStyle: {
type: [String, Object],
value: '',
observer(newVal) {
this.setData({
extStyle: styleToCssString(newVal),
})
},
},
closable: {
type: Boolean,
value: false,
},
mask: {
type: Boolean,
value: true,
},
maskClosable: {
type: Boolean,
value: true,
},
visible: {
type: Boolean,
value: false,
observer: 'setPopupVisible',
},
zIndex: {
type: Number,
value: 1000,
},
hasHeader: {
type: Boolean,
value: true,
},
hasFooter: {
type: Boolean,
value: true,
},
mountOnEnter: {
type: Boolean,
value: true,
},
unmountOnExit: {
type: Boolean,
value: true,
},
},
data: {
transitionName: '',
popupVisible: false,
extStyle: '',
},
computed: {
classes: ['prefixCls, position, safeAreaConfig, isIPhoneX', function(prefixCls, position, safeAreaConfig, isIPhoneX) {
const wrap = classNames(`${prefixCls}-position`, {
[`${prefixCls}-position--${position}`]: position,
[`${prefixCls}-position--is-iphonex`]: safeAreaConfig.bottom && isIPhoneX,
})
const content = `${prefixCls}__content`
const hd = `${prefixCls}__hd`
const title = `${prefixCls}__title`
const bd = `${prefixCls}__bd`
const ft = `${prefixCls}__ft`
const extra = `${prefixCls}__extra`
const close = `${prefixCls}__close`
const x = `${prefixCls}__close-x`
return {
wrap,
content,
hd,
title,
bd,
ft,
extra,
close,
x,
}
}],
},
methods: {
/**
* 点击关闭按钮事件
*/
close() {
this.triggerEvent('close')
},
/**
* 点击蒙层事件
*/
onMaskClick() {
if (this.data.maskClosable) {
this.close()
}
},
/**
* 组件关闭后的回调函数
*/
onExited() {
this.triggerEvent('closed')
},
/**
* 获取过渡的类名
*/
getTransitionName(value = this.data.position) {
const { animationPrefixCls } = this.data
let transitionName = ''
switch (value) {
case 'top':
transitionName = `${animationPrefixCls}--slideInDown`
break
case 'right':
transitionName = `${animationPrefixCls}--slideInRight`
break
case 'bottom':
transitionName = `${animationPrefixCls}--slideInUp`
break
case 'left':
transitionName = `${animationPrefixCls}--slideInLeft`
break
default:
transitionName = `${animationPrefixCls}--fadeIn`
break
}
this.setData({ transitionName })
},
/**
* 设置 popup 组件的显示隐藏
*/
setPopupVisible(popupVisible) {
if (this.data.popupVisible !== popupVisible) {
this.setData({ popupVisible })
this.setBackdropVisible(popupVisible)
if(popupVisible){
this.triggerEvent('show')
}
}
},
/**
* 设置 backdrop 组件的显示隐藏
*/
setBackdropVisible(visible) {
if (this.data.mask && this.$wuxBackdrop) {
this.$wuxBackdrop[visible ? 'retain' : 'release']()
}
},
},
created() {
if (this.data.mask) {
this.$wuxBackdrop = $wuxBackdrop('#wux-backdrop', this)
}
},
attached() {
this.setPopupVisible(this.data.visible)
this.getTransitionName()
},
})

7
components/popup/index.json

@ -0,0 +1,7 @@
{
"component": true,
"usingComponents": {
"wux-animation-group": "../animation-group/index",
"wux-backdrop": "../backdrop/index"
}
}

26
components/popup/index.wxml

@ -0,0 +1,26 @@
<wux-backdrop id="wux-backdrop" wx:if="{{ mask }}" bind:click="onMaskClick" zIndex="{{ zIndex }}" />
<view class="wux-class {{ classes.wrap }}" style="{{ extStyle }}">
<wux-animation-group wux-class="{{ prefixCls }}" in="{{ popupVisible }}" classNames="{{ transitionName }}" bind:exited="onExited" wrapStyle="{{ { zIndex } }}" mountOnEnter="{{ mountOnEnter }}" unmountOnExit="{{ unmountOnExit }}">
<view class="wux-content-class {{ classes.content }}">
<view class="wux-header-class {{ classes.hd }}" wx:if="{{ hasHeader }}">
<view class="{{ classes.title }}" wx:if="{{ title }}">{{ title }}</view>
<block wx:else>
<slot name="header"></slot>
</block>
</view>
<view class="wux-body-class {{ classes.bd }}">
<view wx:if="{{ content }}">{{ content }}</view>
<slot></slot>
</view>
<view class="wux-footer-class {{ classes.ft }}" wx:if="{{ hasFooter }}">
<view class="{{ classes.extra }}" wx:if="{{ extra }}">{{ extra }}</view>
<block wx:else>
<slot name="footer"></slot>
</block>
</view>
<view class="wux-close-class {{ classes.close }}" wx:if="{{ closable }}" bindtap="close">
<text class="{{ classes.x }}"></text>
</view>
</view>
</wux-animation-group>
</view>

114
components/popup/index.wxss

@ -0,0 +1,114 @@
.wux-popup {
position: fixed;
z-index: 1000;
width: 80%;
max-width: 600rpx
}
.wux-popup-position.wux-popup-position--center .wux-popup {
top: 50%;
left: 50%;
transform: translate(-50%,-50%)
}
.wux-popup-position.wux-popup-position--center .wux-popup__content {
border-radius: 6rpx
}
.wux-popup-position.wux-popup-position--center .wux-popup__hd {
padding: 1.3em 1.6em .5em
}
.wux-popup-position.wux-popup-position--center .wux-popup__bd {
padding: 0 1.6em .8em
}
.wux-popup-position.wux-popup-position--center .wux-popup__ft:after {
content: " ";
position: absolute;
left: 0;
top: 0;
right: 0;
height: 2rpx;
border-top: 2rpx solid #d5d5d6;
color: #d5d5d6;
transform-origin: 0 0;
transform: scaleY(.5)
}
.wux-popup-position.wux-popup-position--top .wux-popup {
position: fixed;
left: 0;
top: 0;
width: 100%;
max-width: 100%
}
.wux-popup-position.wux-popup-position--right .wux-popup {
position: fixed;
top: 0;
right: 0;
width: 80%;
max-width: 100%;
height: 100%;
max-height: 100%
}
.wux-popup-position.wux-popup-position--bottom .wux-popup {
position: fixed;
left: 0;
bottom: 0;
width: 100%;
max-width: 100%
}
.wux-popup-position.wux-popup-position--left .wux-popup {
position: fixed;
left: 0;
top: 0;
width: 80%;
max-width: 100%;
height: 100%;
max-height: 100%
}
.wux-popup-position.wux-popup-position--is-iphonex .wux-popup__content {
padding-bottom: 68rpx
}
.wux-popup__content {
position: relative;
background-color: #fff;
border: 0;
background-clip: padding-box;
height: 100%;
text-align: center;
overflow: hidden
}
.wux-popup__title {
font-weight: 400;
font-size: 36rpx
}
.wux-popup__bd {
min-height: 80rpx;
font-size: 30rpx;
line-height: 1.3;
word-wrap: break-word;
word-break: break-all;
color: #999
}
.wux-popup__ft {
position: relative;
line-height: 96rpx;
font-size: 36rpx;
display: -ms-flexbox;
display: flex
}
.wux-popup__close {
border: 0;
padding: 6rpx;
background-color: transparent;
outline: 0;
position: absolute;
top: 12rpx;
right: 12rpx;
height: 42rpx;
width: 42rpx
}
.wux-popup__close-x {
display: inline-block;
width: 30rpx;
height: 30rpx;
background-repeat: no-repeat;
background-size: cover;
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg width='30' height='30' viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23888' fill-rule='evenodd'%3E%3Cpath d='M1.414 0l28.284 28.284-1.414 1.414L0 1.414z'/%3E%3Cpath d='M28.284 0L0 28.284l1.414 1.414L29.698 1.414z'/%3E%3C/g%3E%3C/svg%3E")
}

56
components/refresh-view/index.js

@ -0,0 +1,56 @@
// 使用的时候,用本组件包裹可以触发下拉刷新的内容。enablePullDownRefresh需要设置为false。
Component({
properties: {
refreshed: { // 必选,通知本组件收起
type: Boolean,
value: false,
},
refreshing: { // 可选,通知本组件直接进入refreshing状态
type: Boolean,
value: false,
},
distMax: { // 可选,可以下拉的最大高度,回弹的高度为最大高度的75%
type: Number,
value: 45,
},
color: { // 可选,圆弧颜色
type: String,
value: "#000",
},
backgroundColor: { // 可选,背景颜色
type: String,
value: "#fff",
},
type: {
type: Number,
value: 0
}
},
data: {
reachTop: false,
},
methods: {
initObserver() {
this.observer = this.createIntersectionObserver()
this.observer.relativeToViewport().observe(".intersection-dot", (res) => {
if (res.intersectionRatio > 0) {
this.setData({ reachTop: true, })
} else {
this.setData({ reachTop: false,})
}
})
},
clearObserver() {
if (this.observer) {
this.observer.disconnect()
this.observer = null
}
},
},
ready() {
this.initObserver()
},
detached() {
this.clearObserver()
},
})

4
components/refresh-view/index.json

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

9
components/refresh-view/index.wxml

@ -0,0 +1,9 @@
<wxs module="refresher" src="./index.wxs"></wxs>
<view class="refresh-wrap" style="{{backgroundColor ? 'background-color:' + backgroundColor + ';' : ''}}">
<view class="refresh" style="{{color ? 'border-color:' + color + ';' : ''}}"></view>
</view>
<view class="wrap" change:refreshed="{{refresher.onRefreshed}}" refreshed="{{refreshed}}" change:refreshing="{{refresher.onRefreshing}}" refreshing="{{refreshing}}" data-dist-max="{{distMax}}" data-type="{{type}}" data-reach-top="{{reachTop}}" bind:touchstart="{{refresher.touchStart}}"
bind:touchmove="{{refresher.touchMove}}" bind:touchend="{{refresher.touchEnd}}">
<view class="intersection-dot"></view>
<slot></slot>
</view>

158
components/refresh-view/index.wxs

@ -0,0 +1,158 @@
// 文档:https://developers.weixin.qq.com/miniprogram/dev/framework/view/interactive-animation.html
/* eslint-disable */
function calcResistance(distExtra, distMax) {
return Math.min(1, distExtra / distMax / 1.2) * Math.min(distMax, distExtra)
}
function touchStart(e, ins) {
var dataset = e.instance.getDataset()
var state = e.instance.getState()
state.distMax = dataset.distMax
state.type = dataset.type
state.distThreshold = state.distMax * 0.75
state.reachTop = dataset.reachTop
state.status = state.status || "pending" // pending、pulling、releasing、refreshing
if (state.status === "pending" && state.reachTop) {
state.startPulling = true
state.pullStartX = e.touches[0].clientX
state.pullStartY = e.touches[0].clientY
state.distance = 0
state.component = state.component || ins.selectComponent(".refresh-wrap")
state.component.removeClass("transition")
state.component.removeClass("animation")
state.component.removeClass("fadeout")
state.component.setStyle({
top: (state.distance * 2 - 20) + "rpx",
opacity: 0,
transform: "rotate(0)",
"-webkit-transform": "rotate(0)"
})
}
}
function touchMove(e, ins) {
var state = e.instance.getState()
if (!state.startPulling || state.status === "refreshing") {
return true
}
state.pullMoveX = e.touches[0].clientX
state.pullMoveY = e.touches[0].clientY
if (state.status === "pending") {
state.status = "pulling"
}
var distExtraX = state.pullMoveX - state.pullStartX
var distExtraY = state.pullMoveY - state.pullStartY
if (distExtraY > 0 && Math.abs(distExtraY) >= Math.abs(distExtraX)) {
state.distance = calcResistance(distExtraY, state.distMax)
state.component.setStyle({
top: setop(state.distance, state.type),
opacity: Math.min(1, state.distance / state.distThreshold),
transform: "rotate(" + (245 * state.distance / state.distMax) + "deg)",
"-webkit-transform": "rotate(" + (245 * state.distance / state.distMax) + "deg)"
})
if (state.status === "pulling" && state.distance > state.distThreshold) {
state.status = "releasing"
}
if (state.status === "releasing" && state.distance < state.distThreshold) {
state.status = "pulling"
}
return false
}
return true
}
function touchEnd(e, ins) {
var state = e.instance.getState()
if (!state.startPulling || state.status === "refreshing") {
return
}
state.startPulling = false
if (state.status === "releasing" && state.distance > state.distThreshold) {
state.status = "refreshing"
state.distance = state.distThreshold
state.component.addClass("animation")
state.component.setStyle({
top: setop(state.distance, state.type),
opacity: Math.min(1, state.distance / state.distThreshold),
})
ins.triggerEvent("refresh")
} else {
reset(state)
}
}
function reset(state) {
state.status = "pending"
state.startPulling = false
state.distance = 0
state.component.addClass("transition")
state.component.setStyle({
top: setop(state.distance, state.type),
opacity: 0,
transform: "rotate(0)",
"-webkit-transform": "rotate(0)"
})
}
function onRefreshed(newValue, oldValue, ins, itemIns) {
if (newValue) {
var state = itemIns.getState()
state.status = "pending"
state.startPulling = false
var component = state.component || ins.selectComponent(".refresh-wrap")
component.removeClass("animation")
component.addClass("fadeout")
component.setStyle({
top: (state.distance * 2 - (state.type? 12 : 30)) + "rpx",
opacity: 0,
transform: "scale(0)",
"-webkit-transform": "rotate(0)"
})
}
}
function setop(distance, type){
var top = (distance * 2 + (type == 0 ? 120 : -30)) + "rpx"
return top
}
function onRefreshing(newValue, oldValue, ins, itemIns) {
if (newValue) {
var dataset = itemIns.getDataset()
var state = itemIns.getState()
state.distMax = state.distMax || dataset.distMax
state.distThreshold = state.distThreshold || state.distMax * 0.75
state.status = "refreshing"
state.distance = state.distThreshold
state.startPulling = false
state.component = state.component || ins.selectComponent(".refresh-wrap")
state.component.removeClass("transition")
state.component.removeClass("fadeout")
state.component.addClass("animation")
state.component.setStyle({
top: setop(state.distance, state.type),
opacity: 1,
transition: "none",
})
// ins.triggerEvent("refresh")
}
}
module.exports = {
touchStart: touchStart,
touchMove: touchMove,
touchEnd: touchEnd,
onRefreshed: onRefreshed,
onRefreshing: onRefreshing,
}
/* eslint-enable */

68
components/refresh-view/index.wxss

@ -0,0 +1,68 @@
@keyframes rolling {
0% {
transform: rotate(135deg);
}
100% {
transform: rotate(495deg);
}
}
@keyframes fadeout {
0% {
opacity: 1;
transform: rotate(135deg) scale(1);
}
100% {
opacity: 0;
transform: rotate(135deg) scale(0);
}
}
.refresh-wrap {
position: fixed;
width: 42px;
height: 42px;
left: 50%;
margin-left: -21px;
top: 50px;
z-index: 88;
background-color: #fff;
border-radius: 50%;
box-shadow: 0 0 6px 1px #ccc;
opacity: 0;
display: flex;
align-items: center;
justify-content: center;
}
.refresh-wrap.transition {
transition: top 0.3s ease-in-out, opacity 0.3s ease-in-out, transform 0.3s ease-in-out;
}
.refresh-wrap.animation {
transition: top 0.3s ease-in-out, opacity 0.3s ease-in-out;
animation: rolling 0.6s linear infinite;
}
.refresh-wrap.fadeout {
animation: fadeout 0.3s ease-in-out;
}
.refresh-wrap .refresh {
box-sizing: border-box;
width: 24px;
height: 24px;
border-radius: 50%;
border: 3px solid #000;
border-top-color: transparent !important;
}
.refresh-wrap.fadeout .refresh {
opacity: 0;
}
.wrap {
width: 100%;
height: 100%;
position: relative;
}
.wrap .intersection-dot {
position: absolute;
width: 10px;
height: 10px;
left: 0;
top: 0;
visibility: hidden;
}

110
components/result/index.js

@ -0,0 +1,110 @@
import baseComponent from '../helpers/baseComponent'
import classNames from '../helpers/classNames'
const defaultIcon = {
type: 'success',
size: 93,
color: '#33cd5f',
}
const getIcon = (icon) => {
if (icon !== null && typeof icon === 'object') {
return Object.assign({}, defaultIcon, icon)
} else if (typeof icon === 'string') {
return Object.assign({}, defaultIcon, {
type: icon,
})
}
return defaultIcon
}
baseComponent({
properties: {
prefixCls: {
type: String,
value: 'wux-result',
},
icon: {
type: null,
value: defaultIcon,
observer(newVal) {
this.setData({
resultIcon: getIcon(newVal),
})
},
},
title: {
type: String,
value: '',
},
label: {
type: String,
value: '',
},
buttons: {
type: Array,
value: [],
},
extra: {
type: String,
value: '',
},
fixed: {
type: Boolean,
value: false,
},
},
data: {
resultIcon: null,
},
computed: {
classes: ['prefixCls, fixed', function(prefixCls, fixed) {
const wrap = classNames(prefixCls, {
[`${prefixCls}--fixed`]: fixed,
})
const hd = `${prefixCls}__hd`
const icon = `${prefixCls}__icon`
const bd = `${prefixCls}__bd`
const title = `${prefixCls}__title`
const desc = `${prefixCls}__desc`
const buttons = `${prefixCls}__buttons`
const ft = `${prefixCls}__ft`
return {
wrap,
hd,
icon,
bd,
title,
desc,
buttons,
ft,
}
}],
},
methods: {
onClick(e) {
this.triggerEvent('click', e.currentTarget.dataset)
},
bindgetuserinfo(e) {
this.triggerEvent('getuserinfo', {...e.detail, ...e.currentTarget.dataset })
},
bindcontact(e) {
this.triggerEvent('contact', {...e.detail, ...e.currentTarget.dataset })
},
bindgetphonenumber(e) {
this.triggerEvent('getphonenumber', {...e.detail, ...e.currentTarget.dataset })
},
bindopensetting(e) {
this.triggerEvent('opensetting', {...e.detail, ...e.currentTarget.dataset })
},
onError(e) {
this.triggerEvent('error', {...e.detail, ...e.currentTarget.dataset })
},
},
attached() {
this.setData({
resultIcon: getIcon(this.data.icon),
})
},
})

6
components/result/index.json

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

58
components/result/index.wxml

@ -0,0 +1,58 @@
<view class="wux-class {{ classes.wrap }}">
<view class="{{ classes.hd }}">
<view wx:if="{{ resultIcon }}" class="{{ classes.icon }}">
<icon type="{{ resultIcon.type }}" size="{{ resultIcon.size }}" color="{{ resultIcon.color }}" />
</view>
<block wx:else>
<slot name="header"></slot>
</block>
</view>
<view class="{{ classes.bd }}">
<view wx:if="{{ title }}" class="{{ classes.title }}">{{ title }}</view>
<view wx:if="{{ label }}" class="{{ classes.desc }}">{{ label }}</view>
<view wx:if="{{ buttons.length }}" class="{{ classes.buttons }}">
<block wx:for="{{ buttons }}" wx:for-item="button" wx:key="index">
<wux-button
type="{{ button.type }}"
clear="{{ button.clear }}"
block="{{ button.block }}"
full="{{ button.full }}"
outline="{{ button.outline }}"
size="{{ button.size }}"
disabled="{{ button.disabled }}"
loading="{{ button.loading }}"
form-type="{{ button.formType }}"
open-type="{{ button.openType }}"
hover-stop-propagation="{{ button.hoverStopPropagation }}"
hover-start-time="{{ button.hoverStartTime }}"
hover-stay-time="{{ button.hoverStayTime }}"
lang="{{ button.lang }}"
bind:getuserinfo="bindgetuserinfo"
session-from="{{ button.sessionFrom }}"
send-message-title="{{ button.sendMessageTitle }}"
send-message-path="{{ button.sendMessagePath }}"
send-message-img="{{ button.sendMessageImg }}"
show-message-card="{{ button.showMessageCard }}"
bind:contact="bindcontact"
bind:getphonenumber="bindgetphonenumber"
app-parameter="{{ button.appParameter }}"
binderror="onError"
bindopensetting="bindopensetting"
data-index="{{ index }}"
bind:click="onClick"
>
{{ button.text }}
</wux-button>
</block>
</view>
<slot></slot>
</view>
<view class="{{ classes.ft }}">
<block wx:if="{{ extra }}">
<text>{{ extra }}</text>
</block>
<block wx:else>
<slot name="footer"></slot>
</block>
</view>
</view>

36
components/result/index.wxss

@ -0,0 +1,36 @@
.wux-result {
padding-top: 0;
text-align: center
}
.wux-result__bd {
padding: 60rpx 40rpx
}
.wux-result__icon {
padding-top: 72rpx;
text-align: center
}
.wux-result__title {
margin-bottom: 10rpx;
font-weight: 400;
font-size: 40rpx
}
.wux-result__desc {
font-size: 28rpx;
color: grey
}
.wux-result__buttons {
margin-top: 60rpx
}
.wux-result__ft {
font-size: 28rpx;
color: grey
}
.wux-result--fixed .wux-result__ft {
position: fixed;
left: 0;
bottom: 0;
width: 100%;
padding: 30rpx;
text-align: center;
box-sizing: border-box
}

88
components/step/index.js

@ -0,0 +1,88 @@
import baseComponent from '../helpers/baseComponent'
import classNames from '../helpers/classNames'
const defaultStatus = ['wait', 'process', 'finish', 'error']
const defaultIcon = 'ios-checkmark'
baseComponent({
relations: {
'../steps/index': {
type: 'parent',
},
},
properties: {
prefixCls: {
type: String,
value: 'wux-step',
},
status: {
type: String,
value: '',
},
title: {
type: String,
value: '',
},
content: {
type: String,
value: '',
},
icon: {
type: String,
value: '',
},
},
data: {
width: '100%',
length: 1,
index: 0,
current: 0,
direction: 'horizontal',
},
computed: {
classes: ['prefixCls, direction', function(prefixCls, direction) {
const wrap = classNames(prefixCls, {
[`${prefixCls}--${direction}`]: direction,
})
const hd = `${prefixCls}__hd`
const icon = `${prefixCls}__icon`
const thumb = `${prefixCls}__thumb`
const bd = `${prefixCls}__bd`
const title = `${prefixCls}__title`
const content = `${prefixCls}__content`
const ft = `${prefixCls}__ft`
return {
wrap,
hd,
icon,
thumb,
bd,
title,
content,
ft,
}
}],
},
methods: {
updateCurrent(opts = {}) {
const width = opts.direction === 'horizontal' ? 100 / opts.length + '%' : '100%'
const index = defaultStatus.indexOf(this.data.status)
const hasIcon = opts.index < opts.current || this.data.icon
const thumb = this.data.icon || defaultIcon
const suffix = index !== -1 ? defaultStatus[index] : opts.index < opts.current ? 'finish' : opts.index === opts.current ? 'process' : ''
const className = `${this.data.prefixCls}--${suffix}`
const options = Object.assign({
width,
className,
hasIcon,
thumb,
}, opts)
this.setData(options)
},
},
attached() {
this.updateCurrent(this.data)
},
})

4
components/step/index.json

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

21
components/step/index.wxml

@ -0,0 +1,21 @@
<view class="wux-class {{ classes.wrap }} {{ className }}" style="width: {{ width }}">
<view class="{{ classes.hd }}">
<view class="{{ classes.icon }}" wx:if="{{ !hasIcon }}">{{ index + 1 }}</view>
<text wx:else class="cuIcon-roundcheck text-blue" style="font-size:54rpx"></text>
</view>
<view class="{{ classes.bd }}">
<view class="{{ classes.title }}" wx:if="{{ title }}">
{{ title }}
</view>
<view class="{{ classes.title }}" wx:else>
<slot name="title"></slot>
</view>
<view class="{{ classes.content }}" wx:if="{{ content }}">
{{ content }}
</view>
<view class="{{ classes.content }}" wx:else>
<slot name="content"></slot>
</view>
</view>
<view class="{{ classes.ft }}" wx:if="{{ index !== length - 1 }}"></view>
</view>

122
components/step/index.wxss

@ -0,0 +1,122 @@
.wux-step {
font-size: 0;
position: relative;
display: inline-block;
box-sizing: border-box;
padding: 0 10rpx;
vertical-align: top
}
.wux-step--vertical {
padding-bottom: 60rpx
}
.wux-step--vertical .wux-step__hd {
float: left
}
.wux-step--vertical .wux-step__bd {
overflow: hidden;
display: block;
margin-left: 80rpx;
margin-top: 0;
text-align: left;
clear: inherit
}
.wux-step--vertical .wux-step__ft {
position: absolute;
left: 40rpx;
top: 0;
height: 100%;
width: 2rpx;
padding: 60rpx 0 8rpx;
margin-left: 0
}
.wux-step--vertical .wux-step__ft:after {
width: 2rpx;
height: 100%
}
.wux-step__ft {
position: absolute;
left: 50%;
width: 100%;
top: 24rpx;
padding: 0 48rpx;
margin-left: 6rpx;
box-sizing: border-box
}
.wux-step__ft:after {
content: "";
display: inline-block;
background: #ddd;
height: 2rpx;
border-radius: 2rpx;
width: 100%;
transition: background .3s;
position: relative;
left: -4rpx
}
.wux-step__icon {
box-sizing: border-box;
font-size: 24rpx;
width: 48rpx;
height: 100%;
border-radius: 50%;
background: #fff;
position: relative;
z-index: 2;
margin: 0 auto;
border: #e9eaec solid 2rpx;
margin-left: 2px
}
.wux-step__thumb {
width: 100%;
height: 100%;
display: inline-block;
overflow: hidden
}
.wux-step--process .wux-step__icon {
border: #009ee0 solid 2rpx;
color: #fff;
background: #009ee0
}
.wux-step--wait .wux-step__icon {
border: #e9eaec solid 2rpx;
color: #e9eaec
}
.wux-step--wait .wux-step__ft:after {
background: #009ee0
}
.wux-step--finish .wux-step__icon {
border: #009ee0 solid 2rpx;
color: #009ee0
}
.wux-step--finish .wux-step__ft:after {
background: #009ee0
}
.wux-step--error .wux-step__icon {
border: #ef473a solid 2rpx;
color: #ef473a
}
.wux-step--error .wux-step__ft:after {
background: #ef473a
}
.wux-step__hd {
width: auto;
height: 48rpx;
line-height: 48rpx;
text-align: center;
box-sizing: border-box
}
.wux-step__bd {
margin-top: 20rpx;
text-align: center;
clear: both
}
.wux-step__title {
font-size: 32rpx;
font-weight: 700;
color: #000
}
.wux-step__content {
font-size: 24rpx;
margin-top: 6rpx;
color: #b2b2b2
}

49
components/steps/index.js

@ -0,0 +1,49 @@
import baseComponent from '../helpers/baseComponent'
import classNames from '../helpers/classNames'
baseComponent({
relations: {
'../step/index': {
type: 'child',
observer() {
this.debounce(this.updateCurrent)
},
},
},
properties: {
prefixCls: {
type: String,
value: 'wux-steps',
},
current: {
type: Number,
value: 0,
observer: 'updateCurrent',
},
// status: {
// type: String,
// value: '',
// },
direction: {
type: String,
value: 'horizontal',
},
},
methods: {
updateCurrent() {
const elements = this.getRelationNodes('../step/index')
const { current, direction } = this.data
if (elements.length > 0) {
elements.forEach((element, index) => {
element.updateCurrent({
length: elements.length,
index,
current,
direction,
})
})
}
}
}
})

3
components/steps/index.json

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

3
components/steps/index.wxml

@ -0,0 +1,3 @@
<view class="wux-class {{ prefixCls }}">
<slot></slot>
</view>

4
components/steps/index.wxss

@ -0,0 +1,4 @@
.wux-steps {
position: relative;
width: 100%
}

126
components/tab/index.js

@ -0,0 +1,126 @@
Component({
properties: {
// 数据源
tabData: {
type: Array,
value: [],
observer: "dataChange"
},
// 是否可以超出滚动
tabCur: {
type: Number,
value: 0,
observer: "tabCurChange"
},
// 是否可以超出滚动
scroll: {
type: Boolean,
value: false
},
// tab高度
size: {
type: Number,
value: 90,
observer: "sizeChange"
},
// 颜色
color: {
type: String,
value: ""
}
},
data: {
/* 未渲染数据 */
windowWidth: 0, // 屏幕宽度
tabItems: [], // 所有 tab 节点信息
/* 渲染数据 */
scrolling: true, // 控制 scroll-view 滚动以在异步加载数据的时候能正确获得 dom 信息
needTransition: false, // 下划线是否需要过渡动画
translateX: 0, // 下划 line 的左边距离
lineWidth: 0, // 下划 line 宽度
scrollLeft: 0, // scroll-view 左边滚动距离
},
methods: {
/**
* 切换菜单
*/
toggleTab(e) {
this.triggerEvent('change', {index: e.currentTarget.dataset.index});
this.scrollByIndex(e.currentTarget.dataset.index);
},
/**
* 滑动到指定位置
* @param tabCur: 当前激活的tabItem的索引
* @param needTransition: 下划线是否需要过渡动画, 第一次进来应设置为false
*/
scrollByIndex(tabCur, needTransition = true) {
let item = this.data.tabItems[tabCur];
if (!item) return;
let itemWidth = item.width || 0,
itemLeft = item.left || 0;
this.setData({needTransition: needTransition});
if (this.data.scroll) { // 超出滚动的情况
// 保持滚动后当前 item '尽可能' 在屏幕中间
let scrollLeft = itemLeft - (this.data.windowWidth - itemWidth) / 2;
this.setData({
tabCur: tabCur,
scrollLeft: scrollLeft,
translateX: itemLeft,
lineWidth: itemWidth
});
} else { // 不超出滚动的情况
this.setData({
tabCur: tabCur,
translateX: itemLeft,
lineWidth: itemWidth
});
}
},
/**
* 监听数据变化, 如果改变重新初始化参数
*/
dataChange(newVal, oldVal) {
this.setData({
scrolling: false
});
// 异步加载数据时候, 延迟执行 init 方法, 防止基础库 2.7.1 版本及以下无法正确获取 dom 信息
setTimeout(() => this.init(), 10);
},
/**
* 监听 tabCur 变化, 做对应处理
*/
tabCurChange(newVal, oldVal) {
this.scrollByIndex(newVal);
},
/**
* 监听 tab 高度变化, 最小值为80rpx
*/
sizeChange(newVal, oldVal) {
if (newVal <= 80) {
this.setData({size: 80});
}
},
/**
* 初始化函数
*/
init() {
const {windowWidth} = wx.getSystemInfoSync();
this.setData({windowWidth: windowWidth || 375});
this.createSelectorQuery().selectAll(".tabs__item-child").boundingClientRect((res) => {
this.setData({
scrolling: true,
tabItems: res
});
this.scrollByIndex(this.data.tabCur, false);
}).exec();
}
},
ready() {
this.init();
}
});

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

Loading…
Cancel
Save