# 2-1.Vue外送平台App-登入介面 ## 登入介面相關效果 Login.vue ### 1. 切換登入方式 ![](https://i.imgur.com/kDYy5oj.png) * 當點擊短信登入或密碼登入能切換效果 * 此切換效果搭配樣式 class="on" style="on{color:green font-weight:700 border-bottom:2px solid green}" * loginWay 切換功能使用boolean的ture ,false來定義進行切換功能 ```htmlmixed= <template> <div class="loginContainer"> <div class="loginInner"> <div class="login_header"> <h2 class="login_logo">Vue外送平台</h2> <div class="login_header_title"> //加入切換點擊監聽事件 <a href="javascript:;" :class="{on : loginWay}" @click="loginWay=true">短訊登入</a> <a href="javascript:;" :class="{on : !loginWay}" @click="loginWay=false">密碼登入</a> </div> </div> <div class="login_content"> <form> //判斷如果現在是ture會@click="loginWay=true"事件一起轉動到這邊表格樣式 <div :class="{on : loginWay}"> <section class="login_message"> <input type="tel" maxlength="11" placeholder="手機號碼"> <button disabled="disabled" class="get_verification">獲得驗證碼</button> </section> <section class="login_verification"> <input type="tel" maxlength="8" placeholder="驗證碼"> </section> <section class="login_hint"> 溫馨提醒:未註冊Vue外送平台帳號的手機,登入時將自動註冊,且代表已同意 <a href="javascript:;">《用戶服務協議》</a> </section> </div> //判斷如果現在是false會連著@click="loginWay=false事件一起轉動到這邊表格樣式 <div :class="{on : !loginWay}"> <section> <section class="login_message"> <input type="tel" maxlength="11" placeholder="手機/郵箱/用户名"> </section> <section class="login_verification"> <input type="tel" maxlength="8" placeholder="密码"> <div class="switch_button off"> <div class="switch_circle"></div> <span class="switch_text">...</span> </div> </section> <section class="login_message"> <input type="text" maxlength="11" placeholder="驗證碼"> <img class="get_verification" src="../Login/images/captcha.svg" alt="captcha"> </section> </section> </div> <button class="login_submit">登入</button> </form> <a href="javascript:;" class="about_us">關於我们</a> </div> <!--跳轉道上一頁--> <span href="javascript:" class="go_back" @click="$router.back()"> <i class="iconfont icon-jiantou2"></i> </span> </div> </div> </template> <script> export default { data() { return { //需先初始化 loginWay: true, //false:短訊登入 true:密碼登入 } }, } </script> ``` ### 2. 手機合法檢查 * 運用正則表達式,手機格式是否正確 * 要驗證短訊登入->手機號碼 ### 3. 倒數計時效果 * 當手機號碼格式與驗證相符時,點取獲得驗證碼會切換成倒數計器 ```htmlmixed= <!--<from>表單中--> <div :class="{on : loginWay}"> <section class="login_message"> <!--在v-model綁定與api接口一樣的值--> <input type="text" maxlength="10" placeholder="手機號碼" v-model="phone"> <!--:disabled="!rightPhone"如果正則表達式在input中格式正確 那麼就變化成倒數計時器 --> <!--:class="{right_phone :rightPhone} 綁定class屬性 在樣式中加入right_phone{color:black} rightPhone格式正確,啟動right_phone樣式 --> <button :disabled="!rightPhone" class="get_verification" :class="{right_phone :rightPhone}" @click.prevent="getCode"> <!-- computeTime 如果大於零 執行`已發送(${computeTime}s)` 不然就執行 '獲得驗證碼' --> {{ computeTime > 0 ? `已發送(${computeTime}s)`:'獲得驗證碼'}}</button> </section> <section class="login_verification"> <input type="text" maxlength="8" placeholder="驗證碼"> </section> <section class="login_hint"> 溫馨提醒:未註冊Vue外送平台帳號的手機,登入時將自動註冊,且代表已同意 <a href="javascript:;">《用戶服務協議》</a> </section> </div> <script> export default { data() { return { loginWay: true, //false:短訊登入 true:密碼登入 } }, computed: { // 運用計算屬性來運算正則表達式 rightPhone() { return /^[0-9]{10}$/g.test(this.phone) } } </script> ``` ### 4. 切換顯示或隱藏密碼 * 密碼登入->密碼->製作隱藏切換按鈕後能顯示密碼 * 不顯示和顯示密碼按鈕切換樣式 * ![](https://i.imgur.com/7iVumY6.png) ```htmlmixed= <section> <section class="login_message"> <input type="tel" maxlength="11" placeholder="手機/郵箱/用户名" v-model="name"> </section> <section class="login_verification"> <!--再增加一個input -> v-model="pwd"(要跟api的值相同) 運用v-if v-else來定義ture or false--> <input type="text" maxlength="8" placeholder="密码" v-model="pwd" v-if="pwdShow"> <input type="password" maxlength="8" placeholder="密码" v-model="pwd" v-else="!pwdShow"> <!-- 綁定class pwdShow 是false 顯示on=pwdShow 不然就顯示 off=!pwdShow --> <div class="switch_button" :class="pwdShow ? 'on' : 'off'" @click="pwdShow = !pwdShow"> <!--增加style="switch_circle_right{transform: translateX(30px); : pwdShow (兩個條件都符合才可以成立此功能)}"--> <div class="switch_circle" :class="{switch_circle_right : pwdShow}"></div> <!--pwdShow 如果城裡那麼顯示abc 不然就...---> <span class="switch_text">{{pwdShow? 'abc':'...'}}</span> </div> </section> <section class="login_message"> <input type="text" maxlength="11" placeholder="驗證碼"> <img class="get_verification" src="../Login/images/captcha.svg" alt="captcha"> </section> </section> <script> export default { data() { return { pwdShow: false, //不顯示密碼 } } </script> ``` ### 5. 前後台正規表達驗證與提示(alert) * 收集form 所有input中的數據 v-model=""(裡面值必須對應api接口) * <button class="login_submit">登入</button>點擊後默認直接提交表單,在form 中禁止submit冒泡事件(prevent) * 收集完數據並在data中初始化數據 * 運用methods方法->判斷現在是短信登入還是密碼登入並且驗證格式是否與定義的相符 * 新創建AlertTip Component 1. Login.vue接收AlertTip組件和屬性 2. 完成錯誤訊息視窗靜態組件 3. 判斷什麼時候會出現此視窗 4. 根據格式判斷後alert中的文字變化 ```htmlmixed= <template> <div class="loginContainer"> <div class="loginInner"> <div class="login_header"> <h2 class="login_logo">Vue外送平台</h2> <div class="login_header_title"> <a href="javascript:;" :class="{on : loginWay}" @click="loginWay=true">短訊登入</a> <a href="javascript:;" :class="{on : !loginWay}" @click="loginWay=false">密碼登入</a> </div> </div> <div class="login_content"> <!--阻止冒泡事件 收集完input所有數據後,透過login 方法來->判斷現在是訊息登入曬密碼登入->判斷數據是否與自定義 的格式相同 -->ㄨ <form @submit.prevent="login"> <div :class="{on : loginWay}"> <section class="login_message"> <!--收集數據:在v-model綁定與api接口一樣的值--> <input type="text" maxlength="10" placeholder="手機號碼" v-model="phone"> <button :disabled="!rightPhone" class="get_verification" :class="{right_phone :rightPhone}" @click.prevent="getCode"> {{ computeTime > 0 ? `已發送(${computeTime}s)`:'獲得驗證碼'}}</button> </section> <section class="login_verification"> <!--收集數據:在v-model綁定與api接口一樣的值--> <input type="text" maxlength="6" placeholder="驗證碼" v-model="code"> </section> <section class="login_hint"> 溫馨提醒:未註冊Vue外送平台帳號的手機,登入時將自動註冊,且代表已同意 <a href="javascript:;">《用戶服務協議》</a> </section> </div> <div :class="{on : !loginWay}"> <section> <section class="login_message"> <!--收集數據:在v-model綁定與api接口一樣的值--> <input type="tel" maxlength="11" placeholder="手機/郵箱/用户名" v-model="name"> </section> <section class="login_verification"> <!--收集數據:在v-model綁定與api接口一樣的值--> <input type="text" maxlength="8" placeholder="密码" v-model="pwd" v-if="pwdShow"> <input type="password" maxlength="8" placeholder="密码" v-model="pwd" v-else="!pwdShow"> <div class="switch_button" :class="pwdShow ? 'on' : 'off'" @click="pwdShow = !pwdShow"> <div class="switch_circle" :class="{switch_circle_right : pwdShow}"></div> <span class="switch_text">{{pwdShow? 'abc':'...'}}</span> </div> </section> <section class="login_message"> <!--收集數據:在v-model綁定與api接口一樣的值--> <input type="text" maxlength="11" placeholder="驗證碼" v-model="captcha"> <img class="get_verification" src="../Login/images/captcha.svg" alt="captcha"> </section> </section> </div> <button class="login_submit">登入</button> </form> <a href="javascript:;" class="about_us">關於我們</a> </div> <!--跳轉道上一頁--> <span href="javascript:" class="go_back" @click="$router.back()"> <i class="iconfont icon-jiantou2"></i> </span> </div> <!--1.完成錯誤訊息視窗靜態組件, 2.定義什麼時候會出現此視窗 3.裡面的訊息文字變化 --> <AlertTip :alertText="AlertText" v-show="showAlert" @closeTip="closeTip" /> </div> </template> <script> import AlertTip from '../../components/AlertTip/AlertTip'; export default { data() { return { loginWay: true, //true:短訊登入 false:密碼登入 computeTime: 0, //計時的時間 pwdShow: false, //是否顯示密碼 phone: '', //手機號碼 code: '', //短信驗證碼 name: '', //用戶名 pwd: '', //密码 captcha: '', //圖形驗證碼 showAlert: false, //是否顯示錯誤訊息視窗 AlertText: '' //錯誤訊息裡面文字 } }, computed: { rightPhone() { return /^[0-9]{10}$/g.test(this.phone) } }, methods: { // 異步獲取短信驗證碼 getCode() { // 开始倒计时 if (this.computeTime === 0) { this.computeTime = 60 // // 启动循环定时器, 每隔 1s 减少 1 let interval = setInterval(() => { this.computeTime-- //什麼時候要停止?? if (this.computeTime === 0) { //interval一旦執行會產生回調函數(要定義const or let) clearInterval(this.interval) } }, 1000) } }, //前台表單驗證 login() { //假如loginWay = true:短訊登入 if (this.loginWay) { const { rightPhone, phone, code } = this if (!this.rightPhone) { //手機號碼格式不正確 this.showAlert = true this.AlertText = '手機號碼格式不正確' } else if (!(/^\d{6}$/gi.test(this.code))) { //短信驗證碼格式不正確 this.showAlert = true this.AlertText = '短信驗證碼格式不正確' } //不然密碼登入 } else { const { name, pwd, captcha } = this if (!this.name) { //用户名格式不正確 this.showAlert = true this.AlertText = '用户名格式不正確' } else if (!this.pwd) { //密碼格式不正確 this.showAlert = true this.AlertText = '密碼格式不正確' } else if (!this.captcha) { //圖形驗證不正確 this.showAlert = true this.AlertText = '圖形驗證不正確' } } }, //關閉提示框 closeTip() { this.showAlert = false this.AlertText = '' } }, components: { AlertTip } } </script> <!-- src > components > AlertTip > AlertTip.vue--> <template> <div class="alert_container"> <section class="tip_text_container"> <div class="tip_icon"> <span></span> <span></span> </div> <p class="tip_text">{{alertText}}</p> <div class="confrim" @click="closeTip">確定</div> </section> </div> </template> <script> export default { props: { alertText: String }, methods: { closeTip() { this.$emit('closeTip') } }, } </script> <style lang="scss"> @import '../../assets/style/common/_mixins.scss'; @keyframes tipMove { 100% { transform: scale(1) } 35% { transform: scale(.8) } 70% { transform: scale(1.1) } 100% { transform: scale(1) } } .alert_container { position: fixed; top: 0; left: 0; right: 0; bottom: 0; z-index: 200; background: rgba(0, 0, 0, .5); .tip_text_container { position: absolute; top: 50%; left: 50%; //transform: translate(-50%, -50%); margin-top: -110px; margin-left: -110px; width: 60%; animation: tipMove .5s; background-color: rgba(255, 255, 255, 1); border: 1px; padding-top: 20px; display: flex; justify-content: center; align-items: center; flex-direction: column; border-radius: 5px; .tip_icon { width: 55px; height: 55px; border: 2px solid #f8cb86; border-radius: 50%; font-size: 20px; display: flex; justify-content: center; align-items: center; flex-direction: column; span:nth-of-type(1) { width: 2px; height: 30px; background-color: #f8cb86; } span:nth-of-type(2) { width: 2px; height: 2px; border: 1px; border-radius: 50%; margin-top: 2px background-color #f8cb86; } } .tip_text { font-size: 14px; color: #333; line-height: 20px; text-align: center; margin-top: 10px; padding: 0 5px; } .confrim { font-size: 18px; font-weight: bold; margin-top: 10px; background-color: #4cd964; width: 100%; text-align: center; line-height: 35px; border: 1px; color: #fff; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; } } } </style> ``` --- ## 前後台交互功能 ### 1. 動態一次性圖型驗證碼 * 不需與透過ajax交互 * 如何讓介面點即時切換下一個圖形驗證碼? * 運用$refs 1. 想要從 父元件 取得 子元件 的資料時 2. 想要取得 DOM Element 的資訊時(例如寬度) 3. $refs 這個 Instance Property 的來解決上述問題;只要在透過 ref 這個 Attribute 就可以讓 Vue 定位取得你想要的 Instance。 4. 做法很簡單,只要在你想要的 Element 上給定一個 ref value,在元件中只要搭配 this.$refs.<your_ref_value> 就可以取得這個 Element or 元件的 Instance 了。 ```htmlmixed= <section class="login_message"> <input type="text" maxlength="11" placeholder="驗證碼" v-model="captcha"> <!--scr放入api url 給定ref value --> <img class="get_verification" src="http://localhost:4000/captcha" alt="captcha" @click="getCaptcha" ref="captcha"> <script> </section> export default { methods:{ //圖形介面切換 getCaptcha() { //在元件中搭配this.$refs.value this.$refs.captcha.src = 'http://localhost:4000/captcha?time=' + Date.now() }, } } </script> ``` ### 2. 動態一次性短信驗證碼 ### 3. 短信登入 ### 4. 密碼登入 ### 5. 登出 --- ### async await | async | await | | -------- | -------- | | 宣非告被定義成非同步函式,而且只能回傳一個promise | 等待一個Promise的回傳(只能用在async function裡) | ###### tags: `Vue` `Login` `async await`