123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- <template>
- <movable-area class="fs-swipe-box">
- <movable-view
- v-if="state.swipeViewWidth"
- class="fs-swipe-view"
- @change="change"
- @touchend="touchend"
- @touchstart="touchstart"
- direction="horizontal"
- :disabled="disabled"
- :x="state.moveX"
- :style="{ width: state.swipeViewWidth }"
- >
- <view class="fs-swipe-content"><slot></slot></view>
- <view
- class="fs-swipe-option"
- v-for="(item, index) in options"
- :key="index"
- :style="{ backgroundColor: item.bgColor }"
- @click="handleOption(item)"
- >
- <view class="fs-swipe-option-text" :style="{ width: optionWidth + 'px', backgroundColor: item.bgColor }">
- {{ item.name }}
- </view>
- </view>
- </movable-view>
- </movable-area>
- </template>
- <script>
- /**
- * 滑动面板组件
- * @description 滑动面板组件
- * @property {Array} options 操作选项
- * @property {null} optionData 操作选项数据
- * @property {Number} optionWidth 操作选项宽度(单位px)
- * @property {Boolean} disabled 操作选项数据
- * @property {Number} swipeRate 滑动比例阈值,大于此值会自动打开或关闭
- */
- export default {
- name: 'fs-swipe-action'
- }
- </script>
- <script setup>
- import { inject, onMounted, reactive, ref, nextTick, getCurrentInstance } from 'vue'
- const props = defineProps({
- disabled: Boolean,
- optionWidth: {
- type: Number,
- default: 80
- },
- options: {
- type: Array,
- default: () => []
- },
- optionData: null,
- swipeRate: {
- type: Number,
- default: 1 / 4
- }
- })
- const emits = defineEmits(['clickOption'])
- const state = reactive({
- moveX: 0,
- scrollX: 0,
- swipeViewWidth: 0,
- status: false,
- moving: false,
- allOptionWidth: props.optionWidth * props.options.length
- })
- const swipeGroup = inject('swipeGroup', {})
- const updateState = () => {
- if (state.moving) {
- state.moving = false
- } else {
- state.moveX = 0
- }
- }
- swipeGroup.updateChildren({
- updateState
- })
- onMounted(() => {
- uni
- .createSelectorQuery()
- .in(getCurrentInstance().ctx)
- .select('.fs-swipe-box')
- .boundingClientRect(data => {
- state.swipeViewWidth = data.width + state.allOptionWidth + 'px'
- })
- .exec()
- })
- function change(e) {
- state.scrollX = e.detail.x
- }
- function touchstart() {
- state.moving = true
- swipeGroup.toggle()
- }
- function touchend() {
- state.moveX = state.scrollX
- setTimeout(() => {
- if (state.status) {
- //打开状态
- if (state.moveX >= -state.allOptionWidth * (1 - Number(props.swipeRate))) {
- handleClose()
- } else {
- handleOpen()
- }
- } else {
- if (state.moveX <= -state.allOptionWidth * Number(props.swipeRate)) {
- handleOpen()
- } else {
- handleClose()
- }
- }
- }, 0)
- }
- function handleOpen() {
- state.moveX = -state.allOptionWidth
- state.status = true
- }
- function handleClose() {
- state.moveX = 0
- state.status = false
- }
- function handleOption(item) {
- emits('clickOption', { option: item, data: props.optionData })
- handleClose()
- }
- </script>
- <style lang="scss" scoped>
- .fs-swipe-box {
- width: auto;
- height: auto;
- overflow: hidden;
- position: relative;
- }
- .fs-swipe-view {
- display: flex;
- position: relative;
- height: inherit;
- width: 100%;
- }
- .fs-swipe-content {
- flex: 1;
- }
- .fs-swipe-option {
- display: flex;
- justify-content: center;
- align-items: center;
- text-align: center;
- color: #fff;
- }
- </style>
|