123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- <template>
- <view
- :class="['cl-list-item', isAppend, isDisabled, isBorder]"
- :style="[customStyle]"
- @touchstart="onTouchStart"
- @touchmove="onTouchMove"
- @touchend="onTouchEnd"
- @tap.stop="onTap"
- >
- <view
- class="cl-list-item__swiper"
- :style="{
- transform: translateX,
- }"
- >
- <view class="cl-list-item__container">
- <view class="cl-list-item__icon" v-if="$slots.icon">
- <slot name="icon"></slot>
- </view>
- <text class="cl-list-item__label" v-if="label && label != 'true'">{{ label }}</text>
- <view :class="['cl-list-item__content', isJustify, isColor]">
- <slot></slot>
- </view>
- <view class="cl-list-item__append">
- <slot name="append"></slot>
- </view>
- </view>
- <template v-if="swipe != 'none'">
- <view :class="[`cl-list-item__menu-${swipe}`]">
- <slot name="menu"></slot>
- </view>
- </template>
- </view>
- </view>
- </template>
- <script>
- import Parent from "../../mixins/parent";
- /**
- * list-item 列表项
- * @description 列表项,自定义内容,支持滑动
- * @tutorial https://docs.cool-js.com/uni/components/layout/list.html
- * @property {String} label 标签内容
- * @property {Boolean} disabled 是否禁用
- * @property {Boolean} border 是否带有下边框,默认true
- * @property {Boolean} type 类型 primary | success | error | warning | info
- * @property {Boolean} justify 水平布局方式,默认end
- * @property {Boolean} swipe 是否滑动 none | left | right,默认none
- * @event {Function} tap 点击时触发
- * @example 见教程
- */
- export default {
- name: "cl-list-item",
- componentName: "ClListItem",
- props: {
- // 标签内容
- label: String,
- // 是否禁用
- disabled: Boolean,
- // 是否带有下边框
- border: {
- type: Boolean,
- default: null,
- },
- // 类型 primary | success | error | warning | info
- type: String,
- // 水平布局方式
- justify: {
- type: String,
- default: "end",
- },
- // 是否滑动 none | left | right
- swipe: {
- type: String,
- default: "none",
- validator: (val) => {
- return ["none", "left", "right"].indexOf(val) !== -1;
- },
- },
- // 自定义样式
- customStyle: Object,
- },
- mixins: [Parent],
- data() {
- return {
- touch: {
- start: 0,
- end: 0,
- x: 0,
- maxX: 0,
- direction: "left",
- lock: true,
- },
- menu: {
- width: 0,
- },
- Keys: ["disabled", "justify", "border"],
- ComponentName: "ClList",
- };
- },
- computed: {
- isColor() {
- return this.type ? `is-color-${this.type}` : "";
- },
- isBorder() {
- if (this.border === null) {
- if (this.parent.border === true) {
- return `is-border`;
- }
- }
- return this.border ? "is-border" : "";
- },
- isJustify() {
- return (this.parent.justify || this.justify) !== "start"
- ? `is-justify-${this.justify}`
- : "";
- },
- isAppend() {
- return this.$slots.append ? "cl-list-item--append" : "";
- },
- isDisabled() {
- return this.parent.disabled || this.disabled ? "cl-list-item--disabled" : "";
- },
- translateX() {
- return `translateX(${this.touch.x}px)`;
- },
- },
- watch: {
- swipe() {
- this.setMenu();
- },
- },
- mounted() {
- this.setMenu();
- },
- methods: {
- onTap(e) {
- this.$emit("click", e);
- this.$emit("tap", e);
- },
- onTouchStart(e) {
- if (this.swipe != "none") {
- this.touch.start = e.touches[0].pageX;
- this.touch.lock = false;
- }
- },
- onTouchMove(e) {
- const { start, end, lock, maxX } = this.touch;
- if (!lock) {
- // 滑动距离
- let offsetX = e.touches[0].pageX - start;
- // 移动方向
- this.touch.direction = offsetX > 0 ? "right" : "left";
- // 偏移距离
- let x = end + offsetX;
- if (this.swipe == "left") {
- if (x > maxX) {
- x = maxX;
- }
- if (x < 0) {
- x = 0;
- }
- }
- if (this.swipe == "right") {
- if (x < maxX) {
- x = maxX;
- }
- if (x > 0) {
- x = 0;
- }
- }
- this.touch.x = x;
- }
- },
- onTouchEnd() {
- const { direction, x, end, lock, maxX } = this.touch;
- if (!lock) {
- if (Math.abs(x - end) > 50) {
- if (direction === this.swipe) {
- this.touch.x = 0;
- } else {
- this.touch.x = maxX;
- }
- this.touch.end = this.touch.x;
- } else {
- this.touch.x = end === 0 ? 0 : maxX;
- }
- this.touch.lock = true;
- }
- },
- // 设置菜单宽度
- setMenu() {
- if (this.swipe != "none") {
- const query = uni.createSelectorQuery().in(this);
- query
- .select(`.cl-list-item__menu-${this.swipe}`)
- .boundingClientRect((data) => {
- if (data) {
- this.menu.width = data.width;
- this.touch.maxX = this.menu.width * (this.swipe === "right" ? -1 : 1);
- }
- })
- .exec();
- }
- },
- // 滑动后还原位置的方法
- restore(callback) {
- this.touch.start = 0;
- this.touch.end = 0;
- this.touch.lock = true;
- this.touch.x = 0;
- if (callback) {
- setTimeout(() => {
- callback();
- }, 300);
- }
- },
- },
- };
- </script>
|