【vue3.0】10.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>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,911评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,014评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,129评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,283评论 1 264
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,159评论 4 357
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,161评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,565评论 3 382
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,251评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,531评论 1 292
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,619评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,383评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,255评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,624评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,916评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,199评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,553评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,756评论 2 335

推荐阅读更多精彩内容