Lenny-Hu / note

blog
5 stars 1 forks source link

vue自定义常用简单组件 #88

Open Lenny-Hu opened 4 years ago

Lenny-Hu commented 4 years ago

模态框相关

css

@mixin full-screen ($position: fixed) {
  display: block;
  width: 100%;
  height: 100%;
  position: $position;
  z-index: 990;
  left: 0;
  top: 0;
  bottom: 0;
  right: 0;
}

// 简单对话框,仅包含基本结构
@mixin m-dialog {
  .m-dialog-box {
    @include full-screen;
    z-index: 1000;
    overflow-y: auto;
  }

  .m-dialog-inner {
    margin: 20px auto 20px;
    width: 600px;
    min-height: 150px;
    background-color: #fff;
    border-radius: 10px;
    overflow: hidden;
  }

  .m-dialog-header {
    position: relative;
    height: 55px;
    line-height: 55px;
    text-align: center;
    color: #333;
    font-size: 24px;
    border-bottom-right-radius: 0;
    border-bottom-left-radius: 0;
    letter-spacing: 2px;
    border-bottom: 1px solid #ddd;

    .close {
      position: absolute;
      width: 26px;
      height: 22px;
      top: 0;
      right: 14px;
      cursor: pointer;
      margin: 0;
      color: #999;
    }
  }

  .m-dialog-body {
    padding: 10px;
  }

  .m-dialog-footer {
    padding: 25px 10px;

    .btn {
      & + .btn {
        margin-left: 50px;
      }

      &.disabled {
        cursor: auto;
        opacity: 0.5;
      }
    }
  }

  body.m-dialog-open {
    overflow: hidden;
    padding-right: 16px;

    @keyframes dialogFadeIn
    {
      from {
        opacity: 0;
      }
      to {
        opacity: 1;
      }
    }

    &::after {
      @include full-screen;
      content: '';
      background: rgba(0, 0, 0, .5);
      animation: dialogFadeIn .5s 1;
    }
  }
}

// loading
@mixin m-loading {
  .m-loading-box {
    @include full-screen;
    z-index: 9999;
    background: rgba(0, 0, 0, .5);
    overflow-y: hidden;
  }

  .m-loading-inner {
    position: absolute;
    top: 50%;
    margin-top: -57px;
    margin-left: -57px;
    left: 50%;
    width: 64px;
    height: 64px;
    padding: 15px;
    background-color: #fff;
    border-radius: 10px;
    overflow: hidden;
  }

  .m-loading-body {
    img {
      width: 32px;
      height: 32px;
    }

    .text {
      margin-top: 10px;
      color: #999;
    }
  }
}

js

Vue.component('m-dialog', {
  props: {
    value: {
      type: Boolean,
      default: false
    },
    title: {
      type: String,
      default: ''
    },
    btnText: {
      type: String,
      default: '关闭'
    },
    showHeader: {
      type: Boolean,
      default: true
    },
    showFooter: {
      type: Boolean,
      default: true
    },
    className: {
      type: String,
      default: ''
    }
  },
  template: '<div class="m-dialog-box" :class="className" v-if="show">' +
    '<div class="m-dialog-inner">' +
      '<div class="m-dialog-header" v-if="showHeader">' +
        '<h4>{{title}}</h4>' +
        '<span class="close" @click="close">x</span>' +
      '</div>' +
      '<div class="m-dialog-body">' +
        '<slot></slot>' +
      '</div>' +
      '<div class="m-dialog-footer f-tac" v-if="showFooter">' +
        '<a href="" class="btn" @click.prevent="close" v-if="!$slots.footer">{{btnText}}</a>' +
        '<slot name="footer"></slot>' +
      '</div>' +
    '</div>' +
  '</div>',
  data: function () {
    return {
    };
  },
  computed: {
    show: function () {
      var eventName = this.value ? 'open' : 'close';
      this.toggleClass();
      this.$emit(eventName);
      return this.value;
    }
  },
  methods: {
    close: function () {
      this.$emit('input', false);
    },
    toggleClass: function () {
      this.$nextTick(function () {
        var $body = $(document.body);
        var count = $body.data('dialog-count') || 0;

        if (this.value) {
          count++;
          $body.addClass('m-dialog-open').data('dialog-count', count);
        } else {
          count && count--;
          if (count <= 0) {
            $body.removeClass('m-dialog-open');
          }
          $body.data('dialog-count', count);
        }
      });
    }
  },
  created: function () {
  }
});

// loading
(function () {
  var ModuleLoading = Vue.extend({
    template: '<div class="m-loading-box" v-if="visible">' +
    '<div class="m-loading-inner">' +
      '<div class="m-loading-body f-tac">' +
        '<img src="/dianping/www/images/common/load.gif" />' +
        '<div class="text f-toe" v-if="loadingText">{{loadingText}}</div>' +
      '</div>' +
    '</div>' +
  '</div>',
    data: function () {
      return {
        visible: false,
        loadingText: ''
      }
    },
    methods: {
      show: function (text) {
        this.loadingText = text || '加载中...';
        this.visible = true;
      },
      close: function () {
        this.visible = false;
        this.loadingText = '';
      }
    }
  });

  var loadingPlugin = {
    install: function (Vue) {
      Vue.prototype.$loading = (function () {
        var instance = new ModuleLoading();
        instance.vm = instance.$mount();

        document.body.appendChild(instance.vm.$el);
        return instance.vm;
      })();
    }
  };

  $(function () {
    Vue.use(loadingPlugin);
  });
})();

使用

<!-- 提示框 -->
    <m-dialog class="dialog-alert f-tac" :class-name="alertType" :show-footer="false" v-model="showAlert">
      <table class="f-vam">
        <tr>
          <td v-html="alertText">
          </td>
        </tr>
      </table>
      <button class="btn-action" @click.prevent="showAlert = false">确&nbsp;认</button>
    </m-dialog>