diff --git a/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/common/class-names.js b/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/common/class-names.js new file mode 100644 index 0000000000000000000000000000000000000000..7a3a99f1c71c68f33e4bb495abf737e73b187d85 --- /dev/null +++ b/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/common/class-names.js @@ -0,0 +1,29 @@ +const hasOwn = {}.hasOwnProperty; + +export function classNames() { + const classes = []; + + for (let i = 0; i < arguments.length; i++) { + const arg = arguments[i]; + if (!arg) continue; + + const argType = typeof arg; + + if (argType === 'string' || argType === 'number') { + classes.push(arg); + } else if (Array.isArray(arg) && arg.length) { + const inner = classNames.apply(null, arg); + if (inner) { + classes.push(inner); + } + } else if (argType === 'object') { + for (const key in arg) { + if (hasOwn.call(arg, key) && arg[key]) { + classes.push(key); + } + } + } + } + + return classes.join(' '); +}; diff --git a/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/common/create.js b/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/common/create.js new file mode 100644 index 0000000000000000000000000000000000000000..6d76447b98365f3e24231a087b582475b75db2fc --- /dev/null +++ b/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/common/create.js @@ -0,0 +1,40 @@ +import { basic } from '../mixins/basic'; +import { observe } from '../mixins/observer/index'; + +export function create(sfc) { + // map props to properties + if (sfc.props) { + sfc.properties = sfc.props; + delete sfc.props; + } + + // map mixins to behaviors + if (sfc.mixins) { + sfc.behaviors = sfc.mixins; + delete sfc.mixins; + } + + // map classes to externalClasses + sfc.externalClasses = sfc.classes || []; + delete sfc.classes; + + // add default externalClasses + sfc.externalClasses.push('custom-class'); + + // add default behaviors + sfc.behaviors = sfc.behaviors || []; + sfc.behaviors.push(basic); + + // add default options + sfc.options = sfc.options || {}; + sfc.options.multipleSlots = true; + sfc.options.addGlobalClass = true; + + // map field to form-field behavior + if (sfc.field) { + sfc.behaviors.push('wx://form-field'); + } + + observe(sfc); + Component(sfc); +}; diff --git a/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/common/index.wxss b/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/common/index.wxss new file mode 100644 index 0000000000000000000000000000000000000000..c3925180745f28c13970f07950eb59901c586ecb --- /dev/null +++ b/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/common/index.wxss @@ -0,0 +1 @@ +.van-ellipsis{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.van-multi-ellipsis--l2{overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}.van-multi-ellipsis--l3{overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical}.van-clearfix::after{content:'';display:table;clear:both}.van-hairline,.van-hairline--bottom,.van-hairline--left,.van-hairline--right,.van-hairline--surround,.van-hairline--top,.van-hairline--top-bottom{position:relative}.van-hairline--bottom::after,.van-hairline--left::after,.van-hairline--right::after,.van-hairline--surround::after,.van-hairline--top-bottom::after,.van-hairline--top::after,.van-hairline::after{content:'';position:absolute;top:-50%;left:-50%;right:-50%;bottom:-50%;-webkit-transform:scale(.5);transform:scale(.5);pointer-events:none;box-sizing:border-box;border:0 solid #eee}.van-hairline--top::after{border-top-width:1px}.van-hairline--left::after{border-left-width:1px}.van-hairline--right::after{border-right-width:1px}.van-hairline--bottom::after{border-bottom-width:1px}.van-hairline--top-bottom::after{border-width:1px 0}.van-hairline--surround::after{border-width:1px} \ No newline at end of file diff --git a/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/common/style/clearfix.wxss b/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/common/style/clearfix.wxss new file mode 100644 index 0000000000000000000000000000000000000000..df65a0a492b47ba614a07432acedd7f0679be540 --- /dev/null +++ b/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/common/style/clearfix.wxss @@ -0,0 +1 @@ +.van-clearfix::after{content:'';display:table;clear:both} \ No newline at end of file diff --git a/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/common/style/ellipsis.wxss b/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/common/style/ellipsis.wxss new file mode 100644 index 0000000000000000000000000000000000000000..94eba8e273614b71007e95e73728fb3a3c7ee6a8 --- /dev/null +++ b/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/common/style/ellipsis.wxss @@ -0,0 +1 @@ +.van-ellipsis{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.van-multi-ellipsis--l2{overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}.van-multi-ellipsis--l3{overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical} \ No newline at end of file diff --git a/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/common/style/hairline.wxss b/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/common/style/hairline.wxss new file mode 100644 index 0000000000000000000000000000000000000000..8b81d62231822c36efb29271dbb8597b97f19a8e --- /dev/null +++ b/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/common/style/hairline.wxss @@ -0,0 +1 @@ +.van-hairline,.van-hairline--bottom,.van-hairline--left,.van-hairline--right,.van-hairline--surround,.van-hairline--top,.van-hairline--top-bottom{position:relative}.van-hairline--bottom::after,.van-hairline--left::after,.van-hairline--right::after,.van-hairline--surround::after,.van-hairline--top-bottom::after,.van-hairline--top::after,.van-hairline::after{content:'';position:absolute;top:-50%;left:-50%;right:-50%;bottom:-50%;-webkit-transform:scale(.5);transform:scale(.5);pointer-events:none;box-sizing:border-box;border:0 solid #eee}.van-hairline--top::after{border-top-width:1px}.van-hairline--left::after{border-left-width:1px}.van-hairline--right::after{border-right-width:1px}.van-hairline--bottom::after{border-bottom-width:1px}.van-hairline--top-bottom::after{border-width:1px 0}.van-hairline--surround::after{border-width:1px} \ No newline at end of file diff --git a/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/common/style/mixins/clearfix.wxss b/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/common/style/mixins/clearfix.wxss new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/common/style/mixins/ellipsis.wxss b/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/common/style/mixins/ellipsis.wxss new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/common/style/mixins/hairline.wxss b/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/common/style/mixins/hairline.wxss new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/common/style/var.wxss b/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/common/style/var.wxss new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/common/utils.js b/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/common/utils.js new file mode 100644 index 0000000000000000000000000000000000000000..71ddfc644263c041976bc5c6bc300257074b8277 --- /dev/null +++ b/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/common/utils.js @@ -0,0 +1,13 @@ +function isDef(value) { + return value !== undefined && value !== null; +} + +function isObj(x) { + const type = typeof x; + return x !== null && (type === 'object' || type === 'function'); +} + +export { + isObj, + isDef +}; diff --git a/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/mixins/basic.js b/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/mixins/basic.js new file mode 100644 index 0000000000000000000000000000000000000000..bad37d454d9a416b9bf1b041b5a891c029797878 --- /dev/null +++ b/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/mixins/basic.js @@ -0,0 +1,28 @@ +import { classNames } from '../common/class-names'; + +export const basic = Behavior({ + methods: { + classNames, + + $emit() { + this.triggerEvent.apply(this, arguments); + }, + + getRect(selector, all) { + return new Promise((resolve, reject) => { + wx.createSelectorQuery() + .in(this)[all ? 'selectAll' : 'select'](selector) + .boundingClientRect(rect => { + if (all && Array.isArray(rect) && rect.length) { + resolve(rect); + } + + if (!all && rect) { + resolve(rect); + } + }) + .exec(); + }); + } + } +}); diff --git a/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/mixins/button.js b/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/mixins/button.js new file mode 100644 index 0000000000000000000000000000000000000000..fd15aea83399771ca297633494886507df8bc004 --- /dev/null +++ b/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/mixins/button.js @@ -0,0 +1,50 @@ +export const button = Behavior({ + properties: { + loading: Boolean, + openType: String, + appParameter: String, + sendMessageTitle: String, + sendMessagePath: String, + sendMessageImg: String, + showMessageCard: String, + hoverStopPropagation: Boolean, + hoverStartTime: { + type: Number, + value: 20 + }, + hoverStayTime: { + type: Number, + value: 70 + }, + lang: { + type: String, + value: 'en' + }, + sessionFrom: { + type: String, + value: '' + } + }, + + methods: { + bindgetuserinfo(event = {}) { + this.$emit('getuserinfo', event.detail); + }, + + bindcontact(event = {}) { + this.$emit('contact', event.detail); + }, + + bindgetphonenumber(event = {}) { + this.$emit('getphonenumber', event.detail); + }, + + bindopensetting(event = {}) { + this.$emit('opensetting', event.detail); + }, + + binderror(event = {}) { + this.$emit('error', event.detail); + } + } +}); diff --git a/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/mixins/observer/behavior.js b/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/mixins/observer/behavior.js new file mode 100644 index 0000000000000000000000000000000000000000..9162ef043df4e000872a27f4b857b710acf87df4 --- /dev/null +++ b/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/mixins/observer/behavior.js @@ -0,0 +1,36 @@ +export const behavior = Behavior({ + created() { + if (!this.$options) { + return; + } + + const cache = {}; + const { setData } = this; + const { computed } = this.$options(); + const keys = Object.keys(computed); + + const calcComputed = () => { + const needUpdate = {}; + keys.forEach(key => { + const value = computed[key].call(this); + + if (cache[key] !== value) { + cache[key] = needUpdate[key] = value; + } + }); + + return needUpdate; + }; + + Object.defineProperty(this, 'setData', { writable: true }); + + this.setData = (data, callback) => { + data && setData.call(this, data, callback); + setData.call(this, calcComputed()); + }; + }, + + attached() { + this.setData(); + } +}); diff --git a/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/mixins/observer/index.js b/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/mixins/observer/index.js new file mode 100644 index 0000000000000000000000000000000000000000..0cba0aecb477753399ac5876f245d85fd91d92f1 --- /dev/null +++ b/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/mixins/observer/index.js @@ -0,0 +1,14 @@ +import { behavior } from './behavior'; +import { observeProps } from './props'; + +export function observe(sfc) { + if (sfc.computed) { + sfc.behaviors.push(behavior); + sfc.methods = sfc.methods || {}; + sfc.methods.$options = () => sfc; + + if (sfc.properties) { + observeProps(sfc.properties); + } + } +} diff --git a/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/mixins/observer/props.js b/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/mixins/observer/props.js new file mode 100644 index 0000000000000000000000000000000000000000..9f7923f64509dcefc7cf8c7782bcafc45e6dabfc --- /dev/null +++ b/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/mixins/observer/props.js @@ -0,0 +1,25 @@ +export function observeProps(props) { + if (!props) { + return; + } + + Object.keys(props).forEach(key => { + let prop = props[key]; + if (prop === null || !prop.type) { + prop = { type: prop }; + } + + let { observer } = prop; + prop.observer = function() { + if (observer) { + if (typeof observer === 'string') { + observer = this[observer]; + } + observer.apply(this, arguments); + } + this.setData(); + }; + + props[key] = prop; + }); +} diff --git a/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/mixins/touch.js b/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/mixins/touch.js new file mode 100644 index 0000000000000000000000000000000000000000..ae2cb78e3211d7f5920e717e9d117f316182df9c --- /dev/null +++ b/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/mixins/touch.js @@ -0,0 +1,22 @@ +export const touch = Behavior({ + methods: { + touchStart(event) { + this.direction = ''; + this.deltaX = 0; + this.deltaY = 0; + this.offsetX = 0; + this.offsetY = 0; + this.startX = event.touches[0].clientX; + this.startY = event.touches[0].clientY; + }, + + touchMove(event) { + const touch = event.touches[0]; + this.deltaX = touch.clientX - this.startX; + this.deltaY = touch.clientY - this.startY; + this.offsetX = Math.abs(this.deltaX); + this.offsetY = Math.abs(this.deltaY); + this.direction = this.offsetX > this.offsetY ? 'horizontal' : this.offsetX < this.offsetY ? 'vertical' : ''; + } + } +}); diff --git a/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/mixins/transition.js b/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/mixins/transition.js new file mode 100644 index 0000000000000000000000000000000000000000..e1a5ab872abe1055a2b9a98f7dbaa7c0db545181 --- /dev/null +++ b/examples/wxcomponents-template/wxcomponents/vant-weapp/dist/mixins/transition.js @@ -0,0 +1,54 @@ +export const transition = function(showDefaultValue) { + return Behavior({ + properties: { + customStyle: String, + show: { + value: showDefaultValue, + type: Boolean, + observer(value) { + if (value) { + this.show(); + } else { + this.setData({ + type: 'leave' + }); + } + } + }, + duration: { + type: Number, + value: 300 + } + }, + + data: { + type: '', + inited: false, + display: false + }, + + attached() { + if (this.data.show) { + this.show(); + } + }, + + methods: { + show() { + this.setData({ + inited: true, + display: true, + type: 'enter' + }); + }, + + onAnimationEnd() { + if (!this.data.show) { + this.setData({ + display: false + }); + } + } + } + }); +}; diff --git a/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/animation-group/index.js b/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/animation-group/index.js new file mode 100644 index 0000000000000000000000000000000000000000..a857c44339232b5464c0c1a58c049789795a8ebd --- /dev/null +++ b/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/animation-group/index.js @@ -0,0 +1,407 @@ +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: '', // 离开过渡的完成状态 +} + +Component({ + externalClasses: ['wux-class'], + data: { + animateCss: '', // 动画样式 + animateStatus: EXITED, // 动画状态,可选值 entering、entered、exiting、exited + isMounting: false, // 是否首次挂载 + }, + 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, + }, + }, + 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) + }, + /** + * safeSetData + * @param {Object} nextData 数据对象 + * @param {Function} callback 回调函数 + */ + safeSetData(nextData, callback) { + this.pendingData = Object.assign({}, this.data, nextData) + callback = this.setNextCallback(callback) + + this.setData(nextData, () => { + this.pendingData = null + callback() + }) + }, + /** + * 设置下一回调函数 + * @param {Function} callback 回调函数 + */ + setNextCallback(callback) { + let active = true + + this.nextCallback = (event) => { + if (active) { + active = false + this.nextCallback = null + + callback.call(this, event) + } + } + + this.nextCallback.cancel = () => { + active = false + } + + return this.nextCallback + }, + /** + * 取消下一回调函数 + */ + cancelNextCallback() { + if (this.nextCallback !== null) { + this.nextCallback.cancel() + this.nextCallback = null + } + }, + /** + * 延迟一段时间触发回调 + * @param {Number} timeout 延迟时间 + * @param {Function} handler 回调函数 + */ + delayHandler(timeout, handler) { + if (timeout) { + this.setNextCallback(handler) + setTimeout(this.nextCallback, timeout) + } + }, + /** + * 点击事件 + */ + onTap() { + this.triggerEvent('click') + }, + }, + created() { + this.nextCallback = null + }, + 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) + }) + }, + detached() { + this.cancelNextCallback() + }, +}) \ No newline at end of file diff --git a/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/animation-group/index.json b/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/animation-group/index.json new file mode 100644 index 0000000000000000000000000000000000000000..fba482a42bfc985e328144eb7f5cc005680b7c57 --- /dev/null +++ b/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/animation-group/index.json @@ -0,0 +1,3 @@ +{ + "component": true +} \ No newline at end of file diff --git a/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/animation-group/index.wxml b/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/animation-group/index.wxml new file mode 100644 index 0000000000000000000000000000000000000000..6c646d7cc28f845983e5d6a447071568d0767b57 --- /dev/null +++ b/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/animation-group/index.wxml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/animation-group/index.wxss b/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/animation-group/index.wxss new file mode 100644 index 0000000000000000000000000000000000000000..9468c86bcc3ca255e06ff27432cbecde7c27b140 --- /dev/null +++ b/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/animation-group/index.wxss @@ -0,0 +1,250 @@ +.wux-animate--fadeIn-enter { + -webkit-transition: opacity .3s; + transition: opacity .3s; + opacity: 0; +} +.wux-animate--fadeIn-enter-active, +.wux-animate--fadeIn-enter-done { + opacity: 1; +} +.wux-animate--fadeIn-exit { + -webkit-transition: opacity .3s; + transition: opacity .3s; + opacity: 1; +} +.wux-animate--fadeIn-exit-active, +.wux-animate--fadeIn-exit-done { + opacity: 0; +} +.wux-animate--fadeInDown-enter { + -webkit-transition: opacity .3s, -webkit-transform .3s; + transition: opacity .3s, -webkit-transform .3s; + transition: opacity .3s, transform .3s; + transition: opacity .3s, transform .3s, -webkit-transform .3s; + opacity: 0; + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); +} +.wux-animate--fadeInDown-enter-active, +.wux-animate--fadeInDown-enter-done { + opacity: 1; + -webkit-transform: none; + transform: none; +} +.wux-animate--fadeInDown-exit { + -webkit-transition: opacity .3s, -webkit-transform .3s; + transition: opacity .3s, -webkit-transform .3s; + transition: opacity .3s, transform .3s; + transition: opacity .3s, transform .3s, -webkit-transform .3s; + opacity: 1; + -webkit-transform: none; + transform: none; +} +.wux-animate--fadeInDown-exit-active, +.wux-animate--fadeInDown-exit-done { + opacity: 0; + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); +} +.wux-animate--fadeInLeft-enter { + -webkit-transition: opacity .3s, -webkit-transform .3s; + transition: opacity .3s, -webkit-transform .3s; + transition: opacity .3s, transform .3s; + transition: opacity .3s, transform .3s, -webkit-transform .3s; + opacity: 0; + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); +} +.wux-animate--fadeInLeft-enter-active, +.wux-animate--fadeInLeft-enter-done { + opacity: 1; + -webkit-transform: none; + transform: none; +} +.wux-animate--fadeInLeft-exit { + -webkit-transition: opacity .3s, -webkit-transform .3s; + transition: opacity .3s, -webkit-transform .3s; + transition: opacity .3s, transform .3s; + transition: opacity .3s, transform .3s, -webkit-transform .3s; + opacity: 1; + -webkit-transform: none; + transform: none; +} +.wux-animate--fadeInLeft-exit-active, +.wux-animate--fadeInLeft-exit-done { + opacity: 0; + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); +} +.wux-animate--fadeInRight-enter { + -webkit-transition: opacity .3s, -webkit-transform .3s; + transition: opacity .3s, -webkit-transform .3s; + transition: opacity .3s, transform .3s; + transition: opacity .3s, transform .3s, -webkit-transform .3s; + opacity: 0; + -webkit-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); +} +.wux-animate--fadeInRight-enter-active, +.wux-animate--fadeInRight-enter-done { + opacity: 1; + -webkit-transform: none; + transform: none; +} +.wux-animate--fadeInRight-exit { + -webkit-transition: opacity .3s, -webkit-transform .3s; + transition: opacity .3s, -webkit-transform .3s; + transition: opacity .3s, transform .3s; + transition: opacity .3s, transform .3s, -webkit-transform .3s; + opacity: 1; + -webkit-transform: none; + transform: none; +} +.wux-animate--fadeInRight-exit-active, +.wux-animate--fadeInRight-exit-done { + opacity: 0; + -webkit-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); +} +.wux-animate--fadeInUp-enter { + -webkit-transition: opacity .3s, -webkit-transform .3s; + transition: opacity .3s, -webkit-transform .3s; + transition: opacity .3s, transform .3s; + transition: opacity .3s, transform .3s, -webkit-transform .3s; + opacity: 0; + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); +} +.wux-animate--fadeInUp-enter-active, +.wux-animate--fadeInUp-enter-done { + opacity: 1; + -webkit-transform: none; + transform: none; +} +.wux-animate--fadeInUp-exit { + -webkit-transition: opacity .3s, -webkit-transform .3s; + transition: opacity .3s, -webkit-transform .3s; + transition: opacity .3s, transform .3s; + transition: opacity .3s, transform .3s, -webkit-transform .3s; + opacity: 1; + -webkit-transform: none; + transform: none; +} +.wux-animate--fadeInUp-exit-active, +.wux-animate--fadeInUp-exit-done { + opacity: 0; + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); +} +.wux-animate--slideInUp-enter { + -webkit-transition: -webkit-transform .3s; + transition: -webkit-transform .3s; + transition: transform .3s; + transition: transform .3s, -webkit-transform .3s; + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + visibility: visible; +} +.wux-animate--slideInUp-enter-active, +.wux-animate--slideInUp-enter-done { + -webkit-transform: translateZ(0); + transform: translateZ(0); +} +.wux-animate--slideInUp-exit { + -webkit-transition: -webkit-transform .3s; + transition: -webkit-transform .3s; + transition: transform .3s; + transition: transform .3s, -webkit-transform .3s; + -webkit-transform: translateZ(0); + transform: translateZ(0); +} +.wux-animate--slideInUp-exit-active, +.wux-animate--slideInUp-exit-done { + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + visibility: visible; +} +.wux-animate--slideInDown-enter { + -webkit-transition: -webkit-transform .3s; + transition: -webkit-transform .3s; + transition: transform .3s; + transition: transform .3s, -webkit-transform .3s; + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); + visibility: visible; +} +.wux-animate--slideInDown-enter-active, +.wux-animate--slideInDown-enter-done { + -webkit-transform: translateZ(0); + transform: translateZ(0); +} +.wux-animate--slideInDown-exit { + -webkit-transition: -webkit-transform .3s; + transition: -webkit-transform .3s; + transition: transform .3s; + transition: transform .3s, -webkit-transform .3s; + -webkit-transform: translateZ(0); + transform: translateZ(0); +} +.wux-animate--slideInDown-exit-active, +.wux-animate--slideInDown-exit-done { + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); + visibility: visible; +} +.wux-animate--slideInLeft-enter { + -webkit-transition: -webkit-transform .3s; + transition: -webkit-transform .3s; + transition: transform .3s; + transition: transform .3s, -webkit-transform .3s; + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); + visibility: visible; +} +.wux-animate--slideInLeft-enter-active, +.wux-animate--slideInLeft-enter-done { + -webkit-transform: translateZ(0); + transform: translateZ(0); +} +.wux-animate--slideInLeft-exit { + -webkit-transition: -webkit-transform .3s; + transition: -webkit-transform .3s; + transition: transform .3s; + transition: transform .3s, -webkit-transform .3s; + -webkit-transform: translateZ(0); + transform: translateZ(0); +} +.wux-animate--slideInLeft-exit-active, +.wux-animate--slideInLeft-exit-done { + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); + visibility: visible; +} +.wux-animate--slideInRight-enter { + -webkit-transition: -webkit-transform .3s; + transition: -webkit-transform .3s; + transition: transform .3s; + transition: transform .3s, -webkit-transform .3s; + -webkit-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); + visibility: visible; +} +.wux-animate--slideInRight-enter-active, +.wux-animate--slideInRight-enter-done { + -webkit-transform: translateZ(0); + transform: translateZ(0); +} +.wux-animate--slideInRight-exit { + -webkit-transition: -webkit-transform .3s; + transition: -webkit-transform .3s; + transition: transform .3s; + transition: transform .3s, -webkit-transform .3s; + -webkit-transform: translateZ(0); + transform: translateZ(0); +} +.wux-animate--slideInRight-exit-active, +.wux-animate--slideInRight-exit-done { + -webkit-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); + visibility: visible; +} diff --git a/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/backdrop/index.js b/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/backdrop/index.js new file mode 100644 index 0000000000000000000000000000000000000000..60ef4aeca7df8fdf46f38be3785bb5ab36bd1f48 --- /dev/null +++ b/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/backdrop/index.js @@ -0,0 +1,43 @@ +import baseBehavior from '../helpers/baseBehavior' + +Component({ + behaviors: [baseBehavior], + externalClasses: ['wux-class'], + properties: { + transparent: { + type: Boolean, + value: false, + }, + }, + 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') + }, + }, +}) \ No newline at end of file diff --git a/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/backdrop/index.json b/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/backdrop/index.json new file mode 100644 index 0000000000000000000000000000000000000000..9b9e7abfc6cffb4f868e60bf1b19ad7ec6e853ef --- /dev/null +++ b/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/backdrop/index.json @@ -0,0 +1,6 @@ +{ + "component": true, + "usingComponents": { + "wux-animation-group": "../animation-group/index" + } +} \ No newline at end of file diff --git a/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/backdrop/index.wxml b/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/backdrop/index.wxml new file mode 100644 index 0000000000000000000000000000000000000000..66be6180b3c58caf9bb6a7971287a94b4fca4a62 --- /dev/null +++ b/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/backdrop/index.wxml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/backdrop/index.wxss b/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/backdrop/index.wxss new file mode 100644 index 0000000000000000000000000000000000000000..edfc7968f1e37e302f179406ae198a55ebda56d7 --- /dev/null +++ b/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/backdrop/index.wxss @@ -0,0 +1,15 @@ +.wux-backdrop { + background: rgba(0, 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: transparent; +} diff --git a/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/helpers/baseBehavior.js b/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/helpers/baseBehavior.js new file mode 100644 index 0000000000000000000000000000000000000000..dd04f8153807ccd1ed04a6da9e1a55deb7dacedd --- /dev/null +++ b/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/helpers/baseBehavior.js @@ -0,0 +1,77 @@ +/** + * Simple bind, faster than native + * + * @param {Function} fn + * @param {Object} ctx + * @return {Function} + */ +const bind = (fn, ctx) => { + return (...args) => { + return args.length ? fn.apply(ctx, args) : fn.call(ctx) + } +} + +/** + * Object assign + */ +const assign = (...args) => Object.assign({}, ...args) + +export default Behavior({ + properties: { + visible: { + type: Boolean, + value: false, + }, + }, + methods: { + /** + * 合并参数并绑定方法 + * + * @param {Object} opts 参数对象 + * @param {Object} fns 方法挂载的属性 + */ + $$mergeOptionsAndBindMethods(opts = {}, fns = this.fns) { + const options = Object.assign({}, opts) + + for (const key in options) { + if (options.hasOwnProperty(key) && typeof options[key] === 'function') { + fns[key] = bind(options[key], this) + delete options[key] + } + } + + return options + }, + /** + * Promise setData + * @param {Array} args 参数对象 + */ + $$setData(...args) { + const params = assign({}, ...args) + + return new Promise((resolve) => { + this.setData(params, resolve) + }) + }, + /** + * 延迟指定时间执行回调函数 + * @param {Function} callback 回调函数 + * @param {Number} timeout 延迟时间 + */ + $$requestAnimationFrame(callback = () => {}, timeout = 1000 / 60) { + return new Promise((resolve) => setTimeout(resolve, timeout)).then(callback) + }, + }, + /** + * 组件生命周期函数,在组件实例进入页面节点树时执行 + */ + created() { + this.fns = {} + }, + /** + * 组件生命周期函数,在组件实例被从页面节点树移除时执行 + */ + detached() { + this.fns = {} + }, +}) \ No newline at end of file diff --git a/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/helpers/colors.js b/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/helpers/colors.js new file mode 100644 index 0000000000000000000000000000000000000000..3490eff72ad5c2ddc73f16b027c265ad21ece3f1 --- /dev/null +++ b/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/helpers/colors.js @@ -0,0 +1,18 @@ +export const colors = { + 'light': '#ddd', + 'stable': '#b2b2b2', + 'positive': '#387ef5', + 'calm': '#11c1f3', + 'balanced': '#33cd5f', + 'energized': '#ffc900', + 'assertive': '#ef473a', + 'royal': '#886aea', + 'dark': '#444', +} + +export const isPresetColor = (color) => { + if (!color) { + return false + } + return colors[color] ? colors[color] : color +} \ No newline at end of file diff --git a/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/helpers/gestures.js b/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/helpers/gestures.js new file mode 100644 index 0000000000000000000000000000000000000000..908ee845eeaa4b7d9882e8bd783f5ba6806aa2e2 --- /dev/null +++ b/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/helpers/gestures.js @@ -0,0 +1,38 @@ +/** + * 获取触摸点位置信息 + */ +export const getTouchPoints = (e, index = 0) => { + const { pageX: x, pageY: y } = e.touches[index] || e.changedTouches[index] + return { + x, + y, + } +} + +/** + * 获取触摸点个数 + */ +export const getPointsNumber = (e) => e.touches && e.touches.length || e.changedTouches && e.changedTouches.length + +/** + * 判断是否为同一点 + */ +export const isEqualPoints = (p1, p2) => p1.x === p2.x && p1.y === p2.y + +/** + * 判断是否为相近的两点 + */ +export const isNearbyPoints = (p1, p2, DOUBLE_TAP_RADIUS = 25) => { + const xMove = Math.abs(p1.x - p2.x) + const yMove = Math.abs(p1.y - p2.y) + return xMove < DOUBLE_TAP_RADIUS & yMove < DOUBLE_TAP_RADIUS +} + +/** + * 获取两点之间的距离 + */ +export const getPointsDistance = (p1, p2) => { + const xMove = Math.abs(p1.x - p2.x) + const yMove = Math.abs(p1.y - p2.y) + return Math.sqrt(xMove * xMove + yMove * yMove) +} \ No newline at end of file diff --git a/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/helpers/mergeOptionsToData.js b/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/helpers/mergeOptionsToData.js new file mode 100644 index 0000000000000000000000000000000000000000..632556bd228b3610ba20e690f1bca8c52226b685 --- /dev/null +++ b/examples/wxcomponents-template/wxcomponents/wux-weapp/dist/helpers/mergeOptionsToData.js @@ -0,0 +1,17 @@ +/** + * 过滤对象的函数属性 + * @param {Object} opts + */ +const mergeOptionsToData = (opts = {}) => { + const options = Object.assign({}, opts) + + for (const key in options) { + if (options.hasOwnProperty(key) && typeof options[key] === 'function') { + delete options[key] + } + } + + return options +} + +export default mergeOptionsToData \ No newline at end of file