《Vue3+TS》开发一个自己的起始页
前言
之前習慣使用的是百度的作為瀏覽器的首頁,百度登錄賬號后可以在首頁上收藏很多書簽,但是近期因為使用不同電腦協同辦公,導致一臺電腦登錄百度賬號后,其它的電腦的百度會被提下線,這就很煩,還不如自己做個起始頁;
?
效果圖
項目下載
項目代碼已上傳,可以前往下載相關代,下載地址如下:下載地址,如果不能下載且有需要的小伙伴及時聯系博主或評論留下郵箱,我看到后會第一時間發送代碼;
技術棧
本項目前臺的主要技術棧使用的是:Vue3+VueX+VueRouter+Axios+TypeScript,后臺主要是用的Node+TypeScript,當然本文主要講述的是前臺相關,后臺部分代碼有興趣的可以留言;
分析
在開始碼代碼前簡單的分析一下,理一下邏輯,同時看看有可能會涉及到哪些知識點,這樣在準備階段大致心里就有了一個底,對于重復度高的部分可以提前預計到并封裝成組件,公共樣式也盡量提前抽離;
?
思維導圖
?
功能點概述
首頁
主要用途是搜索,有搜索框組件和時鐘組件組成,并且搜索框組件聚焦時可以看到歷史記錄以及熱門搜索,同時聚焦時背景圖上有一個放大以及毛玻璃的效果;
快捷頁
快捷入口的集合,打開時背景圖同樣有一個放大以及毛玻璃的效果;
另外,在整個項目里,使用到了lowdb來對數據進行緩存和讀取(其實就是localstage),使用到了loadsh作為函數庫
初始化項目
既然是基于Vue,那么開始必須是基于Vue3的腳手架搭建項目,具體命令如下:
vue create start注意的是,在配置項目的時候需要選擇安裝TypeScript,以及使用到了CSS的預處理器:less,實際上我覺得Sass更符合我個人的使用習慣,但是公司的項目都是用的less,那么這里也就繼續使用less作為預處理器,兩者其實差不多,沒什么根本性的不同;
?
功能點
感覺沒有必要將每一行代碼都放在博客里,那樣的話感覺整篇博客都是長篇代碼而且效果也不好,博客里又不能調試,要看整體代碼直接下載項目就是了,還能一邊看一邊調試,本文主要記錄一下涉及到的功能點的代碼,方便理解Vue3+Typescript(由于代碼寫的比較早,現在回過頭來看還是又一些可以優化的地方的,寫的不好的地方多多見諒);
?
布局組件
這個組件的主要目的是用來做布局,因為新的界面交付到我們開發手里時,不能直接開始寫代碼,肯定要寫一些布局組件,用來對頁面進行合理的布局,布局組件寫完后,只要在對應的位置填入對應的組件就行了,這樣就不用在每一個頁面都寫一遍布局,這樣不科學也太累,一旦需求發生變化,如果每個頁面都是進行布局那工作了就成倍的增加了;
布局組件部分代碼如下,在本項目中這個布局組件除了用來布局,還用來做各個子組件的數據的一個交互的鏈接點,因為不管是快捷入口還是搜索欄組件都會對背景組件的狀態產生修改,一旦狀態發生變化,那么這個組件就可以用來臨時做數據的中轉:
我們寫了一個base-layout的組件用來做布局,并且在組件中預留了4個插槽,分別用來放置背景組件,主界面,快捷入口,版權信息,這樣整體的結構不會凌亂,而base-layout部分代碼如下:
<template><div class="threeS-home-container"><div class="threeS-home-bg"><slot name="backgourndImage"></slot></div><div class="threeS-home-search"><slot name="search"></slot></div><div class="threeS-home-copyright"><slot name="copyright"></slot></div><div class="threeS-home-shortcuts" v-if="shortcuts"><slot name="shortcuts"></slot></div></div> </template><script lang="ts"> import { defineComponent } from "vue";export default defineComponent({props: {shortcuts: {type: Boolean,default: false,},},setup() {}, }); </script><style scoped lang="less"> // ... 具體的樣式 </style>就是做了一個布局,對每一塊內容都進行圈定范圍,并且預留了插槽用來內容填充;
?
背景組件
這個組件主要的功能就是背景圖的放大以及毛玻璃,這兩塊效果其實都是CSS實現的,JS實現的主要是在什么時機觸發這個效果,在本項目中,觸發的時機一共有兩個:
部分代碼如下:
<script lang="ts"> import { defineComponent, computed, ref, nextTick, watch } from "vue";import { useStore, Store } from "vuex";export default defineComponent({props: {glass: {type: Boolean,default: false,},shortcuts: {type: Boolean,default: false,},},setup(props, context) {// 表單DOMconst threeSBgRef: any = ref(null);// 獲取vuex信息const store: Store<any> = useStore();// 背景圖路徑const imgSrcPath = ref("");// 背景圖狀態,false-隱藏,true-顯示const showImg = ref(false);// 背景圖信息const bagImg = computed(() => store.getters["basic/basic/getBg"]);/*** 背景圖DOM* @returns {HTMLElement} 背景圖DOM*/async function getImgDom(): Promise<any> {return new Promise((resolve) => {nextTick(() => {resolve(threeSBgRef.value);});});}watch(() => bagImg.value,async (value) => {if (Array.isArray(value)) {return false;}const img: HTMLElement = await getImgDom();img.onload = () => {showImg.value = true;};imgSrcPath.value = value.path;});/*** 右擊*/function handleRightClick(): void | boolean {if (imgSrcPath.value === "") return false;context.emit("changeShortcuts", !props.shortcuts);}/*** 左擊*/function handleLeftClick(): void | boolean {if (!props.glass) return false;context.emit("changeGlass", false);}return {imgSrc: computed(() =>imgSrcPath.value === ""? null: require(`../../../../../src/assets/bg/${imgSrcPath.value}`)),showImg,threeSBgRef,handleRightClick,handleLeftClick,};}, }); </script>另外,這里還有一個骨架屏的效果,就是當背景圖還沒有被加載的時候,整個背景圖處于灰色,并且有一個從左往右的動效,代表正在加載中,骨架屏效果代碼如下:
.threeS-loading {background-color: #f2f2f2;background: linear-gradient(100deg,rgba(255, 255, 255, 0) 40%,rgba(255, 255, 255, 0.5) 50%,rgba(255, 255, 255, 0) 60%)#f6f6f6;background-size: 200% 100%;background-position-x: 120%;animation: 1s loading ease-in-out infinite; }@keyframes loading {to {background-position-x: -20%;} }時鐘組件
這個組件的難點在于實現電子數字的格式,這個是最復雜的,而時間的獲取就是基于瀏覽器Date對象,這個很簡單,獲取時間的方法部分如下:
/*** 獲得時間* @returns {String} 當前時間*/ function getTime(): string {const date = new Date();const hour = date.getHours();const minute = date.getMinutes();return ((hour >= 10 ? hour : "0" + hour) +":" +(minute >= 10 ? minute : "0" + minute)); }當獲取到時間以后,需要將轉成電子格式的,這部分的原理就是先拼出一個電子格式的8,然后,不同的數字只是去掉8中的某一個筆劃,這樣就達到了0-9的數字,這里我挑一部分CSS代碼
.digits div span {opacity: 0;position: absolute;-webkit-transition: 0.25s;-moz-transition: 0.25s;transition: 0.25s; } .digits div span:before, .digits div span:after {content: "";position: absolute;width: 0;height: 0;border: @fontSize solid transparent; } .digits .d1 {height: @fontSize;width: 16px;top: 0;left: 6px; } .digits .d1:before {border-width: 0 @fontSize @fontSize 0;border-right-color: inherit;left: -@fontSize; } .digits .d1:after {border-width: 0 0 @fontSize @fontSize;border-left-color: inherit;right: -@fontSize; }.digits .d2 {height: @fontSize;width: 16px;top: 24px;left: 6px; } .digits .d2:before {border-width: 3px 4px 2px;border-right-color: inherit;left: -8px; } .digits .d2:after {border-width: 3px 4px 2px;border-left-color: inherit;right: -8px; }這里是1和2的組成,通過類似的方法將0-9的CSS都寫完,之后獲取到時間,在填入的時候判斷需要填入的是哪個數字就行:
/*** 填入時間* @param {String} time - 時間* @param {HTMLElement} timerClock - 填入時間的DOM* @returns 無*/ function clocknum(time: string, timerClock: HTMLElement): void {timerClock.innerHTML = "";var html = "";var strarr: any[] = time.toString().split("");var digit_to_name = "zero one two three four five six seven eight nine".split(" ");for (var i = 0; i < strarr.length; i++) {if (strarr[i] == ":") {html += '<div class="dot"></div>';} else {var clasname = digit_to_name[strarr[i]];html +='<div class="' +clasname +'">' +'<span class="d1"></span>' +'<span class="d2"></span>' +'<span class="d3"></span>' +'<span class="d4"></span>' +'<span class="d5"></span>' +'<span class="d6"></span>' +'<span class="d7"></span>' +"</div>";}}timerClock.innerHTML = html; }這樣時間組件就算基本完成了,使用的時候只需要引入主頁,放在對應的位置就可以了;
?
搜索組件
搜索組件一共分為兩部分,需要單獨實現,分別為:搜索框,搜索歷史(熱門搜索);
?
搜索框
這個其實簡單,其實就是一個輸入框,并且在其上附加了一個聚焦事件,用于和背景組件的聯動,確認搜索的時候根據搜索類型打開對應的頁簽就可以了,并且確認搜索的時候,將該條搜索條件作為記錄存儲到本地緩存中,所謂歷史記錄的一部分,部分實現代碼如下:
<!-- 輸入框 --> <div:class="['threeS-search-container',{ 'threeS-search-hover': mouseEnter },{ 'threeS-search-active': glass },]"@mouseenter="handleMouseEvent"@mouseleave="handleMouseEvent" ><div class="threeS-search-body"><inputclass="threeS-search-input"type="text":placeholder="glass ? '' : '搜索內容'"@focus="handleFocus"v-model="searchValue"@keyup.enter="handleSearch"/><buttonv-if="glass"class="icon iconfont icon-magnifier search-icon"@click="handleSearch"></button></div> </div> <!-- 搜索類型 --> <div:class="['threeS-search-type-container',{ 'threeS-type-focus': glass },]" ><divclass="threeS-search-type":class="[{ 'is-active': item.id === searchType }]"v-for="item in searchTypeList":key="item.id"@click="handleSearchType(item)">{{ item.name }}</div> </div>這個是HTML部分,從結構上看沒有什么復雜的,只是搜索的按鈕需要融入搜索框的背景之中,不顯突兀;
const searchTypeList: searchType[] = [{name: "百度",id: "baidu",url: "https://www.baidu.com/s?wd=",},{name: "谷歌",id: "google",url: "https://www.google.com/search?q=",},{name: "必應",id: "bing",url: "https://cn.bing.com/search?q=",},{name: "淘寶",id: "taobao",url: "https://s.taobao.com/search?q=",}, ]; const searchType: Ref<string> = ref(searchTypeList[0].id); const searchUrl: Ref<string> = ref(searchTypeList[0].url);function handleSearchType(item: searchType): void {searchType.value = item.id;searchUrl.value = item.url; }這個一部分搜索類型時的代碼,這部分也不復雜,但是這部分又很關鍵,因為每個平臺的搜索地址前綴到底是什么樣的,網絡上查了很久都沒查到合理的答案,只能自己試,試了好久才發現;
?
歷史記錄
歷史記錄這一塊主要的知識點在Vue部分其實就是一個for循環,通過對數據的便利將其展示出來,對了,還有有一個,就是數據的來源,這里的一部分是來自于后臺接口,一部分是來自于本地的localstage,這里存在一個數據合并的問題以及清除歷史記錄時需要對本地的localstage進行同步清理,下面是部分代碼
// ---------- 歷史信息 start ---------- const getHistoryInfo: any = computed(() => store.getters["basic/basic/getHistory"] );watch(() => getHistoryInfo.value,(value) => {historyList.value = value;} );const updateHistory: ActionMethod = (history: urlInterface[]) =>store.dispatch("basic/basic/updateHistoryInfo", history);/*** 清除歷史記錄* @param {Object} item 待清除的項*/ function handleClearHistory(item: urlInterface): void {const newHistoryInfo: urlInterface[] = getHistoryInfo.value.filter((el: urlInterface) => {return el.url !== item.url;});// 更新updateHistory(newHistoryInfo); }function goHistoryUrl(item: urlInterface): void {window.open(item.url); }/*** 清除全部歷史記錄*/ function clearHistory() {// 更新updateHistory([]); } // ---------- 歷史信息 end ----------?
快捷入口
快捷入口的難點其實在于ICON的展示,至于關于Vue的知識點其實也同樣跟上面一樣是一個v-for的循環,將數據遍歷并展示出來,并為其增加點擊事件,點擊后直接打開新窗口;
至于ICON的難點在于一開始使用的是iconfont的Font class模式,但是后來發現Font class模式有一個最大的缺點:無法展示多色,因此整個icon都是一個個單色的方塊,后來通過仔細了解字體模式,發現了它SVG的用法,使用SVG可以將其展示成多色,當然這個模式也有一個缺點,就是對瀏覽器的兼容沒那么好,但是,IE什么的本來就不再考慮了,以下是部分代碼:
小結
通過本項目,目的是為了更好的了解Vue3,畢竟Vue3已經正式發布,雖然項目中不會立即使用到,但是對于Vue3的理解已經是必須提上行程了,同時也必須去調研日常所用的插件,工具函數等是否能在Vue3+TypeScript中得到良好的運用;
?
好了,本文差不多就到這里,如果有任何問題歡迎留言提問,相互學習,一起成長!
總結
以上是生活随笔為你收集整理的《Vue3+TS》开发一个自己的起始页的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 异常--------JavaSE
- 下一篇: html5倒计时秒杀怎么做,vue 设