123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- <template>
- <view
- v-if="show"
- :class="[
- 'cl-popup__wrapper',
- `cl-popup__wrapper--${direction}`,
- `is-${status ? 'open' : 'close'}`
- ]"
- @touchmove.stop.prevent
- >
- <view class="cl-popup__modal" @tap="modalClose" v-if="modal"></view>
- <view
- :class="['cl-popup']"
- :style="{ height, width, backgroundColor, borderRadius: parseRpx(borderRadius) }"
- >
- <view class="cl-popup__container" :style="{ padding: parseRpx(padding) }">
- <slot></slot>
- </view>
- </view>
- </view>
- </template>
- <script>
- import { parseRpx } from "../../utils";
- /**
- * popup 弹出框
- * @description 支持各方向的弹出框
- * @tutorial https://docs.cool-js.com/uni/components/view/popup.html
- * @property {Boolean} visible 是否可见
- * @property {Function} beforeClose 关闭前钩子函数
- * @property {String} direction 弹出方向, top | right | bottom | left | center,默认left
- * @property {Boolean} closeOnClickModal 点击遮罩层是否关闭,默认true
- * @property {String, Number} size 弹出框大小,默认auto
- * @property {String} backgroundColor 背景颜色,默认#fff
- * @property {String, Number} borderRadius 内容圆角
- * @property {String, Number} padding 内容内间据,默认20
- * @property {Boolean} modal 是否显示遮罩层
- * @example <cl-popup :visible.sync="visible">Hello !</cl-popup>
- */
- export default {
- name: "cl-popup",
- props: {
- // 是否可见
- visible: Boolean,
- // 关闭前钩子函数
- beforeClose: Function,
- // 弹出方向
- direction: {
- type: String,
- default: "left"
- },
- // 点击遮罩层是否关闭
- closeOnClickModal: {
- type: Boolean,
- default: true
- },
- // 弹出框大小
- size: {
- type: [String, Number],
- default: "auto"
- },
- // 背景颜色
- backgroundColor: {
- type: String,
- default: "#fff"
- },
- // 内容圆角
- borderRadius: [String, Number],
- // 内容内间据
- padding: {
- type: [String, Number],
- default: 20
- },
- // 是否显示遮罩层
- modal: {
- type: Boolean,
- default: true
- }
- },
- data() {
- return {
- show: false,
- status: false,
- timer: null
- };
- },
- computed: {
- height() {
- switch (this.direction) {
- case "top":
- case "bottom":
- return parseRpx(this.size);
- case "left":
- case "right":
- return "100%";
- }
- },
- width() {
- switch (this.direction) {
- case "top":
- case "bottom":
- return "100%";
- case "left":
- case "right":
- case "center":
- return parseRpx(this.size);
- }
- }
- },
- watch: {
- visible: {
- immediate: true,
- handler(val) {
- if (val) {
- this.open();
- } else {
- this.close();
- }
- }
- }
- },
- methods: {
- parseRpx,
- open() {
- if (!this.show) {
- // 显示内容
- this.show = true;
- this.$emit("update:visible", true);
- this.$emit("open");
- clearTimeout(this.timer);
- this.timer = setTimeout(() => {
- // 开始动画
- this.status = true;
- // 等待动画结束
- this.timer = setTimeout(() => {
- this.$emit("opened");
- }, 350);
- }, 50);
- }
- },
- close() {
- if (this.status) {
- const done = () => {
- // 关闭动画
- this.status = false;
- this.$emit("close");
- clearTimeout(this.timer);
- this.timer = setTimeout(() => {
- // 隐藏内容
- this.show = false;
- this.$emit("update:visible", false);
- this.$emit("closed");
- }, 300);
- };
- if (this.beforeClose) {
- this.beforeClose(done);
- } else {
- done();
- }
- }
- },
- modalClose() {
- if (!this.closeOnClickModal) {
- return false;
- }
- this.close();
- }
- }
- };
- </script>
|