1
This commit is contained in:
@@ -0,0 +1,670 @@
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<!-- @vue-docgen-ignore-next-line -->
|
||||
<script module="xfs" lang="wxs" src="./xfs.wxs"></script>
|
||||
<!-- #endif -->
|
||||
<script lang="ts">
|
||||
import { getUid, checkIsCssUnit } from '../../core/util/xCoreUtil.uts'
|
||||
import { getDefaultColor } from '../../core/util/xCoreColorUtil.uts'
|
||||
import { SlotsType } from 'vue'
|
||||
import { xConfig } from "../../config/xConfig.uts"
|
||||
|
||||
type POSITION_TYPE_XY = {
|
||||
x : number,
|
||||
y : number
|
||||
}
|
||||
|
||||
/**
|
||||
* @name 左滑菜单 xSwitchSlider
|
||||
* @description 常用于对话聊天,订单列表等一些隐藏式按钮设计场景。如果子菜单无法定宽或者被挤夺请写style:flex-shrink: 0;避免。
|
||||
* @page /pages/index/switch-slider
|
||||
* @category 反馈组件
|
||||
* @constant 平台兼容
|
||||
* | Harmony | H5 | andriod | IOS | 小程序 | UTS | UNIAPP-X SDK | version |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
| ☑ | ☑ | ☑️ | ☑️ | ☑️ | ☑️ | 4.76+ | 1.1.18 |
|
||||
*/
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
opened: false,
|
||||
startX: 0,
|
||||
startY: 0,
|
||||
slideX: 0,
|
||||
_x: 0,
|
||||
_y: 0,
|
||||
_tempPop_x:0,
|
||||
_tempPop_y:0,
|
||||
dirs: "right",
|
||||
id: "xSwitchSilder" + getUid(),
|
||||
idMenuRight: "xSwitchSilderItems" + getUid(),
|
||||
isMove: false,
|
||||
dateTime: 0,
|
||||
diffX: 0,
|
||||
isSwiper:'none'
|
||||
}
|
||||
},
|
||||
emits: [
|
||||
/**
|
||||
* 提供这个函数是因为如果你把此组件套在了scroll中
|
||||
* 你在ios端根本 无法去阻止 底部的scrollview的滚动,这大概官方是解决不了的
|
||||
* 冒泡 事件。我只能绕开。
|
||||
* 此函数会发现是否禁用你外部滚动的指示。
|
||||
*/
|
||||
"disabledScrollChange",
|
||||
/**
|
||||
* 活动区域被点击时触发。
|
||||
*/
|
||||
"click",
|
||||
/**
|
||||
* 打开菜单时触发
|
||||
*/
|
||||
"open",
|
||||
/**
|
||||
* 关闭时触发
|
||||
*/
|
||||
"close",
|
||||
/**
|
||||
* 触摸开始
|
||||
*/
|
||||
"start",
|
||||
/**
|
||||
* 触摸结束
|
||||
*/
|
||||
"end",
|
||||
/**
|
||||
* 触摸中
|
||||
*/
|
||||
"move",
|
||||
/**
|
||||
* 等同v-model:status
|
||||
*/
|
||||
"update:status"
|
||||
],
|
||||
slots: Object as SlotsType<{
|
||||
default : {
|
||||
status : boolean
|
||||
},
|
||||
menu : {
|
||||
status : boolean
|
||||
}
|
||||
}>,
|
||||
props: {
|
||||
|
||||
/**
|
||||
* 被拖动层的自定义样式
|
||||
*/
|
||||
custonmStyle: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
/**
|
||||
* 菜单容器层自定义样式
|
||||
*/
|
||||
custonmMenuStyle: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
/**
|
||||
* 宽度
|
||||
*/
|
||||
width: {
|
||||
type: String,
|
||||
default: "100%"
|
||||
},
|
||||
/**
|
||||
* 高度,单位随意
|
||||
*/
|
||||
height: {
|
||||
type: String,
|
||||
default: "50"
|
||||
},
|
||||
/**
|
||||
* 是否禁用
|
||||
*/
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
/**
|
||||
* 当滑动时小于此值,会回弹到原位。
|
||||
*/
|
||||
threshold: {
|
||||
type: Number,
|
||||
default: 15
|
||||
},
|
||||
/**
|
||||
* 当打开或者松开时的动画时间
|
||||
*/
|
||||
duration: {
|
||||
type: Number,
|
||||
default: 450
|
||||
},
|
||||
/**
|
||||
* 当前打开状态
|
||||
*/
|
||||
status: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
/**
|
||||
* 下边线的颜色
|
||||
*/
|
||||
borderColor:{
|
||||
type:String,
|
||||
default:"#f5f5f5"
|
||||
},
|
||||
/**
|
||||
* 下边线暗黑的颜色,如果不提供,取全局borderDarkColor
|
||||
*/
|
||||
borderDarkColor:{
|
||||
type:String,
|
||||
default:""
|
||||
},
|
||||
/**
|
||||
* 让拖动层内容失去响应,会导致顶层里面的内容无法触发事件响应
|
||||
* 但好处是:拖动更流畅,没有断断续续。请自行根据场景打开和关闭。
|
||||
* false关闭让内容响应事件,true让内容失去响应。
|
||||
*/
|
||||
eventNone:{
|
||||
type:Boolean,
|
||||
default:true
|
||||
}
|
||||
|
||||
},
|
||||
computed: {
|
||||
_height() : string {
|
||||
return checkIsCssUnit(this.height, xConfig.unit)
|
||||
},
|
||||
_disabled() : boolean {
|
||||
return this.disabled
|
||||
},
|
||||
_custonmStyle() : string {
|
||||
return this.custonmStyle
|
||||
},
|
||||
_custonmMenuStyle() : string {
|
||||
return this.custonmStyle
|
||||
},
|
||||
|
||||
_borderColor() : string {
|
||||
if (xConfig.dark == 'dark'&&this.borderDarkColor=='') return getDefaultColor(xConfig.borderDarkColor)
|
||||
if (xConfig.dark == 'dark'&&this.borderDarkColor!='') return getDefaultColor(this.borderDarkColor)
|
||||
return getDefaultColor(this.borderColor)
|
||||
},
|
||||
_animationFun() : string {
|
||||
return xConfig.animationFun
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
status(newval : boolean) {
|
||||
if (newval == this.opened) return;
|
||||
if (this.status) {
|
||||
this.open()
|
||||
} else {
|
||||
this.close()
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
|
||||
this.getNodeInfo();
|
||||
},
|
||||
methods: {
|
||||
// #ifdef MP-WEIXIN
|
||||
setOpts(opts){
|
||||
if(opts?.isMove!=null){
|
||||
this.isMove = opts.isMove;
|
||||
}
|
||||
if(opts?.opened!=null){
|
||||
this.opened = opts.opened;
|
||||
}
|
||||
if(opts?.isSwiper!=null){
|
||||
this.isSwiper = opts.isSwiper;
|
||||
}
|
||||
|
||||
},
|
||||
callEmits(args){
|
||||
if(!args.name) return;
|
||||
if(args.args!=null&&args.args!=undefined){
|
||||
this.$emit(args.name,args.args)
|
||||
}else{
|
||||
this.$emit(args.name)
|
||||
if(args.name=='open'|| args.name=='close'){
|
||||
this.$emit("update:status", args.name=='open')
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
// #endif
|
||||
resetMoveData() {
|
||||
this.startX = 0;
|
||||
this.startY = 0;
|
||||
let ele = this.$refs['xSwitchSilder'] as UniElement
|
||||
ele.style.setProperty("transition-duration", '0ms')
|
||||
},
|
||||
getNodeInfo() {
|
||||
uni.createSelectorQuery().in(this)
|
||||
.select(".xSwitchSilderItems")
|
||||
.boundingClientRect().exec((ret) => {
|
||||
let el = uni.getElementById(this.id as string) as UniElement|null
|
||||
let nodeinfo = ret[0] as NodeInfo
|
||||
let width = nodeinfo.width as number
|
||||
if (this.status&&el!=null) {
|
||||
this.opened = false;
|
||||
this.dirs = "left"
|
||||
el.style.setProperty("transition-duration", this.duration.toString() + 'ms')
|
||||
el.style.setProperty("left", '-' + width.toString() + 'px')
|
||||
this.slideX = -width;
|
||||
}
|
||||
})
|
||||
},
|
||||
getMenuRightwidth() : number {
|
||||
let idMenuRight = this.$refs['xSwitchSilderItems'] as UniElement
|
||||
let menurightWidth = idMenuRight.getBoundingClientRect().width;
|
||||
return menurightWidth
|
||||
},
|
||||
eventTransform_start(evt : POSITION_TYPE_XY) {
|
||||
this.diffX = 0
|
||||
this.dateTime = new Date().getTime()
|
||||
this.resetMoveData();
|
||||
if (this._disabled) return;
|
||||
this.startX = evt.x - this.slideX;
|
||||
this._x = evt.x
|
||||
this._y = evt.y
|
||||
this.startY = evt.y;
|
||||
this.isMove = true;
|
||||
},
|
||||
eventTransform_move(evt : POSITION_TYPE_XY) {
|
||||
let el = this.$refs['xSwitchSilder'] as UniElement|null;
|
||||
if(el==null) return;
|
||||
let x = evt.x - this.startX;
|
||||
let realleftdom = el.style.getPropertyValue("left") as string | null
|
||||
let leftpos = parseInt(realleftdom == null ? '0' : realleftdom)
|
||||
if (isNaN(leftpos)) {
|
||||
leftpos = 0
|
||||
}
|
||||
let menuwidth = this.getMenuRightwidth()
|
||||
let diffX = evt.x - this._x;
|
||||
this._x = evt.x
|
||||
|
||||
if (leftpos > 0) {
|
||||
x = 0
|
||||
} else if (leftpos < -menuwidth) {
|
||||
x = -menuwidth
|
||||
}
|
||||
|
||||
x = Math.min(0, x)
|
||||
x = Math.max(-menuwidth, x)
|
||||
|
||||
this.slideX = x;
|
||||
|
||||
if (Math.abs(x) > this.threshold) {
|
||||
if (diffX > 0) {
|
||||
this.dirs = "right"
|
||||
} else {
|
||||
this.dirs = "left"
|
||||
}
|
||||
}
|
||||
if (leftpos >= -menuwidth && leftpos <= 0 && Math.abs(diffX) > 0) {
|
||||
el.style.setProperty("left", x + 'px')
|
||||
}
|
||||
this.diffX = diffX;
|
||||
},
|
||||
mStart(evt : UniTouchEvent) {
|
||||
/**
|
||||
* 触发时触发
|
||||
*/
|
||||
this.$emit("start")
|
||||
this.dateTime = Date.now()
|
||||
let event = evt.changedTouches[0];
|
||||
this._tempPop_x = event.clientX
|
||||
this._tempPop_y = event.clientY
|
||||
this.resetMoveData();
|
||||
if (this._disabled) return;
|
||||
this.isMove = true;
|
||||
this.isSwiper = 'none';
|
||||
this.eventTransform_start({ x: event.clientX, y: event.clientY } as POSITION_TYPE_XY)
|
||||
},
|
||||
mMove(evt : UniTouchEvent) {
|
||||
/**
|
||||
* 触摸中时触发
|
||||
*/
|
||||
this.$emit("move")
|
||||
let event = evt.changedTouches[0]
|
||||
if (this._disabled) return;
|
||||
|
||||
// 如果y距离大于x距离就允许滑动页面,否则左滑组件。
|
||||
let y = Math.abs(event.clientY - this._tempPop_y)
|
||||
let x = Math.abs(event.clientX - this._tempPop_x)
|
||||
// 判断是否有明显的方向
|
||||
const hasDirection = Math.max(x, y) > 10
|
||||
// 判断是否为水平方向
|
||||
const isHorizontal = x > y
|
||||
|
||||
if (hasDirection && this.isSwiper == 'none') {
|
||||
if (isHorizontal) {
|
||||
// 水平滑动,启用左滑并阻止页面滚动
|
||||
this.isSwiper = 'swiper'
|
||||
evt.preventDefault()
|
||||
evt.stopPropagation()
|
||||
} else {
|
||||
// 垂直滑动,禁用左滑
|
||||
this.isSwiper = 'off'
|
||||
}
|
||||
}
|
||||
|
||||
// 只有在启用左滑状态下才执行滑动
|
||||
if (this.isSwiper == 'swiper') {
|
||||
this.eventTransform_move({ x: event.clientX, y: event.clientY } as POSITION_TYPE_XY)
|
||||
}
|
||||
},
|
||||
mEnd(evt : UniTouchEvent) {
|
||||
|
||||
/**
|
||||
* 触摸结束时触发
|
||||
*/
|
||||
this.$emit("end")
|
||||
let diffdate = Date.now() -this.dateTime
|
||||
let diffx = evt.changedTouches[0].clientX - this._tempPop_x
|
||||
let diffy = evt.changedTouches[0].clientY - this._tempPop_y
|
||||
if(Math.abs(diffx) == Math.abs(diffy) && diffx==0 && diffdate>50&&diffdate<=250){
|
||||
this.mClick()
|
||||
}
|
||||
|
||||
|
||||
let el = this.$refs['xSwitchSilder'] as UniElement | null;
|
||||
let idMenuRight = this.$refs['xSwitchSilderItems'] as UniElement|null
|
||||
if(el==null||idMenuRight==null) return;
|
||||
this.isMove = false;
|
||||
if (this._disabled||this.isSwiper=='off'){
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
let menuwidth = idMenuRight.getBoundingClientRect().width
|
||||
el.style.setProperty("transition-duration", this.duration.toString() + 'ms')
|
||||
if (this.dirs == 'left') {
|
||||
|
||||
this.slideX = -menuwidth;
|
||||
el.style.setProperty("left", (-menuwidth).toString() + 'px')
|
||||
this.opened = true;
|
||||
/**
|
||||
* 打开菜单时触发
|
||||
*/
|
||||
this.$emit("open")
|
||||
|
||||
} else if (this.dirs == 'right') {
|
||||
el.style.setProperty("left", '0px')
|
||||
this.slideX = 0
|
||||
this.opened = false;
|
||||
/**
|
||||
* 关闭时触发
|
||||
*/
|
||||
this.$emit("close")
|
||||
}
|
||||
},
|
||||
onAniEnd() {
|
||||
// #ifdef APP||WEB
|
||||
if (this.dirs == 'left') {
|
||||
/** 等同v-model:status **/
|
||||
this.$emit("update:status", true)
|
||||
this.isMove = false;
|
||||
}
|
||||
if (this.dirs == 'right') {
|
||||
/** 等同v-model:status **/
|
||||
this.$emit("update:status", false)
|
||||
this.isMove = false;
|
||||
}
|
||||
// #endif
|
||||
},
|
||||
mClick() {
|
||||
|
||||
/**
|
||||
* 活动区域被点击时触发。
|
||||
*/
|
||||
this.$emit("click")
|
||||
},
|
||||
// #ifdef WEB
|
||||
mmStart(evt : UniMouseEvent) {
|
||||
window.xSwitchSliderId = this.id
|
||||
/**
|
||||
* 触发时触发
|
||||
*/
|
||||
this.$emit("start")
|
||||
|
||||
this.dateTime = Date.now()
|
||||
this.resetMoveData();
|
||||
this._tempPop_x = evt.clientX;
|
||||
this._tempPop_y = evt.clientY;
|
||||
if (this._disabled) return;
|
||||
this.isSwiper = 'none';
|
||||
this.isMove = true;
|
||||
this.eventTransform_start({ x: evt.clientX, y: evt.clientY } as POSITION_TYPE_XY)
|
||||
},
|
||||
mmMove(evt : UniMouseEvent) {
|
||||
if(window.xSwitchSliderId != this.id) return;
|
||||
/**
|
||||
* 触摸中时触发
|
||||
*/
|
||||
this.$emit("move")
|
||||
if (this._disabled||!this.isMove) return;
|
||||
|
||||
// 如果y距离大于x距离就允许滑动页面,否则左滑组件。
|
||||
let y = Math.abs(evt.clientY - this._tempPop_y)
|
||||
let x = Math.abs(evt.clientX - this._tempPop_x)
|
||||
// 判断是否有明显的方向
|
||||
const hasDirection = Math.max(x, y) > 10
|
||||
// 判断是否为水平方向
|
||||
const isHorizontal = x > y
|
||||
|
||||
if (hasDirection && this.isSwiper == 'none') {
|
||||
if (isHorizontal) {
|
||||
// 水平滑动,启用左滑并阻止页面滚动
|
||||
this.isSwiper = 'swiper'
|
||||
evt.preventDefault()
|
||||
evt.stopPropagation()
|
||||
|
||||
} else {
|
||||
// 垂直滑动,禁用左滑
|
||||
this.isSwiper = 'off'
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isSwiper == 'swiper') {
|
||||
this.eventTransform_move({ x: evt.clientX, y: evt.clientY } as POSITION_TYPE_XY)
|
||||
}
|
||||
},
|
||||
mmEnd(evt:UniMouseEvent) {
|
||||
if(window.xSwitchSliderId != this.id||!this.isMove) return;
|
||||
/**
|
||||
* 触摸结束时触发
|
||||
*/
|
||||
this.$emit("end")
|
||||
let diffdate = Date.now() -this.dateTime
|
||||
let diffx = evt.clientX - this._tempPop_x
|
||||
let diffy = evt.clientY - this._tempPop_y
|
||||
if(Math.abs(diffx) == Math.abs(diffy) && diffx==0 && diffdate>50&&diffdate<=250){
|
||||
this.mClick()
|
||||
}
|
||||
|
||||
let el = this.$refs['xSwitchSilder'] as UniElement
|
||||
let idMenuRight = this.$refs['xSwitchSilderItems'] as UniElement
|
||||
this.isMove = false;
|
||||
|
||||
if (this._disabled||this.isSwiper == 'off') return;
|
||||
|
||||
let menuwidth = idMenuRight!.getBoundingClientRect().width
|
||||
el!.style.setProperty("transition-duration", this.duration.toString() + 'ms')
|
||||
if (this.dirs == 'left') {
|
||||
|
||||
this.slideX = -menuwidth;
|
||||
el!.style.setProperty("left", (-menuwidth).toString() + 'px')
|
||||
this.opened = true;
|
||||
/**
|
||||
* 打开菜单时触发
|
||||
*/
|
||||
this.$emit("open")
|
||||
|
||||
} else if (this.dirs == 'right') {
|
||||
el!.style.setProperty("left", '0px')
|
||||
this.slideX = 0
|
||||
this.opened = false;
|
||||
/**
|
||||
* 关闭时触发
|
||||
*/
|
||||
this.$emit("close")
|
||||
}
|
||||
},
|
||||
// #endif
|
||||
/**
|
||||
* 打开
|
||||
* @public
|
||||
*/
|
||||
open() {
|
||||
this.opened = true;
|
||||
this.dirs = "left"
|
||||
// #ifdef APP||WEB
|
||||
let menuwidth = this.getMenuRightwidth()
|
||||
let el = this.$refs['xSwitchSilder'] as UniElement|null;
|
||||
if(el==null) return;
|
||||
el.style.setProperty("transition-duration", this.duration.toString() + 'ms')
|
||||
el.style.setProperty("left", '-' + menuwidth.toString() + 'px')
|
||||
this.slideX = -menuwidth;
|
||||
// #endif
|
||||
},
|
||||
/**
|
||||
* 关闭
|
||||
* @public
|
||||
*/
|
||||
close() {
|
||||
this.opened = false;
|
||||
this.dirs = "right"
|
||||
|
||||
// #ifdef APP||WEB
|
||||
let el = this.$refs['xSwitchSilder'] as UniElement|null;
|
||||
if(el!=null){
|
||||
el.style.setProperty("transition-duration", this.duration.toString() + 'ms')
|
||||
el.style.setProperty("left", '0px')
|
||||
}
|
||||
// #endif
|
||||
this.slideX = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<view>
|
||||
<view
|
||||
class="xSwitchSilder" :style="{minHeight:_height}">
|
||||
<view
|
||||
|
||||
|
||||
<!-- #ifdef APP||WEB -->
|
||||
@touchstart="mStart"
|
||||
@touchmove="mMove"
|
||||
@touchend="mEnd"
|
||||
@touchcancel="mEnd"
|
||||
<!-- #endif -->
|
||||
|
||||
|
||||
<!-- #ifdef WEB -->
|
||||
@mousedown="mmStart"
|
||||
@mousemove="mmMove"
|
||||
@mouseup="mmEnd"
|
||||
@mouseleave="mmEnd"
|
||||
<!-- #endif -->
|
||||
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
@touchstart="xfs.mStart"
|
||||
@touchmove="xfs.mMove"
|
||||
@touchend="xfs.mEnd"
|
||||
@touchcancel="xfs.mEnd"
|
||||
:data-opts="{
|
||||
disabled:_disabled,
|
||||
slideX:slideX,
|
||||
duration:duration,
|
||||
animationFun:_animationFun,
|
||||
opened:opened,
|
||||
threshold:threshold
|
||||
}"
|
||||
:change:prop="xfs.propObserver"
|
||||
:prop="opened"
|
||||
<!-- #endif -->
|
||||
|
||||
:id="id" ref="xSwitchSilder"
|
||||
:style="[{'transition-timing-function':_animationFun},_custonmStyle]"
|
||||
class="xSwitchSilderWrap "
|
||||
@transitionend="onAniEnd">
|
||||
<view :class="[eventNone?'noEventBySwitchSlider':'']" class="" style="width: 100%;height: 100%;">
|
||||
<!--
|
||||
@slot 默认插槽,你的顶层布局可以在这里。 由于vue 的diff机制,去掉5ms的延迟。内容层会失去事件响应。请通过组件的@click
|
||||
-->
|
||||
<slot></slot>
|
||||
</view>
|
||||
</view>
|
||||
<view class="xSwitchSilderItemsWrap">
|
||||
<view ref="xSwitchSilderItems" :id="idMenuRight" class="xSwitchSilderItems" :style="_custonmMenuStyle">
|
||||
<!--
|
||||
@slot 菜单插槽
|
||||
@prop {boolean} status - 当前打开的状态
|
||||
-->
|
||||
<slot name="menu" :status="opened"></slot>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view :style="{backgroundColor:_borderColor,height:'1px'}"></view>
|
||||
</view>
|
||||
</template>
|
||||
<style>
|
||||
.noEventBySwitchSlider {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.xSwitchSilder {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
/* #ifdef WEB */
|
||||
cursor: grab;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
/* #ifdef WEB */
|
||||
.xSwitchSilder:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
.xSwitchSilderWrap {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 2;
|
||||
right: 0px;
|
||||
transition-property: left;
|
||||
transition-duration: 0ms;
|
||||
}
|
||||
|
||||
.xSwitchSilderItemsWrap {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.xSwitchSilderItems {
|
||||
flex-shrink: 0;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
/* #ifdef WEB */
|
||||
cursor: pointer;
|
||||
/* #endif */
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,167 @@
|
||||
var _x = 0
|
||||
var _realx = 0
|
||||
var _y = 0
|
||||
var isMoving = false
|
||||
var leftPos = 0
|
||||
var menuwidth = 0
|
||||
var opts = {
|
||||
disabled: false,
|
||||
slideX:0,
|
||||
duration:0,
|
||||
animationFun:"cubic-bezier(.42,.38,.15,.93)",
|
||||
threshold:10,
|
||||
opened:false
|
||||
}
|
||||
var dirs = "right"
|
||||
var newDirs = "right"
|
||||
var dateTime = 0
|
||||
var isSwiper = 'none';
|
||||
var _diff_x = 0
|
||||
|
||||
function mStart(evt, ins) {
|
||||
ins.callMethod('callEmits', {name:"start"})
|
||||
dateTime = Date.now()
|
||||
_realx = evt.changedTouches[0].clientX;
|
||||
_diff_x = evt.changedTouches[0].clientX;
|
||||
var ele = ins.selectComponent('.xSwitchSilderWrap')
|
||||
var itemMenuele = ins.selectComponent('.xSwitchSilderItems')
|
||||
menuwidth = itemMenuele.getBoundingClientRect().width
|
||||
opts = ele.getDataset().opts;
|
||||
if (opts.disabled) return false;
|
||||
leftPos = parseFloat(ele.getComputedStyle(['left']).left)
|
||||
dirs = opts.opened ? "left" : "right"
|
||||
newDirs = dirs
|
||||
ele.setStyle({
|
||||
'left': leftPos + 'px',
|
||||
'transition-duration':'0ms',
|
||||
'transition-timing-function':opts.animationFun
|
||||
})
|
||||
|
||||
_x = evt.changedTouches[0].clientX - leftPos;
|
||||
_y = evt.changedTouches[0].clientY;
|
||||
isMoving = true
|
||||
isSwiper = 'none';
|
||||
ins.callMethod('setOpts', {
|
||||
isMove: isMoving,
|
||||
isSwiper:isSwiper
|
||||
})
|
||||
|
||||
z}
|
||||
|
||||
function mMove(evt, ins) {
|
||||
ins.callMethod('callEmits', {name:"move"})
|
||||
var ele = ins.selectComponent('.xSwitchSilderWrap')
|
||||
if (opts.disabled) return true;
|
||||
var x = evt.changedTouches[0].clientX - _x
|
||||
var dreal_iff_x = evt.changedTouches[0].clientX - _diff_x
|
||||
var diffx = Math.abs(evt.changedTouches[0].clientX - _realx)
|
||||
var diffy = Math.abs(evt.changedTouches[0].clientY - _y)
|
||||
// 判断是否有明显的方向
|
||||
var hasDirection = Math.max(diffx, diffy) > 10
|
||||
// 判断是否为水平方向
|
||||
var isHorizontal = diffx > diffy
|
||||
if(hasDirection && isSwiper == 'none'){
|
||||
if (isHorizontal) {
|
||||
// 水平滑动,启用左滑并阻止页面滚动
|
||||
isSwiper = 'swiper'
|
||||
// evt.preventDefault()
|
||||
// evt.stopPropagation()
|
||||
} else {
|
||||
// 垂直滑动,禁用左滑
|
||||
isSwiper = 'off'
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ins.callMethod('setOpts', {
|
||||
isSwiper:isSwiper
|
||||
})
|
||||
|
||||
if(isSwiper == 'swiper'){
|
||||
x = Math.min(0, x)
|
||||
x = Math.max(-menuwidth, x)
|
||||
|
||||
ele.setStyle({
|
||||
'left': x + 'px'
|
||||
})
|
||||
|
||||
if (Math.abs(x) > opts.threshold) {
|
||||
|
||||
if (dreal_iff_x > 0) {
|
||||
newDirs = "right"
|
||||
} else {
|
||||
newDirs = "left"
|
||||
}
|
||||
}
|
||||
|
||||
_diff_x = evt.changedTouches[0].clientX
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function mEnd(evt, ins) {
|
||||
ins.callMethod('callEmits', {name:"end"})
|
||||
|
||||
var diffdate = Date.now() - dateTime
|
||||
var diffx = evt.changedTouches[0].clientX - _realx
|
||||
var diffy = evt.changedTouches[0].clientY - _y
|
||||
if(Math.abs(diffx) == Math.abs(diffy) && diffx==0 && diffdate>50&&diffdate<=250){
|
||||
ins.callMethod('callEmits', {name:"click"})
|
||||
}
|
||||
if (opts.disabled || isSwiper=='off') return false;
|
||||
var ele = ins.selectComponent('.xSwitchSilderWrap')
|
||||
var event = evt.changedTouches[0];
|
||||
|
||||
var diffX = evt.changedTouches[0].clientX - _realx
|
||||
|
||||
var x = 0;
|
||||
if(newDirs == 'left'){
|
||||
x = -menuwidth
|
||||
}
|
||||
|
||||
ele.setStyle({
|
||||
'left': x + 'px',
|
||||
'transition-duration':opts.duration+'ms',
|
||||
'transition-timing-function':opts.animationFun
|
||||
})
|
||||
if(diffX==0||dirs == newDirs){
|
||||
return;
|
||||
}
|
||||
dirs = newDirs
|
||||
var opened = x>=0?false:true
|
||||
ins.callMethod('setOpts', {
|
||||
isMove: isMoving,
|
||||
isSwiper:isSwiper,
|
||||
opened:opened
|
||||
})
|
||||
if(opts.opened!=opened){
|
||||
ins.callMethod('callEmits', {name:opened?'open':"close"})
|
||||
}
|
||||
|
||||
opts.opened = opened
|
||||
}
|
||||
function setTatus(status,instance){
|
||||
var ele = instance.selectComponent('.xSwitchSilderWrap')
|
||||
var itemMenuele = instance.selectComponent('.xSwitchSilderItems')
|
||||
menuwidth = itemMenuele.getBoundingClientRect().width
|
||||
var x = opts.opened?-menuwidth:0
|
||||
ele.setStyle({
|
||||
'left': x + 'px',
|
||||
'transition-duration':opts.duration+'ms',
|
||||
'transition-timing-function':opts.animationFun
|
||||
})
|
||||
}
|
||||
module.exports = {
|
||||
mStart: mStart,
|
||||
mMove: mMove,
|
||||
mEnd: mEnd,
|
||||
propObserver: function(newValue, oldValue, ownerInstance, instance) {
|
||||
var ele = ownerInstance.selectComponent('.xSwitchSilderWrap')
|
||||
opts = ele.getDataset().opts;
|
||||
if(newValue!=undefined&&oldValue!=undefined&&newValue!=oldValue){
|
||||
setTatus(newValue,ownerInstance)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user