做爰全過程免費(fèi)的網(wǎng)站視頻廣告公司怎么找客戶資源
47、通用組件 - 倒計(jì)時(shí)組件
特惠部分存在一個(gè)倒計(jì)時(shí)的功能,所以我們需要先處理對(duì)應(yīng)的倒計(jì)時(shí)模塊,并把它處理成一個(gè)通用組件。
那么對(duì)于倒計(jì)時(shí)模塊我們又應(yīng)該如何進(jìn)行處理呢?
所謂倒計(jì)時(shí),其實(shí)更多的是一個(gè)時(shí)間的處理,那么對(duì)于時(shí)間的處理,此時(shí)我們就需要使用到一個(gè)第三方的包: dayis。通過這個(gè)包我們可以處理對(duì)應(yīng)的倒計(jì)時(shí)格式問題。
那么時(shí)間格式處理完成之后,接下來我們就需要處理對(duì)應(yīng)的數(shù)據(jù):
我們期望對(duì)倒計(jì)時(shí)模塊,可以傳遞兩個(gè)值:
time
毫秒值:表示倒計(jì)時(shí)的時(shí)長(zhǎng)- format格式:表示倒計(jì)時(shí)的展示格式
那么到這里咱們整個(gè)的倒計(jì)時(shí)功能即使就分析的差不多了,總共分成了兩部分:
1.時(shí)間格式
2.?dāng)?shù)據(jù)
<template><slot :data="{ timeStr, timeValue }"><div>{{ timeStr }}</div></slot>
</template><script setup>
import dayjs from 'dayjs'
import duration from 'dayjs/plugin/duration'
import 'dayjs/locale/zh-cn'
import { watch, ref, computed, onUnmounted } from 'vue'dayjs.extend(duration)
dayjs.locale('zh-cn')
let timer = null
const props = defineProps({time: {// 倒計(jì)時(shí)時(shí)間, ms單位type: Number,required: true},format: {// 格式化時(shí)間type: String,default: 'HH小時(shí)mm分鐘ss秒SSS'}
})// 組件銷毀時(shí)清理定時(shí)器
onUnmounted(() => {close()
})
const timeValue = ref(props.time)// 封裝格式化日期函數(shù)
const fmtTime = (milliseconds) => {const d = dayjs.duration(milliseconds)return d.format(props.format)
}const handleSetInterval = () => {timer = setInterval(() => {if (typeof timeValue.value === 'number' && timeValue.value <= 0) {//完成close()} else {timeValue.value -= 9}}, 9)
}
const timeStr = computed(() => {return typeof timeValue.value === 'number' ? fmtTime(timeValue.value) : ''
})
/*** 關(guān)閉定時(shí)器*/
const close = () => {clearInterval(timer)
}
/*** 開啟定時(shí)器*/
const start = () => {handleSetInterval()
}
/*** 從新設(shè)置定時(shí)器*/
const reset = (v) => {const setV = v > 0 ? v : props.timetimeValue.value = setV
}
watch(() => props.time,(v) => {timeValue.value = vclose()start()},{immediate: true}
)defineExpose({close,start,reset,timeStr,timeValue
})
</script>
48、第三方平臺(tái)登錄解決方案流程大解析
通常情況下我們所說的第三方登錄,多指的是:通過第三方APP進(jìn)行登錄
那么我們這個(gè)第三方的 APP
是如何和我們自己的應(yīng)用進(jìn)行關(guān)聯(lián)的呢?
如果大家不是很清楚,那么本小節(jié)將為你解答。
想要搞明白這個(gè)問題,那么我們首先需要搞清楚整個(gè)第三方登錄的流程是如何進(jìn)行的。
我們以常見app第三方登錄為例:
- 1.點(diǎn)擊第三方登錄按鈕
- 2.彈出一個(gè)小窗口,展示對(duì)應(yīng)二維碼
- 3.手機(jī)打開對(duì)應(yīng)的 APP進(jìn)行掃碼之后,會(huì)跳轉(zhuǎn)到同意頁面,同時(shí)瀏覽器端也會(huì)顯示掃碼成功
- 4.手機(jī)端操作同意登錄之后,會(huì)出現(xiàn)兩種情況:
- 1.當(dāng)前用戶已注冊(cè):直接登錄
- 2.當(dāng)前用戶未注冊(cè):執(zhí)行注冊(cè)功能
詳細(xì)流程如下:
- 1.點(diǎn)擊第三方登錄按鈕:執(zhí)行
window.open
方法,打開一個(gè)第三方指定的URL
窗口,該地址會(huì)指向第三方登錄的URL
,并且由第三方提供一個(gè)對(duì)應(yīng)的二維碼 - 2.彈出一個(gè)小窗口,展示對(duì)應(yīng)二維碼: 此處展示的二維碼,即為上一步中第三方提供的二維碼
- 3.手機(jī)打開對(duì)應(yīng)的
APP
進(jìn)行掃碼之后,會(huì)跳轉(zhuǎn)到同意頁面,同時(shí)瀏覽器端也會(huì)顯示掃碼成功:在第三方中會(huì)一直對(duì)該頁面進(jìn)行輪詢,配合第三方APP 來判斷是否掃碼成功 - 4.手機(jī)端操作同意登錄之后,會(huì)出現(xiàn)兩種情況:在 APP 中同意之后,第三方會(huì)進(jìn)行對(duì)應(yīng)的跳轉(zhuǎn),跳轉(zhuǎn)地址為你指定的地址,在該地址中可以獲取到第三方的用戶信息,該信息即為第三方登錄時(shí)要獲取到的關(guān)鍵數(shù)據(jù)
- 5**.至此,第三方操作完成。接下來需要進(jìn)行本平臺(tái)的登錄判定。**
- 1.該注冊(cè)指的是第三方用戶是否在本平臺(tái)中進(jìn)行了注冊(cè)。
- 2.因?yàn)樵谥暗乃胁僮髦?,我們拿到的是第三方的用戶信息?/li>
- 3.該信息可以幫助我們直接顯示對(duì)用的用戶名和頭像,但是因?yàn)椴话P(guān)鍵信息(手機(jī)號(hào)、用戶名、密碼)所以我們無法使用該信息幫助用戶直接登錄
- 4.所以我們需要判斷當(dāng)前用戶是否在咱們自己的平臺(tái)中完成了注冊(cè)
- 1.當(dāng)前用戶已注冊(cè):直接登錄
- 2.當(dāng)前用戶未注冊(cè):執(zhí)行注冊(cè)功能
48.1、QQ開放平臺(tái)流程大解析
那么接下來我們先來處理QQ
第三方登錄功能。
想要對(duì)接QQ
登錄,那么需要使用到QQ
互聯(lián)平臺(tái),在該平臺(tái)中:
1.注冊(cè)賬戶
2.認(rèn)證開發(fā)者
3.注冊(cè)應(yīng)用
48.2、QQ登錄對(duì)接流程: 獲取QQ用戶信息
官網(wǎng)文檔
對(duì)接QQ
登錄分為以下幾步:
- 1.展示
QQ
登錄二維碼 - 2.獲取用戶信息
- 3.完成跨頁面數(shù)據(jù)傳輸
- 4.認(rèn)證是否已注冊(cè)分
- 5.完成
QQ
對(duì)接
展示QQ
登錄二維碼
1、在index.html
中引入QQ
的SDK
<!-- QQ 登錄 --><scripttype="text/javascript"charset="utf-8"src="https://connect.qq.com/qc_jssdk.js"data-appid="[你的appid]"data-redirecturi="[你在QQ互聯(lián)中配置的成功之后的回調(diào)]"></script>
2、創(chuàng)建qq-login
組件、來鳳凰qq登錄組件
<template><div class="qq-connect-box"><span id="qqLoginBtn"></span><svg-iconclass="w-4 h-4 fill-zinc-200 dark:fill-zinc-300 duration-500 cursor-pointer"name="qq"></svg-icon></div>
</template><script setup>
import { onMounted } from 'vue'
onMounted(() => {QC.Login({btnId: 'qqLoginBtn' //插入按鈕的節(jié)點(diǎn)id},(data, ops) => {console.log(data, '登錄成功')})
})
</script>
上面的圖片可以得知、qqLoginBtn
就是放置調(diào)起二維碼按鈕的地方、點(diǎn)擊qqLoginBtn
標(biāo)簽中的a鏈接、可以調(diào)起二維碼;但是這樣寫有太丑;所以我們可以將a鏈接的透明度設(shè)置為0,并且置于最下方即可;css如下
<style lang="scss" scoped>
.qq-connect-box {position: relative;&:deep(#qqLoginBtn) {a {position: absolute;top: 0;right: 0;bottom: 0;left: 0;z-index: -1px;opacity: 0;}}
}
</style>
完整示例
<template><div class="qq-connect-box"><span id="qqLoginBtn"></span><svg-iconclass="w-4 h-4 fill-zinc-200 dark:fill-zinc-300 duration-500 cursor-pointer"name="qq"></svg-icon></div>
</template><script setup>
import { onMounted } from 'vue'
onMounted(() => {// 當(dāng)我們登錄成功之后、會(huì)緩存起來、下次登錄不需要掃碼、所以我們需要注銷登錄、避免用戶下次登錄時(shí)展示上次的記錄QC.Login({btnId: 'qqLoginBtn' //插入按鈕的節(jié)點(diǎn)id},(data, ops) => {// 掃碼授權(quán)登錄成功后的回到console.log(data, '登錄成功')// 注銷登錄QC.Login.signOut()// 登錄成功的回調(diào)// https://imooc-front.lgdsunday.club/login#access_token=4723B87EC749FA12A7247F40975D7BFB&expires_in=7776000// 解析地址欄地址獲取tokenconst accessToken = getQQAccessToken()// 將data中的用戶昵稱、和用戶頭像、以及accessToken發(fā)送給后臺(tái)// TODO})
})const getQQAccessToken = () => {const hash = window.location.hash || ''const reg = /access_token=(.+)&expires_in/return hash.match(reg)[1]
}
</script><style lang="scss" scoped>
.qq-connect-box {position: relative;&:deep(#qqLoginBtn) {a {position: absolute;top: 0;right: 0;bottom: 0;left: 0;z-index: -1px;opacity: 0;}}
}
</style>
注意:掃碼成功重定向的地址是在小窗口打開的、并不是在原來的窗口打開、登錄成功的回調(diào)也是在小窗口中回調(diào)
48.3、 QQ
登錄對(duì)接流程:跨頁面信息傳輸
由于拿到掃碼用戶的 AccessToken
和 用戶的信息(昵稱、頭像…) 都是在小窗口上獲取到的;
這小節(jié)最要作用:就是將小窗口獲取到的這些信息傳遞給主窗口上
想要實(shí)現(xiàn)跨頁面信息傳輸,通常由兩種方式:
- 1、
BroadcastChannel
:允許同源的不同瀏覽器窗口,Tab頁,frame
或者iframe
下的不同文檔之間相互通信。但是會(huì)存在兼容性問題,實(shí)測(cè)Safari15.3
無法使用 - 2、
localStorage
+window.onstorage
: 通過localStorage
進(jìn)行同源的數(shù)據(jù)傳輸。用來處理BroadcastChannel
不兼容的瀏覽器。
那么依據(jù)以上兩個(gè)API,我們實(shí)現(xiàn)對(duì)應(yīng)的通訊模塊:
utils/broadcase.js
/**** 向同源且不同tab標(biāo)簽頁發(fā)送數(shù)據(jù)*/// BroadcastChannel的信道key; 或者localStorage的設(shè)置項(xiàng)的key
const BROAD_CASE_CHANNEL_KEY = 'BROAD_CASE_CHANNEL_KEY'
// BroadcastChannel實(shí)例
let broadcastChannel = null
if (window.BroadcastChanne) {// 創(chuàng)建BroadcastChannel實(shí)例broadcastChannel = new window.BroadcastChanne(BROAD_CASE_CHANNEL_KEY)
}
/*** 發(fā)送數(shù)據(jù)* @param {*} data 發(fā)送的數(shù)據(jù)包*/
export const sendMsg = (data) => {if (broadcastChannel) {broadcastChannel.postMessage(data)} else {window.localStorage.setItem(BROAD_CASE_CHANNEL_KEY, JSON.stringify(data))}
}/*** 監(jiān)聽數(shù)據(jù)傳輸* @returns promise對(duì)象*/
export const listener = () => {return new Promise((resolve, reject) => {if (broadcastChannel) {broadcastChannel.onmessage = (event) => {resolve(event.data)}} else {window.onstorage = (event)