美文网首页vue3Vuevue
【vue3.0】10.0 某东到家(十)——Toast弹窗和代码

【vue3.0】10.0 某东到家(十)——Toast弹窗和代码

作者: bobokaka | 来源:发表于2021-07-18 16:06 被阅读0次

    全局的功能组件——自定义弹窗组件

    新建src\components\Toast\Toast.vue:

    <template
      ><div class="toast">{{message}}</div>
      >
    </template>
    
    <script>
    export default {
      name: 'Toast',
      props: { message: { type: String } }
    }
    </script>
    
    <style lang="scss" scoped>
    .toast {
      position: fixed;
      left: 50%;
      top: 50%;
      transform: translate(-50%, -50%); //垂直水平居中
      padding: 0.1rem;
      background: rgba(0, 0, 0, 0.35);
      border-radius: 0.05rem;
      color: #fff;
    }
    </style>
    

    修改src\views\login\Login.vue:

    <template>
      <div class="wrapper">
        <img class="wrapper__img" src="/i18n/9_16/img/user.png" />
        <div class="wrapper__input">
          <input
            class="wrapper__input__content"
            placeholder="请输入手机号码"
            v-model="data.formInfo.username"
          />
        </div>
        <div class="wrapper__input">
          <input
            type="password"
            class="wrapper__input__content"
            placeholder="请输入密码"
            v-model="data.formInfo.password"
          />
        </div>
        <div class="wrapper__login-button" @click="handleLogin">登陆</div>
        <div class="wrapper__login__item">
          <div class="wrapper__login__item__link" @click="handleRegisterClick">
            立即注册
          </div>
          <p class="wrapper__login__item__cut">|</p>
          <div class="wrapper__login__item__password">忘记密码</div>
        </div>
        <Toast v-if="data.toast.show" :message="data.toast.message" />
      </div>
    </template>
    
    <script>
    import { reactive } from 'vue'
    // 路由跳转方法
    import { useRouter } from 'vue-router'
    
    import { post } from '@/utils/request'
    import Toast from '@/components/Toast/Toast'
    export default {
      name: 'Login',
      components: { Toast },
      setup () {
        const data = reactive({
          formInfo: {
            username: '',
            password: ''
          },
          toast: {
            show: false,
            message: ''
          }
        })
    
        const toastMsg = message => {
          data.toast.show = true
          data.toast.message = message
          setTimeout(() => {
            data.toast.show = false
            data.toast.message = ''
          }, 2000)
        }
        // 获取路由实例
        const router = useRouter()
        // 登录按钮
        const handleLogin = async () => {
          try {
            const resultData = await post('/111/api/user/login', {
              username: data.formInfo.username,
              password: data.formInfo.password
            })
            // console.log(result)
            if (resultData?.code === 200) {
              localStorage.isLogin = true
              router.push({ name: 'Home' })
            } else {
              toastMsg('登陆失败!')
            }
          } catch (e) {
            toastMsg('请求失败!')
          }
        }
        const handleRegisterClick = () => {
          router.push({ name: 'Register' })
        }
        return { data, handleLogin, handleRegisterClick }
      }
    }
    </script>
    ......
    

    代码拆分

    从上面的代码来看 ,实际上来看还是比较难阅读的。
    改进src\views\login\Login.vue:

    <template>
      <div class="wrapper">
        <img class="wrapper__img" src="/i18n/9_16/img/user.png" />
        <div class="wrapper__input">
          <input
            class="wrapper__input__content"
            placeholder="请输入手机号码"
            v-model="data.formInfo.username"
          />
        </div>
        <div class="wrapper__input">
          <input
            type="password"
            class="wrapper__input__content"
            placeholder="请输入密码"
            v-model="data.formInfo.password"
          />
        </div>
        <div class="wrapper__login-button" @click="handleLogin">登陆</div>
        <div class="wrapper__login__item">
          <div class="wrapper__login__item__link" @click="handleRegisterClick">
            立即注册
          </div>
          <p class="wrapper__login__item__cut">|</p>
          <div class="wrapper__login__item__password">忘记密码</div>
        </div>
        <Toast v-if="toastData.show" :message="toastData.message" />
      </div>
    </template>
    
    <script>
    import { reactive } from 'vue'
    // 路由跳转方法
    import { useRouter } from 'vue-router'
    
    import { post } from '@/utils/request'
    import Toast from '@/components/Toast/Toast'
    
    /**
     * toast相关的逻辑
     */
    const useToastEffect = () => {
      const toastData = reactive({
        show: false,
        message: ''
      })
      const toastMsg = message => {
        toastData.show = true
        toastData.message = message
        setTimeout(() => {
          toastData.show = false
          toastData.message = ''
        }, 2000)
      }
    
      return { toastData, toastMsg }
    }
    
    export default {
      name: 'Login',
      components: { Toast },
      setup () {
        // 获取路由实例
        const router = useRouter()
        const data = reactive({
          formInfo: {
            username: '',
            password: ''
          }
        })
    
        const { toastData, toastMsg } = useToastEffect()
        /** *************** 主流程中需要做的事情 *******************/
        // 登录按钮
        const handleLogin = async () => {
          try {
            const resultData = await post('/111/api/user/login', {
              username: data.formInfo.username,
              password: data.formInfo.password
            })
            // console.log(result)
            if (resultData?.code === 200) {
              localStorage.isLogin = true
              router.push({ name: 'Home' })
            } else {
              toastMsg('登陆失败!')
            }
          } catch (e) {
            toastMsg('请求失败!')
          }
        }
        const handleRegisterClick = () => {
          router.push({ name: 'Register' })
        }
        return { toastData, data, handleLogin, handleRegisterClick }
      }
    }
    </script>
    

    现在我们的toast弹窗专门封装出来的代码其实在每个使用弹窗的地方都需要使用,那么我们可以进一步封装到src\components\Toast\Toast.vue

    <template
      ><div class="toast">{{ message }}</div>
      >
    </template>
    
    <script>
    import { reactive } from 'vue'
    export default {
      name: 'Toast',
      props: { message: { type: String } }
    }
    /**
     * toast相关的逻辑
     */
    export const useToastEffect = () => {
      const toastData = reactive({
        show: false,
        message: ''
      })
      const toastMsg = (message, time) => {
        toastData.show = true
        toastData.message = message || ''
        setTimeout(() => {
          toastData.show = false
          toastData.message = ''
        }, time || 2000)
      }
    
      return { toastData, toastMsg }
    }
    </script>
    
    <style lang="scss" scoped>
    .toast {
      position: fixed;
      left: 50%;
      top: 50%;
      transform: translate(-50%, -50%); //垂直水平居中
      padding: 0.1rem;
      background: rgba(0, 0, 0, 0.35);
      border-radius: 0.05rem;
      color: #fff;
    }
    </style>
    
    

    怎么引入,调整src\views\login\Login.vue:

    <template>
      <div class="wrapper">
        <img class="wrapper__img" src="/i18n/9_16/img/user.png" />
        <div class="wrapper__input">
          <input
            class="wrapper__input__content"
            placeholder="请输入手机号码"
            v-model="data.formInfo.username"
          />
        </div>
        <div class="wrapper__input">
          <input
            type="password"
            class="wrapper__input__content"
            placeholder="请输入密码"
            v-model="data.formInfo.password"
          />
        </div>
        <div class="wrapper__login-button" @click="handleLogin">登陆</div>
        <div class="wrapper__login__item">
          <div class="wrapper__login__item__link" @click="handleRegisterClick">
            立即注册
          </div>
          <p class="wrapper__login__item__cut">|</p>
          <div class="wrapper__login__item__password">忘记密码</div>
        </div>
        <Toast v-if="toastData.show" :message="toastData.message" />
      </div>
    </template>
    
    <script>
    import { reactive } from 'vue'
    // 路由跳转方法
    import { useRouter } from 'vue-router'
    
    import { post } from '@/utils/request'
    import Toast, { useToastEffect } from '@/components/Toast/Toast'
    
    export default {
      name: 'Login',
      components: { Toast },
      setup () {
        // 获取路由实例
        const router = useRouter()
        const data = reactive({
          formInfo: {
            username: '',
            password: ''
          }
        })
    
        const { toastData, toastMsg } = useToastEffect()
        /** *************** 主流程中需要做的事情 *******************/
        // 登录按钮
        const handleLogin = async () => {
          try {
            const resultData = await post('/111/api/user/login', {
              username: data.formInfo.username,
              password: data.formInfo.password
            })
            // console.log(result)
            if (resultData?.code === 200) {
              localStorage.isLogin = true
              router.push({ name: 'Home' })
            } else {
              toastMsg('登陆失败!')
            }
          } catch (e) {
            toastMsg('请求失败!')
          }
        }
        const handleRegisterClick = () => {
          router.push({ name: 'Register' })
        }
        return { toastData, data, handleLogin, handleRegisterClick }
      }
    }
    </script>
    ......
    

    继续简化代码:
    src\components\Toast\Toast.vue:

    ......
    <script>
    import { reactive, toRefs } from 'vue'
    export default {
      name: 'Toast',
      props: { message: { type: String } }
    }
    /**
     * toast相关的逻辑
     */
    export const useToastEffect = () => {
      const toastData = reactive({
        show: false,
        message: ''
      })
      const toastMsg = (message, time) => {
        toastData.show = true
        toastData.message = message || ''
        setTimeout(() => {
          toastData.show = false
          toastData.message = ''
        }, time || 2000)
      }
    
      const { show, message } = toRefs(toastData)
      return { show, message, toastMsg }
    }
    </script>
    ......
    

    修改src\views\login\Login.vue:

    <template>
      <div class="wrapper">
        <img class="wrapper__img" src="/i18n/9_16/img/user.png" />
        <div class="wrapper__input">
          <input
            class="wrapper__input__content"
            placeholder="请输入手机号码"
            v-model="username"
          />
        </div>
        <div class="wrapper__input">
          <input
            type="password"
            class="wrapper__input__content"
            placeholder="请输入密码"
            v-model="password"
          />
        </div>
        <div class="wrapper__login-button" @click="handleLogin">登陆</div>
        <div class="wrapper__login__item">
          <div class="wrapper__login__item__link" @click="handleRegisterClick">
            立即注册
          </div>
          <p class="wrapper__login__item__cut">|</p>
          <div class="wrapper__login__item__password">忘记密码</div>
        </div>
        <Toast v-if="show" :message="message" />
      </div>
    </template>
    
    <script>
    import { reactive, toRefs } from 'vue'
    // 路由跳转方法
    import { useRouter } from 'vue-router'
    
    import { post } from '@/utils/request'
    import Toast, { useToastEffect } from '@/components/Toast/Toast'
    
    export default {
      name: 'Login',
      components: { Toast },
      setup () {
        // 获取路由实例
        const router = useRouter()
        const data = reactive({
          formInfo: {
            username: '',
            password: ''
          }
        })
    
        const { show, message, toastMsg } = useToastEffect()
        /** *************** 主流程中需要做的事情 *******************/
        // 登录按钮
        const handleLogin = async () => {
          try {
            const resultData = await post('/111/api/user/login', {
              username: data.formInfo.username,
              password: data.formInfo.password
            })
            // console.log(result)
            if (resultData?.code === 200) {
              localStorage.isLogin = true
              router.push({ name: 'Home' })
            } else {
              toastMsg('登陆失败!')
            }
          } catch (e) {
            toastMsg('请求失败!')
          }
        }
        const handleRegisterClick = () => {
          router.push({ name: 'Register' })
        }
    
        const { username, password } = toRefs(data.formInfo)
        return { show, message, username, password, handleLogin, handleRegisterClick }
      }
    }
    </script>
    ......
    

    进一步抽象登录的逻辑:
    src\views\login\Login.vue完整代码如下:

    <template>
      <div class="wrapper">
        <img class="wrapper__img" src="/i18n/9_16/img/user.png" />
        <div class="wrapper__input">
          <input
            class="wrapper__input__content"
            placeholder="请输入手机号码"
            v-model="username"
          />
        </div>
        <div class="wrapper__input">
          <input
            type="password"
            class="wrapper__input__content"
            placeholder="请输入密码"
            v-model="password"
          />
        </div>
        <div class="wrapper__login-button" @click="handleLogin">登陆</div>
        <div class="wrapper__login__item">
          <div class="wrapper__login__item__link" @click="handleRegisterClick">
            立即注册
          </div>
          <p class="wrapper__login__item__cut">|</p>
          <div class="wrapper__login__item__password">忘记密码</div>
        </div>
        <Toast v-if="show" :message="message" />
      </div>
    </template>
    
    <script>
    import { reactive, toRefs } from 'vue'
    // 路由跳转方法
    import { useRouter } from 'vue-router'
    
    import { post } from '@/utils/request'
    import Toast, { useToastEffect } from '@/components/Toast/Toast'
    
    const useLoginEffect = (toastMsg, router) => {
      const data = reactive({
        username: '',
        password: ''
      })
      // 登录按钮
      const handleLogin = async () => {
        try {
          const resultData = await post('/111/api/user/login', {
            username: data.formInfo.username,
            password: data.formInfo.password
          })
          // console.log(result)
          if (resultData?.code === 200) {
            localStorage.isLogin = true
            router.push({ name: 'Home' })
          } else {
            toastMsg('登陆失败!')
          }
        } catch (e) {
          toastMsg('请求失败!')
        }
      }
      const { username, password } = toRefs(data)
      return { username, password, handleLogin }
    }
    // 跳转注册
    const useRegisterEffect = router => {
      const handleRegisterClick = () => {
        router.push({ name: 'Register' })
      }
      return { handleRegisterClick }
    }
    export default {
      name: 'Login',
      components: { Toast },
      // 从这里可见,setup就是告知代码执行的流程
      setup () {
        // 获取路由实例
        const router = useRouter()
    
        const { show, message, toastMsg } = useToastEffect()
        /** *************** 主流程中需要做的事情 *******************/
        const { username, password, handleLogin } = useLoginEffect(toastMsg, router)
        const { handleRegisterClick } = useRegisterEffect(router)
    
        return {
          show,
          message,
          username,
          password,
          handleLogin,
          handleRegisterClick
        }
      }
    }
    </script>
    
    <style lang="scss" scoped>
    @import '@/style/viriables';
    .wrapper {
      position: absolute;
      top: 50%;
      left: 0;
      right: 0;
      transform: translateY(-50%);
      &__img {
        display: block;
        margin: 0 auto 0.4rem auto;
        width: 0.66rem;
        height: 0.66rem;
      }
      &__input {
        // box-sizing: border-box;//内部间距
        height: 0.48rem;
        margin: 0 0.4rem 0.16rem 0.4rem;
        background: #f9f9f9;
        border: 1px solid rgba(0, 0, 0, 0.1);
        border-radius: 0.06rem;
        &__content {
          line-height: 0.48rem;
          background: none;
          border: none;
          outline: none;
          width: 100%;
          font-size: 0.16rem;
          color: $centent-notice-fontcolor;
          &::placeholder {
            color: $centent-notice-fontcolor;
          }
        }
      }
      &__login-button {
        line-height: 0.48rem;
        margin: 0.32rem 0.4rem 0.16rem 0.4rem;
        background: #0091ff;
        color: #fff;
        box-shadow: 0 0.04rem 0.08rem 0 rgba(0, 145, 255, 0.32);
        border-radius: 0.04rem;
        font-size: 0.16rem;
        text-align: center;
      }
      &__login__item {
        text-align: center;
        &__link {
          display: inline-block;
          margin: auto 0.05rem auto 0.05rem;
          text-align: center;
          font-size: 0.14rem;
          color: $centent-notice-fontcolor;
        }
        &__cut {
          display: inline-block;
          text-align: center;
          font-size: 0.14rem;
          margin: auto 0.05rem auto 0.05rem;
        }
        &__password {
          display: inline-block;
          text-align: center;
          font-size: 0.14rem;
          margin: auto 0.05rem auto 0.05rem;
          color: $centent-notice-fontcolor;
        }
      }
    }
    </style>
    
    

    注册页面修改

    如果是电脑浏览器会自动填充密码。
    解决代码:

     autocomplete="new-password"
    

    注册页面修改如下:
    src\views\register\Register.vue:

    <template>
      <div class="wrapper">
        <img class="wrapper__img" src="/i18n/9_16/img/user.png" />
        <div class="wrapper__input">
          <input
            class="wrapper__input__content"
            placeholder="请输入手机号码"
            v-model="username"
          />
        </div>
        <div class="wrapper__input">
          <input
            type="password"
            class="wrapper__input__content"
            placeholder="请输入密码"
            v-model="password"
            autocomplete="new-password"
          />
        </div>
        <div class="wrapper__input">
          <input
            type="password"
            class="wrapper__input__content"
            placeholder="请再次输入密码"
            v-model="againPassword"
            autocomplete="new-password"
          />
        </div>
        <div class="wrapper__register-button" @click="handleRegister">注册</div>
        <div class="wrapper__register__item">
          <div class="wrapper__register__item__link" @click="handleLoginClick">
            已有账号去登陆
          </div>
        </div>
        <Toast v-if="show" :message="message" />
      </div>
    </template>
    
    <script>
    // 路由跳转方法
    import { useRouter } from 'vue-router'
    import { reactive, toRefs } from 'vue'
    import { post } from '@/utils/request'
    import Toast, { useToastEffect } from '@/components/Toast/Toast'
    // 注册功能的业务逻辑
    const useRegisterEffect = (toastMsg, router) => {
      const data = reactive({
        username: '',
        password: '',
        againPassword: ''
      })
      // 登录按钮
      const handleRegister = async () => {
        try {
          const resultData = await post('/api/user/register', {
            username: data.username,
            password: data.password
          })
          if (resultData?.code === 200) {
            localStorage.isRegister = true
            toastMsg('注册成功,请到登录页面登录!')
            router.push({ name: 'Login' })
          } else {
            toastMsg('注册失败!')
          }
        } catch (e) {
          toastMsg('注册请求失败!')
        }
      }
      const { username, password, againPassword } = toRefs(data)
      return { username, password, againPassword, handleRegister }
    }
    // 跳转登录
    const useLoginEffect = router => {
      const handleLoginClick = () => {
        router.push({ name: 'Login' })
      }
      return { handleLoginClick }
    }
    
    export default {
      name: 'Register',
      components: { Toast },
      setup () {
        // 获取路由实例
        const router = useRouter()
    
        const { show, message, toastMsg } = useToastEffect()
        /** *************** 主流程中需要做的事情 *******************/
        const {
          username,
          password,
          againPassword,
          handleRegister
        } = useRegisterEffect(toastMsg, router)
        const { handleLoginClick } = useLoginEffect(router)
    
        return {
          show,
          message,
          username,
          password,
          againPassword,
          handleLoginClick,
          handleRegister
        }
      }
    }
    </script>
    
    <style lang="scss" scoped>
    @import '@/style/viriables';
    .wrapper {
      position: absolute;
      top: 50%;
      left: 0;
      right: 0;
      transform: translateY(-50%);
      &__img {
        display: block;
        margin: 0 auto 0.4rem auto;
        width: 0.66rem;
        height: 0.66rem;
      }
      &__input {
        // box-sizing: border-box;//内部间距
        height: 0.48rem;
        margin: 0 0.4rem 0.16rem 0.4rem;
        background: #f9f9f9;
        border: 1px solid rgba(0, 0, 0, 0.1);
        border-radius: 0.06rem;
        &__content {
          line-height: 0.48rem;
          background: none;
          border: none;
          outline: none;
          width: 100%;
          font-size: 0.16rem;
          color: $centent-notice-fontcolor;
          &::placeholder {
            color: $centent-notice-fontcolor;
          }
        }
      }
      &__register-button {
        line-height: 0.48rem;
        margin: 0.32rem 0.4rem 0.16rem 0.4rem;
        background: #0091ff;
        color: #fff;
        box-shadow: 0 0.04rem 0.08rem 0 rgba(0, 145, 255, 0.32);
        border-radius: 0.04rem;
        font-size: 0.16rem;
        text-align: center;
      }
      &__register__item {
        text-align: center;
        &__link {
          display: inline-block;
          margin: auto 0.05rem auto 0.05rem;
          text-align: center;
          font-size: 0.14rem;
          color: $centent-notice-fontcolor;
        }
      }
    }
    </style>
    

    相关文章

      网友评论

        本文标题:【vue3.0】10.0 某东到家(十)——Toast弹窗和代码

        本文链接:https://www.haomeiwen.com/subject/hbgbpltx.html