0
点赞
收藏
分享

微信扫一扫

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

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

新建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

Vue3.0整理

vue3.0进阶

0 条评论