Commit 4ee9880a463061fe600eeb4f226a902875bdd60a
Exists in
master
解决冲突
Showing
14 changed files
Show diff stats
src/components/BottomSheet/BottomSheet.vue
| ... | ... | @@ -814,9 +814,10 @@ import store from '@/store' |
| 814 | 814 | mp_id: this.mp_id, |
| 815 | 815 | attrList: this.attrList, |
| 816 | 816 | }) |
| 817 | + this.$store.state.cart.buyItem = this.skuItem | |
| 817 | 818 | // 跳转到确认订单页面 |
| 818 | 819 | uni.navigateTo({ |
| 819 | - url: `../confirmOrder/confirmOrder?pid=${this.pid}&count=${this.count}&name=${this.name}`, | |
| 820 | + url: `../confirmOrder/confirmOrder?pid=${this.pid}&count=${this.count}&name=${this.name}&isCart=false`, | |
| 820 | 821 | }) |
| 821 | 822 | } |
| 822 | 823 | }, | ... | ... |
src/components/CommodityCard/CommodityCard.vue
src/components/uni-swipe-action-item/bindingx.js
| ... | ... | @@ -0,0 +1,245 @@ |
| 1 | +const BindingX = uni.requireNativePlugin('bindingx'); | |
| 2 | +const dom = uni.requireNativePlugin('dom'); | |
| 3 | +const animation = uni.requireNativePlugin('animation'); | |
| 4 | + | |
| 5 | +export default { | |
| 6 | + data() { | |
| 7 | + return { | |
| 8 | + right: 0, | |
| 9 | + button: [], | |
| 10 | + preventGesture: false | |
| 11 | + } | |
| 12 | + }, | |
| 13 | + | |
| 14 | + watch: { | |
| 15 | + show(newVal) { | |
| 16 | + if (!this.position || JSON.stringify(this.position) === '{}') return; | |
| 17 | + if (this.autoClose) return | |
| 18 | + if (this.isInAnimation) return | |
| 19 | + if (newVal) { | |
| 20 | + this.open() | |
| 21 | + } else { | |
| 22 | + this.close() | |
| 23 | + } | |
| 24 | + }, | |
| 25 | + }, | |
| 26 | + created() { | |
| 27 | + if (this.swipeaction.children !== undefined) { | |
| 28 | + this.swipeaction.children.push(this) | |
| 29 | + } | |
| 30 | + }, | |
| 31 | + mounted() { | |
| 32 | + this.boxSelector = this.getEl(this.$refs['selector-box-hock']); | |
| 33 | + this.selector = this.getEl(this.$refs['selector-content-hock']); | |
| 34 | + this.buttonSelector = this.getEl(this.$refs['selector-button-hock']); | |
| 35 | + this.position = {} | |
| 36 | + this.x = 0 | |
| 37 | + setTimeout(() => { | |
| 38 | + this.getSelectorQuery() | |
| 39 | + }, 200) | |
| 40 | + }, | |
| 41 | + beforeDestroy() { | |
| 42 | + if (this.timing) { | |
| 43 | + BindingX.unbind({ | |
| 44 | + token: this.timing.token, | |
| 45 | + eventType: 'timing' | |
| 46 | + }) | |
| 47 | + } | |
| 48 | + if (this.eventpan) { | |
| 49 | + BindingX.unbind({ | |
| 50 | + token: this.eventpan.token, | |
| 51 | + eventType: 'pan' | |
| 52 | + }) | |
| 53 | + } | |
| 54 | + this.swipeaction.children.forEach((item, index) => { | |
| 55 | + if (item === this) { | |
| 56 | + this.swipeaction.children.splice(index, 1) | |
| 57 | + } | |
| 58 | + }) | |
| 59 | + }, | |
| 60 | + methods: { | |
| 61 | + onClick(index, item) { | |
| 62 | + this.$emit('click', { | |
| 63 | + content: item, | |
| 64 | + index | |
| 65 | + }) | |
| 66 | + }, | |
| 67 | + touchstart(e) { | |
| 68 | + if (this.isInAnimation) return | |
| 69 | + if (this.stop) return | |
| 70 | + this.stop = true | |
| 71 | + if (this.autoClose) { | |
| 72 | + this.swipeaction.closeOther(this) | |
| 73 | + } | |
| 74 | + let endWidth = this.right | |
| 75 | + let boxStep = `(x+${this.x})` | |
| 76 | + let pageX = `${boxStep}> ${-endWidth} && ${boxStep} < 0?${boxStep}:(x+${this.x} < 0? ${-endWidth}:0)` | |
| 77 | + | |
| 78 | + let props = [{ | |
| 79 | + element: this.selector, | |
| 80 | + property: 'transform.translateX', | |
| 81 | + expression: pageX | |
| 82 | + }] | |
| 83 | + | |
| 84 | + let left = 0 | |
| 85 | + for (let i = 0; i < this.options.length; i++) { | |
| 86 | + let buttonSelectors = this.getEl(this.$refs['button-hock'][i]); | |
| 87 | + if (this.button.length === 0 || !this.button[i] || !this.button[i].width) return | |
| 88 | + let moveMix = endWidth - left | |
| 89 | + left += this.button[i].width | |
| 90 | + let step = `(${this.x}+x)/${endWidth}` | |
| 91 | + let moveX = `(${step}) * ${moveMix}` | |
| 92 | + let pageButtonX = `${moveX}&& (x+${this.x} > ${-endWidth})?${moveX}:${-moveMix}` | |
| 93 | + props.push({ | |
| 94 | + element: buttonSelectors, | |
| 95 | + property: 'transform.translateX', | |
| 96 | + expression: pageButtonX | |
| 97 | + }) | |
| 98 | + } | |
| 99 | + | |
| 100 | + this.eventpan = this._bind(this.boxSelector, props, 'pan', (e) => { | |
| 101 | + if (e.state === 'end') { | |
| 102 | + this.x = e.deltaX + this.x; | |
| 103 | + if (this.x < -endWidth) { | |
| 104 | + this.x = -endWidth | |
| 105 | + } | |
| 106 | + if (this.x > 0) { | |
| 107 | + this.x = 0 | |
| 108 | + } | |
| 109 | + this.stop = false | |
| 110 | + this.bindTiming(); | |
| 111 | + } | |
| 112 | + }) | |
| 113 | + }, | |
| 114 | + touchend(e) { | |
| 115 | + this.$nextTick(() => { | |
| 116 | + if (this.isopen && !this.isDrag && !this.isInAnimation) { | |
| 117 | + this.close() | |
| 118 | + } | |
| 119 | + }) | |
| 120 | + }, | |
| 121 | + bindTiming() { | |
| 122 | + if (this.isopen) { | |
| 123 | + this.move(this.x, -this.right) | |
| 124 | + } else { | |
| 125 | + this.move(this.x, -40) | |
| 126 | + } | |
| 127 | + }, | |
| 128 | + move(left, value) { | |
| 129 | + if (left >= value) { | |
| 130 | + this.close() | |
| 131 | + } else { | |
| 132 | + this.open() | |
| 133 | + } | |
| 134 | + }, | |
| 135 | + /** | |
| 136 | + * 开启swipe | |
| 137 | + */ | |
| 138 | + open() { | |
| 139 | + this.animation(true) | |
| 140 | + }, | |
| 141 | + /** | |
| 142 | + * 关闭swipe | |
| 143 | + */ | |
| 144 | + close() { | |
| 145 | + this.animation(false) | |
| 146 | + }, | |
| 147 | + /** | |
| 148 | + * 开启关闭动画 | |
| 149 | + * @param {Object} type | |
| 150 | + */ | |
| 151 | + animation(type) { | |
| 152 | + this.isDrag = true | |
| 153 | + let endWidth = this.right | |
| 154 | + let time = 200 | |
| 155 | + this.isInAnimation = true; | |
| 156 | + | |
| 157 | + let exit = `t>${time}`; | |
| 158 | + let translate_x_expression = `easeOutExpo(t,${this.x},${type?(-endWidth-this.x):(-this.x)},${time})` | |
| 159 | + let props = [{ | |
| 160 | + element: this.selector, | |
| 161 | + property: 'transform.translateX', | |
| 162 | + expression: translate_x_expression | |
| 163 | + }] | |
| 164 | + | |
| 165 | + let left = 0 | |
| 166 | + for (let i = 0; i < this.options.length; i++) { | |
| 167 | + let buttonSelectors = this.getEl(this.$refs['button-hock'][i]); | |
| 168 | + if (this.button.length === 0 || !this.button[i] || !this.button[i].width) return | |
| 169 | + let moveMix = endWidth - left | |
| 170 | + left += this.button[i].width | |
| 171 | + let step = `${this.x}/${endWidth}` | |
| 172 | + let moveX = `(${step}) * ${moveMix}` | |
| 173 | + let pageButtonX = `easeOutExpo(t,${moveX},${type ? -moveMix + '-' + moveX: 0 + '-' + moveX},${time})` | |
| 174 | + props.push({ | |
| 175 | + element: buttonSelectors, | |
| 176 | + property: 'transform.translateX', | |
| 177 | + expression: pageButtonX | |
| 178 | + }) | |
| 179 | + } | |
| 180 | + | |
| 181 | + this.timing = BindingX.bind({ | |
| 182 | + eventType: 'timing', | |
| 183 | + exitExpression: exit, | |
| 184 | + props: props | |
| 185 | + }, (e) => { | |
| 186 | + if (e.state === 'end' || e.state === 'exit') { | |
| 187 | + this.x = type ? -endWidth : 0 | |
| 188 | + this.isInAnimation = false; | |
| 189 | + | |
| 190 | + this.isopen = this.isopen || false | |
| 191 | + if (this.isopen !== type) { | |
| 192 | + this.$emit('change', type) | |
| 193 | + } | |
| 194 | + this.isopen = type | |
| 195 | + this.isDrag = false | |
| 196 | + } | |
| 197 | + }); | |
| 198 | + }, | |
| 199 | + /** | |
| 200 | + * 绑定 BindingX | |
| 201 | + * @param {Object} anchor | |
| 202 | + * @param {Object} props | |
| 203 | + * @param {Object} fn | |
| 204 | + */ | |
| 205 | + _bind(anchor, props, eventType, fn) { | |
| 206 | + return BindingX.bind({ | |
| 207 | + anchor, | |
| 208 | + eventType, | |
| 209 | + props | |
| 210 | + }, (e) => { | |
| 211 | + typeof(fn) === 'function' && fn(e) | |
| 212 | + }); | |
| 213 | + }, | |
| 214 | + /** | |
| 215 | + * 获取ref | |
| 216 | + * @param {Object} el | |
| 217 | + */ | |
| 218 | + getEl(el) { | |
| 219 | + return el.ref | |
| 220 | + }, | |
| 221 | + /** | |
| 222 | + * 获取节点信息 | |
| 223 | + */ | |
| 224 | + getSelectorQuery() { | |
| 225 | + dom.getComponentRect(this.$refs['selector-content-hock'], (data) => { | |
| 226 | + if (this.position.content) return | |
| 227 | + this.position.content = data.size | |
| 228 | + }) | |
| 229 | + for (let i = 0; i < this.options.length; i++) { | |
| 230 | + dom.getComponentRect(this.$refs['button-hock'][i], (data) => { | |
| 231 | + if (!this.button) { | |
| 232 | + this.button = [] | |
| 233 | + } | |
| 234 | + if (this.options.length === this.button.length) return | |
| 235 | + this.button.push(data.size) | |
| 236 | + this.right += data.size.width | |
| 237 | + if (this.autoClose) return | |
| 238 | + if (this.show) { | |
| 239 | + this.open() | |
| 240 | + } | |
| 241 | + }) | |
| 242 | + } | |
| 243 | + } | |
| 244 | + } | |
| 245 | +} | ... | ... |
src/components/uni-swipe-action-item/index.wxs
| ... | ... | @@ -0,0 +1,204 @@ |
| 1 | +/** | |
| 2 | + * 监听页面内值的变化,主要用于动态开关swipe-action | |
| 3 | + * @param {Object} newValue | |
| 4 | + * @param {Object} oldValue | |
| 5 | + * @param {Object} ownerInstance | |
| 6 | + * @param {Object} instance | |
| 7 | + */ | |
| 8 | +function sizeReady(newValue, oldValue, ownerInstance, instance) { | |
| 9 | + var state = instance.getState() | |
| 10 | + state.position = JSON.parse(newValue) | |
| 11 | + if (!state.position || state.position.length === 0) return | |
| 12 | + var show = state.position[0].show | |
| 13 | + state.left = state.left || state.position[0].left; | |
| 14 | + // 通过用户变量,开启或关闭 | |
| 15 | + if (show) { | |
| 16 | + openState(true, instance, ownerInstance) | |
| 17 | + } else { | |
| 18 | + openState(false, instance, ownerInstance) | |
| 19 | + } | |
| 20 | +} | |
| 21 | + | |
| 22 | +/** | |
| 23 | + * 开始触摸操作 | |
| 24 | + * @param {Object} e | |
| 25 | + * @param {Object} ins | |
| 26 | + */ | |
| 27 | +function touchstart(e, ins) { | |
| 28 | + var instance = e.instance; | |
| 29 | + var state = instance.getState(); | |
| 30 | + var pageX = e.touches[0].pageX; | |
| 31 | + // 开始触摸时移除动画类 | |
| 32 | + instance.removeClass('ani'); | |
| 33 | + var owner = ins.selectAllComponents('.button-hock') | |
| 34 | + for (var i = 0; i < owner.length; i++) { | |
| 35 | + owner[i].removeClass('ani'); | |
| 36 | + } | |
| 37 | + // state.position = JSON.parse(instance.getDataset().position); | |
| 38 | + state.left = state.left || state.position[0].left; | |
| 39 | + // 获取最终按钮组的宽度 | |
| 40 | + state.width = pageX - state.left; | |
| 41 | + ins.callMethod('closeSwipe') | |
| 42 | +} | |
| 43 | + | |
| 44 | +/** | |
| 45 | + * 开始滑动操作 | |
| 46 | + * @param {Object} e | |
| 47 | + * @param {Object} ownerInstance | |
| 48 | + */ | |
| 49 | +function touchmove(e, ownerInstance) { | |
| 50 | + var instance = e.instance; | |
| 51 | + var disabled = instance.getDataset().disabled | |
| 52 | + var state = instance.getState() | |
| 53 | + // fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复 | |
| 54 | + disabled = (typeof(disabled) === 'string' ? JSON.parse(disabled) : disabled) || false; | |
| 55 | + | |
| 56 | + if (disabled) return | |
| 57 | + var pageX = e.touches[0].pageX; | |
| 58 | + move(pageX - state.width, instance, ownerInstance) | |
| 59 | +} | |
| 60 | + | |
| 61 | +/** | |
| 62 | + * 结束触摸操作 | |
| 63 | + * @param {Object} e | |
| 64 | + * @param {Object} ownerInstance | |
| 65 | + */ | |
| 66 | +function touchend(e, ownerInstance) { | |
| 67 | + var instance = e.instance; | |
| 68 | + var disabled = instance.getDataset().disabled | |
| 69 | + var state = instance.getState() | |
| 70 | + | |
| 71 | + // fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复 | |
| 72 | + disabled = (typeof(disabled) === 'string' ? JSON.parse(disabled) : disabled) || false; | |
| 73 | + | |
| 74 | + if (disabled) return | |
| 75 | + // 滑动过程中触摸结束,通过阙值判断是开启还是关闭 | |
| 76 | + // fixed by mehaotian 定时器解决点击按钮,touchend 触发比 click 事件时机早的问题 ,主要是 ios13 | |
| 77 | + moveDirection(state.left, -40, instance, ownerInstance) | |
| 78 | +} | |
| 79 | + | |
| 80 | +/** | |
| 81 | + * 设置移动距离 | |
| 82 | + * @param {Object} value | |
| 83 | + * @param {Object} instance | |
| 84 | + * @param {Object} ownerInstance | |
| 85 | + */ | |
| 86 | +function move(value, instance, ownerInstance) { | |
| 87 | + var state = instance.getState() | |
| 88 | + // 获取可滑动范围 | |
| 89 | + var x = Math.max(-state.position[1].width, Math.min((value), 0)); | |
| 90 | + state.left = x; | |
| 91 | + instance.setStyle({ | |
| 92 | + transform: 'translateX(' + x + 'px)', | |
| 93 | + '-webkit-transform': 'translateX(' + x + 'px)' | |
| 94 | + }) | |
| 95 | + // 折叠按钮动画 | |
| 96 | + buttonFold(x, instance, ownerInstance) | |
| 97 | +} | |
| 98 | + | |
| 99 | +/** | |
| 100 | + * 移动方向判断 | |
| 101 | + * @param {Object} left | |
| 102 | + * @param {Object} value | |
| 103 | + * @param {Object} ownerInstance | |
| 104 | + * @param {Object} ins | |
| 105 | + */ | |
| 106 | +function moveDirection(left, value, ins, ownerInstance) { | |
| 107 | + var state = ins.getState() | |
| 108 | + var position = state.position | |
| 109 | + var isopen = state.isopen | |
| 110 | + if (!position[1].width) { | |
| 111 | + openState(false, ins, ownerInstance) | |
| 112 | + return | |
| 113 | + } | |
| 114 | + // 如果已经是打开状态,进行判断是否关闭,还是保留打开状态 | |
| 115 | + if (isopen) { | |
| 116 | + if (-left <= position[1].width) { | |
| 117 | + openState(false, ins, ownerInstance) | |
| 118 | + } else { | |
| 119 | + openState(true, ins, ownerInstance) | |
| 120 | + } | |
| 121 | + return | |
| 122 | + } | |
| 123 | + // 如果是关闭状态,进行判断是否打开,还是保留关闭状态 | |
| 124 | + if (left <= value) { | |
| 125 | + openState(true, ins, ownerInstance) | |
| 126 | + } else { | |
| 127 | + openState(false, ins, ownerInstance) | |
| 128 | + } | |
| 129 | +} | |
| 130 | + | |
| 131 | +/** | |
| 132 | + * 设置按钮移动距离 | |
| 133 | + * @param {Object} value | |
| 134 | + * @param {Object} instance | |
| 135 | + * @param {Object} ownerInstance | |
| 136 | + */ | |
| 137 | +function buttonFold(value, instance, ownerInstance) { | |
| 138 | + var ins = ownerInstance.selectAllComponents('.button-hock'); | |
| 139 | + var state = instance.getState(); | |
| 140 | + var position = state.position; | |
| 141 | + var arr = []; | |
| 142 | + var w = 0; | |
| 143 | + for (var i = 0; i < ins.length; i++) { | |
| 144 | + if (!ins[i].getDataset().button) return | |
| 145 | + var btnData = JSON.parse(ins[i].getDataset().button) | |
| 146 | + | |
| 147 | + // fix by mehaotian TODO 在 app-vue 中,字符串转对象,需要转两次,这里先这么兼容 | |
| 148 | + if (typeof(btnData) === 'string') { | |
| 149 | + btnData = JSON.parse(btnData) | |
| 150 | + } | |
| 151 | + | |
| 152 | + var button = btnData[i] && btnData[i].width || 0 | |
| 153 | + w += button | |
| 154 | + arr.push(-w) | |
| 155 | + // 动态计算按钮组每个按钮的折叠动画移动距离 | |
| 156 | + var distance = arr[i - 1] + value * (arr[i - 1] / position[1].width) | |
| 157 | + if (i != 0) { | |
| 158 | + ins[i].setStyle({ | |
| 159 | + transform: 'translateX(' + distance + 'px)', | |
| 160 | + }) | |
| 161 | + } | |
| 162 | + } | |
| 163 | +} | |
| 164 | + | |
| 165 | +/** | |
| 166 | + * 开启状态 | |
| 167 | + * @param {Boolean} type | |
| 168 | + * @param {Object} ins | |
| 169 | + * @param {Object} ownerInstance | |
| 170 | + */ | |
| 171 | +function openState(type, ins, ownerInstance) { | |
| 172 | + var state = ins.getState() | |
| 173 | + var position = state.position | |
| 174 | + if (state.isopen === undefined) { | |
| 175 | + state.isopen = false | |
| 176 | + } | |
| 177 | + // 只有状态有改变才会通知页面改变状态 | |
| 178 | + if (state.isopen !== type) { | |
| 179 | + // 通知页面,已经打开 | |
| 180 | + ownerInstance.callMethod('change', { | |
| 181 | + open: type | |
| 182 | + }) | |
| 183 | + } | |
| 184 | + // 设置打开和移动状态 | |
| 185 | + state.isopen = type | |
| 186 | + | |
| 187 | + | |
| 188 | + // 添加动画类 | |
| 189 | + ins.addClass('ani'); | |
| 190 | + var owner = ownerInstance.selectAllComponents('.button-hock') | |
| 191 | + for (var i = 0; i < owner.length; i++) { | |
| 192 | + owner[i].addClass('ani'); | |
| 193 | + } | |
| 194 | + // 设置最终移动位置 | |
| 195 | + move(type ? -position[1].width : 0, ins, ownerInstance) | |
| 196 | + | |
| 197 | +} | |
| 198 | + | |
| 199 | +module.exports = { | |
| 200 | + sizeReady: sizeReady, | |
| 201 | + touchstart: touchstart, | |
| 202 | + touchmove: touchmove, | |
| 203 | + touchend: touchend | |
| 204 | +} | ... | ... |
src/components/uni-swipe-action-item/mpalipay.js
| ... | ... | @@ -0,0 +1,160 @@ |
| 1 | +export default { | |
| 2 | + data() { | |
| 3 | + return { | |
| 4 | + isshow: false, | |
| 5 | + viewWidth: 0, | |
| 6 | + buttonWidth: 0, | |
| 7 | + disabledView: false, | |
| 8 | + x: 0, | |
| 9 | + transition: false | |
| 10 | + } | |
| 11 | + }, | |
| 12 | + watch: { | |
| 13 | + show(newVal) { | |
| 14 | + if (this.autoClose) return | |
| 15 | + if (newVal) { | |
| 16 | + this.open() | |
| 17 | + } else { | |
| 18 | + this.close() | |
| 19 | + } | |
| 20 | + }, | |
| 21 | + }, | |
| 22 | + created() { | |
| 23 | + if (this.swipeaction.children !== undefined) { | |
| 24 | + this.swipeaction.children.push(this) | |
| 25 | + } | |
| 26 | + }, | |
| 27 | + beforeDestroy() { | |
| 28 | + this.swipeaction.children.forEach((item, index) => { | |
| 29 | + if (item === this) { | |
| 30 | + this.swipeaction.children.splice(index, 1) | |
| 31 | + } | |
| 32 | + }) | |
| 33 | + }, | |
| 34 | + mounted() { | |
| 35 | + this.isopen = false | |
| 36 | + this.transition = true | |
| 37 | + setTimeout(() => { | |
| 38 | + this.getQuerySelect() | |
| 39 | + }, 50) | |
| 40 | + | |
| 41 | + }, | |
| 42 | + methods: { | |
| 43 | + onClick(index, item) { | |
| 44 | + this.$emit('click', { | |
| 45 | + content: item, | |
| 46 | + index | |
| 47 | + }) | |
| 48 | + }, | |
| 49 | + touchstart(e) { | |
| 50 | + let { | |
| 51 | + pageX, | |
| 52 | + pageY | |
| 53 | + } = e.changedTouches[0] | |
| 54 | + this.transition = false | |
| 55 | + this.startX = pageX | |
| 56 | + if (this.autoClose) { | |
| 57 | + this.swipeaction.closeOther(this) | |
| 58 | + } | |
| 59 | + }, | |
| 60 | + touchmove(e) { | |
| 61 | + let { | |
| 62 | + pageX, | |
| 63 | + } = e.changedTouches[0] | |
| 64 | + this.slide = this.getSlide(pageX) | |
| 65 | + if (this.slide === 0) { | |
| 66 | + this.disabledView = false | |
| 67 | + } | |
| 68 | + | |
| 69 | + }, | |
| 70 | + touchend(e) { | |
| 71 | + this.stop = false | |
| 72 | + this.transition = true | |
| 73 | + if (this.isopen) { | |
| 74 | + if (this.moveX === -this.buttonWidth) { | |
| 75 | + this.close() | |
| 76 | + return | |
| 77 | + } | |
| 78 | + this.move() | |
| 79 | + } else { | |
| 80 | + if (this.moveX === 0) { | |
| 81 | + this.close() | |
| 82 | + return | |
| 83 | + } | |
| 84 | + this.move() | |
| 85 | + } | |
| 86 | + }, | |
| 87 | + open() { | |
| 88 | + this.x = this.moveX | |
| 89 | + this.$nextTick(() => { | |
| 90 | + this.x = -this.buttonWidth | |
| 91 | + this.moveX = this.x | |
| 92 | + | |
| 93 | + if(!this.isopen){ | |
| 94 | + this.isopen = true | |
| 95 | + this.$emit('change', true) | |
| 96 | + } | |
| 97 | + }) | |
| 98 | + }, | |
| 99 | + close() { | |
| 100 | + this.x = this.moveX | |
| 101 | + this.$nextTick(() => { | |
| 102 | + this.x = 0 | |
| 103 | + this.moveX = this.x | |
| 104 | + if(this.isopen){ | |
| 105 | + this.isopen = false | |
| 106 | + this.$emit('change', false) | |
| 107 | + } | |
| 108 | + }) | |
| 109 | + }, | |
| 110 | + move() { | |
| 111 | + if (this.slide === 0) { | |
| 112 | + this.open() | |
| 113 | + } else { | |
| 114 | + this.close() | |
| 115 | + } | |
| 116 | + }, | |
| 117 | + onChange(e) { | |
| 118 | + let x = e.detail.x | |
| 119 | + this.moveX = x | |
| 120 | + if (x >= this.buttonWidth) { | |
| 121 | + this.disabledView = true | |
| 122 | + this.$nextTick(() => { | |
| 123 | + this.x = this.buttonWidth | |
| 124 | + }) | |
| 125 | + } | |
| 126 | + }, | |
| 127 | + getSlide(x) { | |
| 128 | + if (x >= this.startX) { | |
| 129 | + this.startX = x | |
| 130 | + return 1 | |
| 131 | + } else { | |
| 132 | + this.startX = x | |
| 133 | + return 0 | |
| 134 | + } | |
| 135 | + | |
| 136 | + }, | |
| 137 | + getQuerySelect() { | |
| 138 | + const query = uni.createSelectorQuery().in(this); | |
| 139 | + query.selectAll('.viewWidth-hook').boundingClientRect(data => { | |
| 140 | + | |
| 141 | + this.viewWidth = data[0].width | |
| 142 | + this.buttonWidth = data[1].width | |
| 143 | + this.transition = false | |
| 144 | + this.$nextTick(() => { | |
| 145 | + this.transition = true | |
| 146 | + }) | |
| 147 | + | |
| 148 | + if (!this.buttonWidth) { | |
| 149 | + this.disabledView = true | |
| 150 | + } | |
| 151 | + | |
| 152 | + if (this.autoClose) return | |
| 153 | + if (this.show) { | |
| 154 | + this.open() | |
| 155 | + } | |
| 156 | + }).exec(); | |
| 157 | + | |
| 158 | + } | |
| 159 | + } | |
| 160 | +} | ... | ... |
src/components/uni-swipe-action-item/mpother.js
| ... | ... | @@ -0,0 +1,158 @@ |
| 1 | +// #ifdef APP-NVUE | |
| 2 | +const dom = weex.requireModule('dom'); | |
| 3 | +// #endif | |
| 4 | +export default { | |
| 5 | + data() { | |
| 6 | + return { | |
| 7 | + uniShow: false, | |
| 8 | + left: 0 | |
| 9 | + } | |
| 10 | + }, | |
| 11 | + computed: { | |
| 12 | + moveLeft() { | |
| 13 | + return `translateX(${this.left}px)` | |
| 14 | + } | |
| 15 | + }, | |
| 16 | + watch: { | |
| 17 | + show(newVal) { | |
| 18 | + if (!this.position || JSON.stringify(this.position) === '{}') return; | |
| 19 | + if (this.autoClose) return | |
| 20 | + if (newVal) { | |
| 21 | + this.$emit('change', true) | |
| 22 | + this.open() | |
| 23 | + } else { | |
| 24 | + this.$emit('change', false) | |
| 25 | + this.close() | |
| 26 | + } | |
| 27 | + } | |
| 28 | + }, | |
| 29 | + mounted() { | |
| 30 | + this.position = {} | |
| 31 | + if (this.swipeaction.children !== undefined) { | |
| 32 | + this.swipeaction.children.push(this) | |
| 33 | + } | |
| 34 | + setTimeout(() => { | |
| 35 | + this.getSelectorQuery() | |
| 36 | + }, 100) | |
| 37 | + }, | |
| 38 | + beforeDestoy() { | |
| 39 | + this.swipeaction.children.forEach((item, index) => { | |
| 40 | + if (item === this) { | |
| 41 | + this.swipeaction.children.splice(index, 1) | |
| 42 | + } | |
| 43 | + }) | |
| 44 | + }, | |
| 45 | + methods: { | |
| 46 | + onClick(index, item) { | |
| 47 | + this.$emit('click', { | |
| 48 | + content: item, | |
| 49 | + index | |
| 50 | + }) | |
| 51 | + this.close() | |
| 52 | + }, | |
| 53 | + touchstart(e) { | |
| 54 | + const { | |
| 55 | + pageX | |
| 56 | + } = e.touches[0] | |
| 57 | + if (this.disabled) return | |
| 58 | + const left = this.position.content.left | |
| 59 | + if (this.autoClose) { | |
| 60 | + this.swipeaction.closeOther(this) | |
| 61 | + } | |
| 62 | + this.width = pageX - left | |
| 63 | + if (this.isopen) return | |
| 64 | + if (this.uniShow) { | |
| 65 | + this.uniShow = false | |
| 66 | + this.isopen = true | |
| 67 | + this.openleft = this.left + this.position.button.width | |
| 68 | + } | |
| 69 | + }, | |
| 70 | + touchmove(e, index) { | |
| 71 | + if (this.disabled) return | |
| 72 | + const { | |
| 73 | + pageX | |
| 74 | + } = e.touches[0] | |
| 75 | + this.setPosition(pageX) | |
| 76 | + }, | |
| 77 | + touchend() { | |
| 78 | + if (this.disabled) return | |
| 79 | + if (this.isopen) { | |
| 80 | + this.move(this.openleft, 0) | |
| 81 | + return | |
| 82 | + } | |
| 83 | + this.move(this.left, -40) | |
| 84 | + }, | |
| 85 | + setPosition(x, y) { | |
| 86 | + if (!this.position.button.width) { | |
| 87 | + return | |
| 88 | + } | |
| 89 | + // this.left = x - this.width | |
| 90 | + this.setValue(x - this.width) | |
| 91 | + }, | |
| 92 | + setValue(value) { | |
| 93 | + // 设置最大最小值 | |
| 94 | + this.left = Math.max(-this.position.button.width, Math.min(parseInt(value), 0)) | |
| 95 | + this.position.content.left = this.left | |
| 96 | + if (this.isopen) { | |
| 97 | + this.openleft = this.left + this.position.button.width | |
| 98 | + } | |
| 99 | + }, | |
| 100 | + move(left, value) { | |
| 101 | + if (left >= value) { | |
| 102 | + this.$emit('change', false) | |
| 103 | + this.close() | |
| 104 | + } else { | |
| 105 | + this.$emit('change', true) | |
| 106 | + this.open() | |
| 107 | + } | |
| 108 | + }, | |
| 109 | + open() { | |
| 110 | + this.uniShow = true | |
| 111 | + this.left = -this.position.button.width | |
| 112 | + this.setValue(-this.position.button.width) | |
| 113 | + }, | |
| 114 | + close() { | |
| 115 | + this.uniShow = true | |
| 116 | + this.setValue(0) | |
| 117 | + setTimeout(() => { | |
| 118 | + this.uniShow = false | |
| 119 | + this.isopen = false | |
| 120 | + }, 300) | |
| 121 | + }, | |
| 122 | + getSelectorQuery() { | |
| 123 | + // #ifndef APP-NVUE | |
| 124 | + const views = uni.createSelectorQuery() | |
| 125 | + .in(this) | |
| 126 | + views | |
| 127 | + .selectAll('.selector-query-hock') | |
| 128 | + .boundingClientRect(data => { | |
| 129 | + this.position.content = data[1] | |
| 130 | + this.position.button = data[0] | |
| 131 | + if (this.autoClose) return | |
| 132 | + if (this.show) { | |
| 133 | + this.open() | |
| 134 | + } else { | |
| 135 | + this.close() | |
| 136 | + } | |
| 137 | + }) | |
| 138 | + .exec() | |
| 139 | + // #endif | |
| 140 | + // #ifdef APP-NVUE | |
| 141 | + dom.getComponentRect(this.$refs['selector-content-hock'], (data) => { | |
| 142 | + if (this.position.content) return | |
| 143 | + this.position.content = data.size | |
| 144 | + }) | |
| 145 | + dom.getComponentRect(this.$refs['selector-button-hock'], (data) => { | |
| 146 | + if (this.position.button) return | |
| 147 | + this.position.button = data.size | |
| 148 | + if (this.autoClose) return | |
| 149 | + if (this.show) { | |
| 150 | + this.open() | |
| 151 | + } else { | |
| 152 | + this.close() | |
| 153 | + } | |
| 154 | + }) | |
| 155 | + // #endif | |
| 156 | + } | |
| 157 | + } | |
| 158 | +} | ... | ... |
src/components/uni-swipe-action-item/mpwxs.js
| ... | ... | @@ -0,0 +1,97 @@ |
| 1 | +export default { | |
| 2 | + data() { | |
| 3 | + return { | |
| 4 | + position: [], | |
| 5 | + button: [] | |
| 6 | + } | |
| 7 | + }, | |
| 8 | + computed: { | |
| 9 | + pos() { | |
| 10 | + return JSON.stringify(this.position) | |
| 11 | + }, | |
| 12 | + btn() { | |
| 13 | + return JSON.stringify(this.button) | |
| 14 | + } | |
| 15 | + }, | |
| 16 | + watch: { | |
| 17 | + show(newVal) { | |
| 18 | + if (this.autoClose) return | |
| 19 | + let valueObj = this.position[0] | |
| 20 | + if (!valueObj) { | |
| 21 | + this.init() | |
| 22 | + return | |
| 23 | + } | |
| 24 | + valueObj.show = newVal | |
| 25 | + this.$set(this.position, 0, valueObj) | |
| 26 | + } | |
| 27 | + }, | |
| 28 | + created() { | |
| 29 | + if (this.swipeaction.children !== undefined) { | |
| 30 | + this.swipeaction.children.push(this) | |
| 31 | + } | |
| 32 | + }, | |
| 33 | + mounted() { | |
| 34 | + this.init() | |
| 35 | + | |
| 36 | + }, | |
| 37 | + beforeDestroy() { | |
| 38 | + this.swipeaction.children.forEach((item, index) => { | |
| 39 | + if (item === this) { | |
| 40 | + this.swipeaction.children.splice(index, 1) | |
| 41 | + } | |
| 42 | + }) | |
| 43 | + }, | |
| 44 | + methods: { | |
| 45 | + init() { | |
| 46 | + | |
| 47 | + setTimeout(() => { | |
| 48 | + this.getSize() | |
| 49 | + this.getButtonSize() | |
| 50 | + }, 50) | |
| 51 | + }, | |
| 52 | + closeSwipe(e) { | |
| 53 | + if (!this.autoClose) return | |
| 54 | + this.swipeaction.closeOther(this) | |
| 55 | + }, | |
| 56 | + | |
| 57 | + change(e) { | |
| 58 | + this.$emit('change', e.open) | |
| 59 | + let valueObj = this.position[0] | |
| 60 | + if (valueObj.show !== e.open) { | |
| 61 | + valueObj.show = e.open | |
| 62 | + this.$set(this.position, 0, valueObj) | |
| 63 | + } | |
| 64 | + }, | |
| 65 | + onClick(index, item) { | |
| 66 | + this.$emit('click', { | |
| 67 | + content: item, | |
| 68 | + index | |
| 69 | + }) | |
| 70 | + }, | |
| 71 | + appTouchStart(){}, | |
| 72 | + appTouchEnd(){}, | |
| 73 | + getSize() { | |
| 74 | + const views = uni.createSelectorQuery().in(this) | |
| 75 | + views | |
| 76 | + .selectAll('.selector-query-hock') | |
| 77 | + .boundingClientRect(data => { | |
| 78 | + if (this.autoClose) { | |
| 79 | + data[0].show = false | |
| 80 | + } else { | |
| 81 | + data[0].show = this.show | |
| 82 | + } | |
| 83 | + this.position = data | |
| 84 | + }) | |
| 85 | + .exec() | |
| 86 | + }, | |
| 87 | + getButtonSize() { | |
| 88 | + const views = uni.createSelectorQuery().in(this) | |
| 89 | + views | |
| 90 | + .selectAll('.button-hock') | |
| 91 | + .boundingClientRect(data => { | |
| 92 | + this.button = data | |
| 93 | + }) | |
| 94 | + .exec() | |
| 95 | + } | |
| 96 | + } | |
| 97 | +} | ... | ... |
src/components/uni-swipe-action-item/uni-swipe-action-item.vue
| ... | ... | @@ -0,0 +1,270 @@ |
| 1 | +<template> | |
| 2 | + <view class="uni-swipe"> | |
| 3 | + <!-- 在微信小程序 app vue端 h5 使用wxs 实现--> | |
| 4 | + <!-- #ifdef APP-VUE || MP-WEIXIN || H5 --> | |
| 5 | + <view class="uni-swipe_content"> | |
| 6 | + <view :data-disabled="disabled" :data-position="pos" :change:prop="swipe.sizeReady" :prop="pos" class="uni-swipe_move-box selector-query-hock move-hock" | |
| 7 | + @touchstart="swipe.touchstart" @touchmove="swipe.touchmove" @touchend="swipe.touchend" @change="change"> | |
| 8 | + <view class="uni-swipe_box"> | |
| 9 | + <slot /> | |
| 10 | + </view> | |
| 11 | + <view ref="selector-button-hock" class="uni-swipe_button-group selector-query-hock move-hock"> | |
| 12 | + <!-- 使用 touchend 解决 ios 13 不触发按钮事件的问题--> | |
| 13 | + <view v-for="(item,index) in options" :data-button="btn" :key="index" :style="{ | |
| 14 | + backgroundColor: item.style && item.style.backgroundColor ? item.style.backgroundColor : '#C7C6CD', | |
| 15 | + fontSize: item.style && item.style.fontSize ? item.style.fontSize : '16px' | |
| 16 | + }" | |
| 17 | + class="uni-swipe_button button-hock" @touchend="onClick(index,item)"><text class="uni-swipe_button-text" :style="{color: item.style && item.style.color ? item.style.color : '#FFFFFF',}">{{ item.text }}</text></view> | |
| 18 | + </view> | |
| 19 | + </view> | |
| 20 | + </view> | |
| 21 | + <!-- #endif --> | |
| 22 | + | |
| 23 | + <!-- app nvue端 使用 bindingx --> | |
| 24 | + <!-- #ifdef APP-NVUE --> | |
| 25 | + <view ref="selector-box-hock" class="uni-swipe_content" @horizontalpan="touchstart" @touchend="touchend"> | |
| 26 | + <view ref="selector-button-hock" class="uni-swipe_button-group selector-query-hock move-hock" :style="{width:right+'px'}"> | |
| 27 | + <view ref="button-hock" v-for="(item,index) in options" :key="index" :style="{ | |
| 28 | + backgroundColor: item.style && item.style.backgroundColor ? item.style.backgroundColor : '#C7C6CD',left: right+'px'}" | |
| 29 | + class="uni-swipe_button " @click.stop="onClick(index,item)"><text class="uni-swipe_button-text" :style="{color: item.style && item.style.color ? item.style.color : '#FFFFFF',fontSize: item.style && item.style.fontSize ? item.style.fontSize : '16px'}">{{ item.text }}</text></view> | |
| 30 | + </view> | |
| 31 | + <view ref='selector-content-hock' class="uni-swipe_move-box selector-query-hock"> | |
| 32 | + <view class="uni-swipe_box"> | |
| 33 | + <slot /> | |
| 34 | + </view> | |
| 35 | + </view> | |
| 36 | + </view> | |
| 37 | + <!-- #endif --> | |
| 38 | + | |
| 39 | + <!-- 在非 app 端、非微信小程序、支付宝小程序、h5端使用 js --> | |
| 40 | + <!-- #ifndef APP-PLUS || MP-WEIXIN || MP-ALIPAY || H5 --> | |
| 41 | + <view class="uni-swipe_content"> | |
| 42 | + <view ref="selector-button-hock" class="uni-swipe_button-group selector-query-hock move-hock"> | |
| 43 | + <view v-for="(item,index) in options" :data-button="btn" :key="index" :style="{ | |
| 44 | + backgroundColor: item.style && item.style.backgroundColor ? item.style.backgroundColor : '#C7C6CD', | |
| 45 | + fontSize: item.style && item.style.fontSize ? item.style.fontSize : '16px' | |
| 46 | + }" | |
| 47 | + class="uni-swipe_button button-hock" @click.stop="onClick(index,item)"><text class="uni-swipe_button-text" :style="{color: item.style && item.style.color ? item.style.color : '#FFFFFF',}">{{ item.text }}</text></view> | |
| 48 | + </view> | |
| 49 | + <view ref='selector-content-hock' class="selector-query-hock" @touchstart="touchstart" @touchmove="touchmove" | |
| 50 | + @touchend="touchend" :class="{'ani':uniShow}" :style="{transform:moveLeft}"> | |
| 51 | + <view class="uni-swipe_move-box" > | |
| 52 | + <view class="uni-swipe_box"> | |
| 53 | + <slot /> | |
| 54 | + </view> | |
| 55 | + </view> | |
| 56 | + </view> | |
| 57 | + </view> | |
| 58 | + <!-- #endif --> | |
| 59 | + <!-- #ifdef MP-ALIPAY --> | |
| 60 | + <view class="uni-swipe-box" @touchstart="touchstart" @touchmove="touchmove" @touchend="touchend"> | |
| 61 | + <view class="viewWidth-hook"> | |
| 62 | + <movable-area v-if="viewWidth !== 0" class="movable-area" :style="{width:(viewWidth-buttonWidth)+'px'}"> | |
| 63 | + <movable-view class="movable-view" direction="horizontal" :animation="!transition" :style="{width:viewWidth+'px'}" | |
| 64 | + :class="[transition?'transition':'']" :x="x" :disabled="disabledView" @change="onChange"> | |
| 65 | + <view class="movable-view-box"> | |
| 66 | + <slot></slot> | |
| 67 | + </view> | |
| 68 | + </movable-view> | |
| 69 | + </movable-area> | |
| 70 | + </view> | |
| 71 | + <view ref="selector-button-hock" class="uni-swipe_button-group viewWidth-hook"> | |
| 72 | + <view v-for="(item,index) in options" :data-button="btn" :key="index" :style="{ | |
| 73 | + backgroundColor: item.style && item.style.backgroundColor ? item.style.backgroundColor : '#C7C6CD', | |
| 74 | + fontSize: item.style && item.style.fontSize ? item.style.fontSize : '16px' | |
| 75 | + }" | |
| 76 | + class="uni-swipe_button button-hock" @click.stop="onClick(index,item)"><text class="uni-swipe_button-text" :style="{color: item.style && item.style.color ? item.style.color : '#FFFFFF',}">{{ item.text }}</text></view> | |
| 77 | + </view> | |
| 78 | + </view> | |
| 79 | + <!-- #endif --> | |
| 80 | + </view> | |
| 81 | +</template> | |
| 82 | +<script src="./index.wxs" module="swipe" lang="wxs"></script> | |
| 83 | +<script> | |
| 84 | + // #ifdef APP-VUE|| MP-WEIXIN || H5 | |
| 85 | + import mpwxs from './mpwxs' | |
| 86 | + // #endif | |
| 87 | + | |
| 88 | + // #ifdef APP-NVUE | |
| 89 | + import bindingx from './bindingx.js' | |
| 90 | + // #endif | |
| 91 | + | |
| 92 | + // #ifndef APP-PLUS|| MP-WEIXIN || MP-ALIPAY || H5 | |
| 93 | + import mixins from './mpother' | |
| 94 | + // #endif | |
| 95 | + | |
| 96 | + // #ifdef MP-ALIPAY | |
| 97 | + import mpalipay from './mpalipay' | |
| 98 | + // #endif | |
| 99 | + | |
| 100 | + /** | |
| 101 | + * SwipeActionItem 滑动操作子组件 | |
| 102 | + * @description 通过滑动触发选项的容器 | |
| 103 | + * @tutorial https://ext.dcloud.net.cn/plugin?id=181 | |
| 104 | + * @property {Boolean} show = [true|false] 开启关闭组件,auto-close = false 时生效 | |
| 105 | + * @property {Boolean} disabled = [true|false] 是否禁止滑动 | |
| 106 | + * @property {Boolean} autoClose = [true|false] 其他组件开启的时候,当前组件是否自动关闭 | |
| 107 | + * @property {Array} options 组件选项内容及样式 | |
| 108 | + * @event {Function} click 点击选项按钮时触发事件,e = {content,index} ,content(点击内容)、index(下标) | |
| 109 | + * @event {Function} change 组件打开或关闭时触发,true:开启状态;false:关闭状态 | |
| 110 | + */ | |
| 111 | + | |
| 112 | + export default { | |
| 113 | + // #ifdef APP-VUE|| MP-WEIXIN||H5 | |
| 114 | + mixins: [mpwxs], | |
| 115 | + // #endif | |
| 116 | + | |
| 117 | + // #ifdef APP-NVUE | |
| 118 | + mixins: [bindingx], | |
| 119 | + // #endif | |
| 120 | + | |
| 121 | + // #ifndef APP-PLUS|| MP-WEIXIN || MP-ALIPAY || H5 | |
| 122 | + mixins: [mixins], | |
| 123 | + // #endif | |
| 124 | + | |
| 125 | + // #ifdef MP-ALIPAY | |
| 126 | + mixins: [mpalipay], | |
| 127 | + // #endif | |
| 128 | + | |
| 129 | + props: { | |
| 130 | + /** | |
| 131 | + * 按钮内容 | |
| 132 | + */ | |
| 133 | + options: { | |
| 134 | + type: Array, | |
| 135 | + default () { | |
| 136 | + return [] | |
| 137 | + } | |
| 138 | + }, | |
| 139 | + /** | |
| 140 | + * 禁用 | |
| 141 | + */ | |
| 142 | + disabled: { | |
| 143 | + type: Boolean, | |
| 144 | + default: false | |
| 145 | + }, | |
| 146 | + /** | |
| 147 | + * 变量控制开关 | |
| 148 | + */ | |
| 149 | + show: { | |
| 150 | + type: Boolean, | |
| 151 | + default: false | |
| 152 | + }, | |
| 153 | + /** | |
| 154 | + * 是否自动关闭 | |
| 155 | + */ | |
| 156 | + autoClose: { | |
| 157 | + type: Boolean, | |
| 158 | + default: true | |
| 159 | + } | |
| 160 | + }, | |
| 161 | + inject: ['swipeaction'] | |
| 162 | + | |
| 163 | + | |
| 164 | + } | |
| 165 | +</script> | |
| 166 | +<style lang="scss" scoped> | |
| 167 | + .uni-swipe { | |
| 168 | + overflow: hidden; | |
| 169 | + } | |
| 170 | + | |
| 171 | + .uni-swipe-box { | |
| 172 | + position: relative; | |
| 173 | + width: 100%; | |
| 174 | + } | |
| 175 | + | |
| 176 | + .uni-swipe_content { | |
| 177 | + flex: 1; | |
| 178 | + position: relative; | |
| 179 | + } | |
| 180 | + | |
| 181 | + .uni-swipe_move-box { | |
| 182 | + /* #ifndef APP-NVUE */ | |
| < |