uniapp+vue move-view 拖拽滑动效果组件
uniapp自身提供了movable-area/movable-view标签实现拖拽滑动效果,但是实际开发中发现,此标签跟滚动效果有冲突,会影响内部列表的滚动效果,基于此,所以单独封装了两种模式的滑动组件。
·
uniapp自身提供了movable-area/movable-view标签实现拖拽滑动效果,但是实际开发中发现,此标签跟滚动效果有冲突,会影响内部列表的滚动效果,基于此,所以单独封装了两种模式的滑动组件。
定位+TOP
<move-view :min-height="55" @change="moveChange">
<view id="move_view_tag"></view>
</move-view
<!--
* @Description: 实现方式:通过absolute+top偏移的方式
* (效果微有瑕疵,如果top默认是0,实现效果又需要在底部展示的话,页面初始化时会出现闪现的现象,
* 解决方式:初始top值写大一点,比如屏高或1080等)
* 特别说明:未做兼容处理,可根据具体实现再次优化组件交互等。
-->
<template>
<view
class="h-full move-view"
:style="'top: '+ top + 'px'"
@touchstart.stop="touchStart"
@touchend.stop="touchEnd"
@touchmove.stop="touchMove"
>
<slot />
</view>
</template>
<script>
export default {
props: {
minHeight: {
type: Number,
default: 20,
},
},
data() {
return {
startY: 0,
top: 1080,
winHeight: 750,
initTop: 0,
moveViewTagHeight: 0,
};
},
mounted() {
this.winHeight = uni.getSystemInfoSync().windowHeight;
// 获取初始的偏移量
const query = uni.createSelectorQuery().in(this);
query.select('#move_view_tag').boundingClientRect((data) => {
this.moveViewTagHeight = data.height;
this.initTop = this.winHeight - data.height;
this.top = this.initTop;
}).exec();
},
methods: {
touchStart(e) {
this.startY = e.touches[0].clientY;
},
touchMove(e) {
const nowY = e.touches[0].clientY;
this.top = nowY;
if (this.top <= this.initTop) {
this.top = this.initTop;
} else if (this.top >= this.winHeight - this.minHeight) {
this.top = this.winHeight - this.minHeight;
}
this.$emit('change', this.top, nowY - this.startY);
},
touchEnd() {
const dif = this.winHeight - (this.moveViewTagHeight / 2);
if (this.top >= dif) {
this.top = this.winHeight - this.minHeight;
} else {
this.top = this.initTop;
}
this.$emit('touchEnd', this.top);
},
},
};
</script>
<style scoped lang="scss">
.move-view {
position: absolute;
left: 0;
right: 0;
bottom: 0;
z-index: 9 !important;
}
</style>
定位+translateY
<moveable-view :y="initY" @change="movableChange" @touchEnd="touchEnd">
<view>你的内容</view>
</moveable-view>
<!--
* @Description: 实现方式:模拟moveable-area/moveable-view的方式,外层固定盒子,内层通过translateY偏移实现效果。
* 说明:基本是模拟uniapp movable-area/movable-view 的交互方式,尽量保持组件的纯净性和单一性。
-->
<template>
<view class="moveable-content">
<view
class="moveable-view"
:style="style"
@touchstart.stop="touchStart"
@touchend.stop="touchEnd"
@touchmove.stop="touchMove"
>
<slot />
</view>
</view>
</template>
<script>
export default {
props: {
y: {
type: Number,
default: null,
},
},
data() {
return {
style: {
transform: 'translateX(0px) translateY(0px) translateZ(0px) scale(1)',
},
query: null,
moveBoxHei: 10,
moveViewHei: 10,
translateY: 0,
};
},
watch: {
y: {
handler(nv) {
this.translateY = nv;
this.style = {
transform: `translateX(0px) translateY(${nv}px) translateZ(0px) scale(1)`,
};
},
deep: true,
immediate: true,
},
},
mounted() {
/**
* 如果是纯vue或H5的项目,应该不需要用以下获取dom的方式,因为框架自动转换的原因,
* 实际渲染后的像素值跟设定的是有区别的,所以需要动态获取以下高度。
* (比如:高度100px,浏览器渲染结果可能是98px,真机就可能是120px...)
*/
this.query = uni.createSelectorQuery().in(this);
setTimeout(() => {
this.query.select('.moveable-content').boundingClientRect((data) => {
this.moveBoxHei = data.height;
}).exec();
this.query.select('.moveable-view').boundingClientRect((data) => {
this.moveViewHei = data.height;
}).exec();
}, 500);
},
methods: {
touchStart(e) {
this.startY = e.touches[0].clientY;
},
touchMove(e) {
const moveY = Math.floor(e.touches[0].clientY - this.startY);
const transY = this.translateY + moveY;
const limit = -(this.moveViewHei - this.moveBoxHei);
// 偏移限定量,超出向上的最大值后,便不在移动
if (limit >= transY) {
this.style = {
transform: `translateX(0px) translateY(${limit}px) translateZ(0px) scale(1)`,
};
// 返回当前偏移量
this.$emit('change', limit);
return;
}
// eslint-disable-next-line no-nested-ternary
const y = transY >= 0 ? 0 : transY;
this.style = {
transform: `translateX(0px) translateY(${y}px) translateZ(0px) scale(1)`,
};
// 返回当前偏移量
this.$emit('change', y);
},
touchEnd() {
// 返回最大偏移量,父界面有可能会用到(比如超过分界值,直接展开)
this.$emit('touchEnd', -(this.moveViewHei - this.moveBoxHei));
},
},
};
</script>
<style scoped lang="scss">
.moveable-content {
position: relative;
width: 100%;
height: 100%;
background: #fff;
min-height: 10px;
min-width: 10px;
}
.moveable-view {
width: 100%;
background: #fff;
transform-origin: center center;
will-change: auto;
}
</style>
更多推荐
已为社区贡献4条内容
所有评论(0)