zoukankan      html  css  js  c++  java
  • vue登录页作为modal全局使用

    背景

    vue项目,有一个登录页面作为单独页面来使用。想要将其改造成 一个modal,然后全局可调用。类似于 mint-ui 的 toast组件这样。

    要用到的位置主要是:vue页面内、接口请求的响应数据处理方法内(环境是 无法拿到当前作用域 this)

    实现原理

    将登陆页面modal封装成一个 插件。

    主要代码

    1、登录页组件:

    正常书写,主要是提供一个组件广播事件 this.$emit('on-logged')。在 登录完成后 通知调用者,做一些操作。

    <template>
      <mt-popup v-model="showValue" :modal="showModal" popup-transition="popup-fade" class="mint-popup-modal">
        <div class="zyby-container box-sizing-border">
          <mt-header>
            <by-back slot="left" :specialBack="_hide"></by-back>
          </mt-header>
          <div class="welcome-block">欢迎登录八音!</div>
          <div class="input-block">
            <mt-field
              class="none-border"
              placeholder="手机号"
              type="tel"
              v-model="pm.telephone"
              :attr="{ maxlength: 11 }"
            ></mt-field>
            <mt-field placeholder="验证码" type="tel" v-model="pm.code" :attr="{ maxlength: 6 }">
              <count-down
                ref="countDown"
                class="count-down"
                :getcodebefore="_getCode"
                :model="codeData.model"
              >
                <span slot="secUnit">s</span>
              </count-down>
            </mt-field>
    
    
          </div>
          <!--<div class="interpretation">完成“八音App”登录注册以便后续奖励发放</div>-->
          <mt-button
            class="login-block"
            :class="classObject"
            type="primary"
            size="large"
            :disabled="!loginFlag"
            @click="_goLogin"
          >登录</mt-button>
    
          <div class="tip-block">未注册用户登录代表已同意注册</div>
        </div>
      </mt-popup>
    </template>
    <script>
      import { CountDown } from "vue-zyby-ui";
      import { addMinutes, format} from 'date-fns'
      import { sendCode, login } from "@/api/index.js";
      import { cellPhoneValidate, numberValidate } from "@/libs/stringUtil.js";
      import { LOCALDATA } from '@/libs/constans.js'
      import storage from '@/libs/storage.js'
      import { commonValidate } from '@/libs/validateUtil.js'
      import config from '@/config'
    
      export default {
        name: "Login",
    
        components: {
          CountDown
        },
        data() {
          return {
            codeData: {
              showCountDown: false,
              model: "validateCode"
            },
            pm: {
              telephone: null,
              code: null,
            },
            showValue: false,
            showModal: false
          };
        },
        mounted() {
          document.querySelectorAll("input").forEach(item => {
            item.addEventListener("blur", function() {
              window.scroll(0, 0);
            });
          });
        },
        computed: {
          classObject: function() {
            return {
              "login-block-active": this.pm.telephone && this.pm.code
            };
          },
          loginFlag: function() {
            return this.pm.telephone && this.pm.code;
          }
        },
        props: {
          value: {
            type: Boolean,
            default: false
          },
        },
        watch: {
          value (val) {
            this.showValue = val
          },
          showValue (val) {
            /*this.$emit('input', val)
            if (val) {
              if (this.showInput) {
                this.msg = ''
                setTimeout(() => {
                  if (this.$refs.input) {
                    this.setInputFocus()
                  }
                }, 300)
              }
              this.$emit('on-show') // emit just after msg is cleared
            }*/
          }
        },
        methods: {
          _getCode() {
            if (this._validatePhone()) {
              this.$refs.countDown.setEnd(format(addMinutes(new Date(), 1), 'YYYY/MM/DD HH:mm:ss'))
              return sendCode(this.pm.telephone);
            }
          },
          _validatePhone() {
            const validateData = [
              { '请输入联系方式': !this.pm.telephone },
              { '请输入正确的手机号': !cellPhoneValidate(this.pm.telephone) }
            ]
            return commonValidate(validateData)
          },
          _goLogin() {
    
            if (!this._validatePhone()) { return false }
            const validateData = [
              { '请输入验证码': !this.pm.code },
              { '请输入正确的验证码': (this.pm.code.length != 6 || !numberValidate(this.pm.code)) },
            ]
            if (commonValidate(validateData)) {
              login(this.pm).then(res => {
                // 设置登录标志
                let user = {
                  telephone: this.pm.telephone,
                  token: res.token,
                  uuid: config.uuid,
                  id: res.id
                }
                storage.setToken(user)
                this.showValue = false
                this.$emit('on-logged')
              })
    
            }
          },
          _hide () {
            this.showValue = false
          }
        },
      };
    </script>
    <style scoped lang="less" rel="stylesheet/less">
      @import "../assets/css/function.less";
    
      @no-left-padding: {
        padding-left: 0;
      };
      @border-bottom-style: {
        border-bottom: 1px solid #d3dfef; /*no*/
      };
      .input-text(@opacity: 0.45) {
        font-family: PingFangSC-Regular;
        font-size: 28px;
        color: rgba(75, 84, 97, @opacity);
      }
      .interpretation{
         100%;
        background-color: #EEFAF8;
        height: 52px;
        line-height: 52px;
        font-size: 24px;
        color: #009F8A;
        text-align: center;
        margin-top: 30px;
        margin-bottom: 180px;
      }
      .mint-header {
        @no-left-padding();
      }
      .zyby-container {
        padding-top: 88px;
        position: relative;
        height: 100%;
        background-color: #fff;
      }
      .welcome-block {
        font-family: PingFangSC-Semibold;
        font-size: 50px;
        color: rgba(62, 74, 89, 0.75);
        letter-spacing: 2px; /*no*/
        text-align: left;
        line-height: 50px;
        margin-top: 56px;
      }
      .input-block {
        margin-top: 108px;
        /*margin-bottom: 211px;*/
        @border-bottom-style();
        /deep/ .mint-cell-wrapper {
          padding-left: 0;
        }
        .none-border /deep/ .mint-cell-wrapper {
          background: none;
        }
        .mint-field:first-child {
          @border-bottom-style();
        }
        /deep/ input::-webkit-input-placeholder {
          .input-text();
        }
        .count-down {
          .input-text();
          border-left: 1px solid rgba(75, 84, 97, 0.45); /*no*/
          margin-left: 40px;
          padding-left: 10px;
          /deep/ .code-text {
            color: rgba(75, 84, 97, 0.45);
          }
          /deep/ .code-count-down {
            color: rgba(75, 84, 97, 0.8);
          }
        }
      }
      .tip-block {
        opacity: 0.75;
        font-family: PingFangSC-Regular;
        font-size: 22px;
        color: rgba(75, 84, 97, 0.45);
        line-height: 22px;
        margin-top: 100px;
        text-align: center;
      }
      .login-block {
        margin-top: 220px;
        background-color: rgba(0, 0, 0, 0.1);
        height: 100px;
        border-radius: 12px; /*no*/
        font-family: PingFangSC-Medium;
        font-size: 32px;
        color: #ffffff;
        letter-spacing: 3px; /*no*/
        text-align: center;
        line-height: 32px;
      }
      .login-block-active {
        background-color: #3ad29f;
      }
    </style>

    2、设置为插件的入口

    将组件打包成为一个插件,在此处进行。

    关键操作有:

    1、暴露install方法:Vue.use用到

    2、设置为全局属性,可基于vue实例 直接调用:vue.mixin

    3、声明全局 对于登录modal的调用方法:主要有 show、hide、isVisible

    4、事件接收:在登录组件里 ,完成登录后我们会发出一个广播事件,也是在这里面 来监听该事件,$vm.$on('on-logged'

    // plugins/login/index.js

    import LoginComponent from '@/components/Login'
    import { mergeOptions } from '@/libs/plugin_helper'
    
    let $vm
    
    const plugin = {
      install (vue, options = {}) {
        const Login = vue.extend(LoginComponent)
    
        if (!$vm) {
          $vm = new Login({
            el: document.createElement('div')
          })
          document.body.appendChild($vm.$el)
        }
    
        const login = {
          show (options) {
            if (typeof options === 'object') {
              mergeOptions($vm, options)
            }
            if (typeof options === 'object' && (options.onShow || options.onHide)) {
              options.onShow && options.onShow()
            }
            this.$watcher && this.$watcher()
            this.$watcher = $vm.$watch('showValue', (val) => {
              if (!val && options && options.onHide) {
                options.onHide()
              }
            })
            $vm.$off('on-logged')
    
            $vm.$on('on-logged', msg => {
              options && options.onLogged && options.onLogged(msg)
            })
            $vm.showValue = true
          },
          /*setInputValue (val) {
            vue.nextTick(() => {
              setTimeout(() => {
                $vm.setInputValue(val)
              }, 10)
            })
          },*/
          hide () {
            $vm.showValue = false
          },
          isVisible () {
            return $vm.showValue
          }
        }
    
        // all Vux's plugins are included in this.$vux
       /* if (!vue.$vux) {
          vue.$vux = {
            login
          }
        } else {
          vue.$vux.login = login
        }
    */
        vue.mixin({  
          created: function () {
            this.$login = login
          }
        })
      }
    }
    
    export default plugin
    export const install = plugin.install

    // plugin_helper.js

    import objectAssign from 'object-assign'
    
    const mergeOptions = function ($vm, options) {
      const defaults = {}
      for (let i in $vm.$options.props) {
        if (i !== 'value') {
          defaults[i] = $vm.$options.props[i].default
        }
      }
      const _options = objectAssign({}, defaults, options)
      for (let i in _options) {
        $vm[i] = _options[i]
      }
    }
    
    export {
      mergeOptions
    }

    使用

    1、安装登录modal插件.

    // main.js

    import loginPlugin from '@/plugins/Login'
    // 注意 由于登录组件里,用到了别的一些组件,所以 use 应该在 最下面,即保证 用到的组件已存在
    Vue.use(loginPlugin)

    2、使用

    普通页面里:

    this.$login.show({
                onLogged: () => this.reload() // 登录完成后的回调方法
              })

    其他位置(无法容易拿到 vue this):

    window.$vue = new Vue({ // 将vue实例 绑定到 window
        el: '#app',
        router,
        components: { App },
        template: '<App/>'
      })
    
    window.$vue.$login.show(); // 基于window 来使用
  • 相关阅读:
    带着萌新看springboot源码
    学习springboot
    第一次来博客园
    第2章 排版样式
    第1章 Bootstrap介绍
    tab左右箭头切换
    $()下的常用方法2
    前端性能优化----yahoo前端性能团队总结的35条黄金定律
    tab
    $()下的常用方法
  • 原文地址:https://www.cnblogs.com/fan-zha/p/11213123.html
Copyright © 2011-2022 走看看