這個百度貼吧的項目是 vue + koa + sequelize 的項目。
由于沒有百度貼吧API接口,所以自己寫了后端
項目部分截圖(GIF)前端:vue + vuex + axios + better-scroll +iview + stylus (還有零散的依賴,完成某些小模塊的,如 moment 完成項目內時間的需求)
前端依賴項
"dependencies": { "axios": "^0.19.0", "better-scroll": "^1.15.2", "iview": "^3.4.2", "js-cookie": "^2.2.0", "jsonwebtoken": "^8.5.1", "moment": "^2.24.0", "vue": "^2.5.2", "vue-photo-preview": "^1.1.3", "vue-router": "^3.0.1", "vuex": "^3.1.1" },
后端:koa + koa-router + mysql2 + sequelize (這些是主要的,還有很多的中間件)
后端依賴項
"dependencies": { "bcrypt": "^3.0.6", "env2": "^2.2.2", "jsonwebtoken": "^8.5.1", "koa": "^2.7.0", "koa-body": "^4.1.0", "koa-bodyparser": "^4.2.1", "koa-jwt": "^3.5.1", "koa-router": "^7.4.0", "koa-session": "^5.12.0", "koa-static": "^5.0.0", "koa2-cors": "^2.0.6", "mysql2": "^1.6.5", "sequelize": "^5.8.12" },
前端代碼初始化是用來vue-cli的腳手架。
圖標是來自阿里巴巴矢量圖標庫,找到的圖標盡量和百度貼吧一致
前端的UI框架選擇了iview(選擇有些失誤,因為百度貼吧的項目是移動端的,應該采用像vant這類優秀的移動端UI框架會更合適)
準備工作是添加一些路徑項 在build目錄下的webpakc.base.conf.js文件中的alias選項中添加一些接下來項目中常用的路徑
該項目的權限控制只采用了一個token,比較簡單,但不是很安全。有興趣可以看看權限控制
由于前后端分離寫的代碼,所以導致登錄認證時設置的cookie 不能在前端取到(應該是域名訪問的問題,取出來是undefined),所以只能將token信息傳給前端,讓前端自己設置cookie(權益之計,不建議采用)
沒有API,也沒寫爬蟲,所以數據都是手寫的,數據量很少,所以一些效果無法實現。
最近看過的帖子和最近訪問的吧, 這兩個模塊的數據是采用localStorage存數據,其它的數據均來自后端
因為后端寫的不是很好,就不講后端的內容了
項目啟動 Tabbar這是成品效果
采用了vue-router 中 router-link to屬性配置的效果
點擊的該項會多出兩個class屬性
router-link-exact-active (精確匹配規則,路由路徑完全一致時會有)
router-link-active (全包含匹配規則,也就是父路由也會有)
將linkActiveClass: "active"添加至router 配置中會將router-link-active 替換成active
這時就也可自定義active的樣式了
頁面結構大體分為5個部分,和零散的幾個頁面,5個部分中其中4個(除info)分別對應4個tabbar選項,將頁面劃分開來。
info中有三個page,分別是userInfo,baInfo,tieInfo
路由將5個部分分開定義,最后匯總
因為該項目的登錄認證對頁面變化很大,所以在路由的beforeEach鉤子函數中進行登錄狀態的判斷,對必須登錄才能訪問的頁面進行強制的登錄判斷,不通過則跳轉到登錄頁。
router.beforeEach((to, from, next) => { // 一定需要登錄的url 沒有認證信息 進行登錄 if (routerLoginRole.some(route => to.path === route) && !Cookies.get("username")) { next("/login") return } }
必須登錄的頁面如下
export const routerLoginRole = [ "/release", "/message", "/user", "/focuslist", "/fanslist", "/focusbalist", "/tielist", "/setting", "/userhome", "/useredit", "/browsehistory", "/collection", "/release", "/like" ]
同時,不同的頁面 tabbar顯示和消失狀態也不同,將tabbar的顯示狀態放入vuex 中,在beforeEach鉤子函數中統一管理
if (TabbarRoutes.some(route => (to.path.indexOf(route) === 0))) { store.dispatch("hiddenTabbar") } else { store.dispatch("showTabbar") }
需要隱藏tabbar的頁面如下
export const TabbarRoutes = [ "/login", "/register", "/search", "/focuslist", "/fanslist", "/focusbalist", "/tielist", "/setting", "/userhome", "/useredit", "/userinfo/", "/tieinfo/", "/bainfo/", "/browsehistory", "/release", "/collection", "/like" ]抽離基本配置以及插件
iview組件的引入方式采用按需引入,在utils目錄下創建一個iview.js 將iview引入的代碼進行統一管理。
import Vue from "vue" import { Button, Input, Switch, Progress, Form, FormItem, Icon, Upload, Dropdown, DropdownMenu, DropdownItem, Message, Spin } from "iview" import "iview/dist/styles/iview.css" Vue.component("Button", Button) Vue.component("i-input", Input) Vue.component("i-switch", Switch) Vue.component("Progress", Progress) Vue.component("Form", Form) Vue.component("FormItem", FormItem) Vue.component("Icon", Icon) Vue.component("Upload", Upload) Vue.component("Dropdown", Dropdown) Vue.component("DropdownMenu", DropdownMenu) Vue.component("DropdownItem", DropdownItem) Vue.component("Spin", Spin) Vue.prototype.$Message = Message export default Vue
filter 全局過濾器,使用moment實現對時間的處理,數字的處理,統一進行管理
對axios設置了攔截器,功能有三:
1.設置axios請求的默認路徑以及運行其攜帶cookie信息
2.部分api接口需要登錄驗證 則需要傳給服務器包括token的cookie憑證
3.請求數據時的加載動畫
axios.defaults.baseURL = "http://192.168.1.4:3000/" axios.defaults.withCredentials = true axios.defaults.timeout = 5000 axios.interceptors.request.use( config => { // 給$http請求設置cookie請求頭 store.dispatch("showLoading") const token = Cookies.get("username") const isTokenRight = !!(token && JsonWebToken.decode(token)) if (isTokenRight) { config.headers.common["Authorization"] = "Bearer " + token } return config }, error => { Message.error("網絡異常,請稍后再試") store.dispatch("hiddenLoading") return Promise.reject(error) } ) axios.interceptors.response.use( response => { store.dispatch("hiddenLoading") if (response.data.statusCode !== 200) { Message.error(response.data.message) return Promise.reject(response) } return response }, error => { Message.error("網絡異常,請稍后再試") store.dispatch("hiddenLoading") return Promise.reject(error) } )部分功能具體實現 首頁刷新功能
效果圖
分為兩個階段
首先是監聽滾動的事件,滾動值超過某個值(個人設置500),觸發事件將tabbar中的首頁替換成刷新按鈕。
點擊刷新按鈕,將vuex中的refreshData屬性變為true。然后在首頁中監聽這個屬性,重新加載數據并且觸發better-scroll的滾動事件,讓其滾動到最上方。
其中還是有些小問題的:
tabbar是采用router-link, 會在其事件冒泡階段阻止事件冒泡,進行其自身的路由跳轉事件,從而無法觸發自定義的事件,解決辦法是在其內部處理掉點擊事件(也就是點擊事件冒泡到其渲染的元素之前處理掉點擊事件,并阻止點擊事件的冒泡)
tabbar頁面中首頁選項的html結構
其觸發的刷新方法
refresh () { if (this.$store.getters.isRefresh) { this.$store.commit("updateRefreshData", true) } },
要避免多余的加載數據,所以采用了keep-alive標簽,在觸發better-scroll的scrollTo方法時,方法無效,具體原因不知,但后面發現自己的better-scroll的版本是基礎型的,后面換成全能力滾動后,就可以正常使用了(有知道具體原因的朋友可以聊一下)
實現優質的左右滾動效果圖
html可分為兩部分 頂部的三個tab 和 下面的三個頁面
頂部的tab動畫效果為css的transition: all 0.3s ease
頁面采用了better-scroll,并在scrollEnd鉤子函數中進行相關操作。
頂部的標記滑動事件
romve (index) { let name = "message-title-" + index this.index = index this.oldX = -index * this.$refs["message-content"].offsetWidth this.$refs.unline.style.left = this.$refs[name].offsetLeft + "px" this.contentScroll.scrollTo(-this.$refs["message-content"].offsetWidth * index, 0, 300) },
左右滾動的初始化
initScroll () { this.$nextTick(() => { if (!this.contentScroll) { this.contentScroll = new BScroll(this.$refs["message-content"], { startX: 0, click: true, tap: true, scrollX: true, scrollY: false, momentum: false // 不讓其生成滾動的滑行動畫 }) } else { this.contentScroll.refresh() } this.contentScroll.on("scrollEnd", ({ x }) => { let width = this.$refs["message-content"].offsetWidth // 獲取單個頁面的寬度 if (x !== -width && x !== -2 * width && x !== 0) { // 避免自動滾動后繼續滾動 if (Math.abs(x - this.oldX) < width / 4) { // 滾動量小于整個頁面的1/4時 自動復原 this.contentScroll.scrollTo(-this.index * width, 0, 300) } else if (this.oldX > x) { // 向左滑動時 自動滾到到右邊頁面 this.contentScroll.scrollTo(-(++this.index) * width, 0, 300) } else { // 向右滑動時 自動滾到到左邊頁面 this.contentScroll.scrollTo(-(--this.index) * width, 0, 300) } this.oldX = -this.index * width // 重新計算值 this.romve(this.index) // 使頂部的標記滑動到對應的位置 } }) this.romve(0) // 頂部的標記初始化到第一個 }) }頁面布局
html方面
主要采用div,span,img,p 等標簽
css方面
選擇器采用的class選擇器
布局主要采用 flex 布局
z-index的層級上是 1-9 ,文字層級低,動畫蒙版等層級略高。
icon圖標的定義是采用了background 的形式
background-size: 30px 30px background-repeat: no-repeat background-position: center center background-image: url("../../assets/icon/left.png")
要注意的問題:
z-index的層級問題,子元素會繼承父元素的層級。
設置了層級,還是會出現下層元素上浮的問題,有可能是上層元素是透明的,添加背景顏色就可以。
應減少使用js的setInterval形成的幀動畫,而應該采用css形成的補間動畫。
結語各個頁面的小功能寫的不多,但很多模塊難度問題不大,沒有詳細寫的必要,具體可看源碼。
整個項目寫下來,也有不少的問題。主要還是整體性上有欠缺,組件化不夠徹底。UI風格上還是沒辦法和百度貼吧一致(有一定的偏差)。
如果你喜歡這篇文章或者可以幫到你,給作者一點鼓勵,點個贊在走吧!同時也非常希望看到這篇文章的你能發表一點見解!
前端源碼
后端源碼
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/105617.html
稍微整理了一下自己平時看到的前端學習資源,分享給大家。 html MDN:Mozilla開發者網絡 SEO:前端開發中的SEO css 張鑫旭:張鑫旭的博客 css精靈圖:css精靈圖實踐 柵格系統:詳解CSS中的柵格系統 媒體查詢:css媒體查詢用法 rem布局:手機端頁面自適應布局 移動前端開發之viewport的深入理解:深入理解viewport 淘寶前端布局:手機淘寶移動端布局 fl...
摘要:但是,有一件事是肯定的年對全棧開發者的需求量很大。有一些方法可以解決這個問題,例如模式,或者你可以這么想,其實谷歌機器人在抓取單頁應用程序時沒有那么糟糕。谷歌正在這方面努力推進,但不要指望在年會看到任何突破。 對于什么是全棧開發者并沒有一個明確的定義。但是,有一件事是肯定的:2019 年對全棧開發者的需求量很大。在本文中,我將向你概述一些趨勢,你可以嘗試根據這些趨勢來確定你可能要投入的...
閱讀 1751·2021-09-27 14:02
閱讀 3100·2021-09-27 13:36
閱讀 1046·2019-08-30 12:46
閱讀 1834·2019-08-30 10:51
閱讀 3571·2019-08-29 17:02
閱讀 941·2019-08-29 16:38
閱讀 1846·2019-08-29 16:37
閱讀 3004·2019-08-26 10:32