效果展現:
https://blog.csdn.net/qq_42239520/article/details/88534955html
所用技術清單
項目地址:項目地址
vue代碼地址:vue代碼地址前端
項目部分過程筆記:vue
項目結構ios
Secondhanbook / 項目目錄 apps v1 __init__.py 導入 urls urls.py 路由配置 forms.py models.py views user_views.py 用戶相關視圖 book_vews.py 書籍相關視圖 config.py 配置文件 run.py 項目啓動文件 manage.py 數據庫遷移文件 Secondhanbook.py 初始化文件 utils 工具類目錄 ...... ......
1. Flask_RESTful 的返回 和 緩存時候的自定義返回git
flask_restful 在視圖方法上加上marshal_with 裝飾器,並傳遞你返回的模式。但當自定義時,須要返回本身的模式github
return marshal(books,self.resource_fields,envelope='data') resource_fields:自定義返回模式 data: 返回時,數據包裝
2. 使用Flask_RESTful 下表單驗證以及csrf防護redis
每當用戶進入提交Post請求的頁面,實例化一個表單form,返回csrf_tokenvuex
csrf_token = form.csrf_token.current_token return restful.success(data=csrf_token)
3.路由配置數據庫
api = Api(prefix='/api') #用戶相關 api.add_resource(Login,'/login/',endpoint='login') ...... #書籍相關 api.add_resource(BookAddView,'/bookadd/',endpoint='bookadd') ......
4.使用itsdangerous生成臨時身份令牌
生成令牌json
def generate_auth_token(self,expiration=172800):#兩天過時 s = Serializer(config.BaseConfig.SECRET_KEY,expires_in=expiration) return s.dumps({'id':self.id})
身份檢驗
def verify_auth_token(token): s = Serializer(config.BaseConfig.SECRET_KEY) try: data = s.loads(token) except Exception as e: return None user = FrontUserModel.query.get(data['id']) return user
5.配置文件的書寫方式,類繼承的方式
class BaseConfig(object): pass class DevelopmentConfig(BaseConfig): pass class OnlineConfig(BaseConfig): pass
6. celery 處理費時任務
@celery.task def send_mail(subject,recipients,user_id): ...... @celery.task def BookCacheAdd(books): ......
7.redis 存儲數據bytes 問題解決
cache = redis.StrictRedis(host='127.0.0.1',port=6379,db=0,decode_responses=True)
8. 封裝jsonfy的返回
class HttpCode(object): Ok = 200 ParamerError = 400 Unauth = 401 ServerError = 500 def RestfulResult(code,message,data): return jsonify({'code':code,'message':message,'data':data}) def success(message="",data=None): return RestfulResult(HttpCode.Ok,message=message,data=data) ......
9.對axios 提交bytes類型數據進行form驗證
from werkzeug.datastructures import MultiDict ...... myform = json.loads((request.data.decode('utf-8'))) form = LoginForm(MultiDict(myform)) ......
10. flask 接收 接收多個文件axios 上傳的多個文件
** AddBookView ** files = request.files for file in files.values(): filename = upload.change_filename(secure_filename(file.filename)) **upload.vue** for (var i = 0; i < this.files.length; i++) { this.formdata.append('file' + i, this.files[i]) } axios.post('api/bookadd/', this.formdata, { headers: {'Content-Type': 'multipart/form-data'} }).then(this.handleAxiosDone)
11.表單對files, 輸入字段驗證
from werkzeug.datastructures import CombinedMultiDict form = Yourform(CombinedMultiDict([request.form, request.files])) // 合併 數據和文件 文件驗證: 定義表單時,採用FileField這個類型 驗證器導入:flask_wtf.file flask_wtf.file.FileRequired 驗證是否爲空 flask_wtf.file.FileAllowed 驗證上傳文件後綴名
項目結構
...... src common footer 頁腳 alert 提示 fade 動畫 gallary 畫廊 ...... store ... vuex相關 pages home components header.vue ...... Home.vue detail me sign ...... ......
1. flask_result 返回時,提供默認值
返回數據時,當axios 未返回渲染到頁面時,使用變量出錯。
**** 解決方法: 定義默認值 例若有使用book.owner.username , book.owner.avatar時,不然報錯無定義,並沒有法顯示。
book: { owner: {......Object} },
2. vuex store一個Message,供於消息提醒
項目基本上每一個頁面都有操做結果的提醒,封裝一個消息提醒的組件 alert.vue
<div v-show="isshow" class="alertBox" :style="{background:this.$store.state.color}"> {{mymessage}} </div> ...... computed: { mymessage () { return this.$store.state.message } }, watch: { mymessage (e) { this.isshow = true } }
state: { message: '默認值', color: '' }, mutations: { msgchange (state, res) { state.message = res.message // color 自定義消息 state.color = res.color // color 自定義顏色 setTimeout(() => { state.message = '' state.color = '' }, 3000) } } **** 重點:必須重置,不然下一次同樣的消息將不顯示 組件寫一個發送提醒消息的方法,方便屢次調用 handleemit (message, color) { this.$store.commit('msgchange', {message: message, color: color}) }
3. 登錄註冊:
利用 vue mounted 生命週期函數請求後端返回的csrf_token , 以及檢驗本地 localStorage,token是否過時。首次登錄成功返回存儲token
localStorage.setExpire('token', res.headers.token, 1000 * 60 * 60 * 24 * 2) // 設置兩天過時 註冊發送email 激活帳號
4 . 使用better-scroll 加載更多
swiper 盒子必須小於content高度才能滾動
能夠滾動後,頁面將不能點擊,解決:**** this.scroll = new BScroll(this.$refs.wrapper, { click: true, ...... 監聽下拉方法,加載更多 pullUpLoad: { // 當上拉距離超過盒子高度的的時候,就派發一個上拉加載的事件(觸發條件) threshold: 0 } 監聽事件 this.scroll.on('pullingUp', () => { axios.get('/api/booklist/?start=' + this.start).then(this.handleAxiosSuccess) }) *** 對於下拉加載更多,雙重遍歷,遍歷頁碼對應的數據 v-for="(p,index) in page" v-for="item in booklist[index]" :key="item.id" // booklist[index] 爲第幾回下拉的返回的數據
5. vue-awesome-swiper
圖片點擊事件 監聽事件: on: { click: function (e) { window.open(e.target.src) // 跳轉到網頁 } } 使用: <swiper :options="swiperOption"> swiperOption爲參數{ loop: true,effect: 'fade'......} <!-- slides --> <swiper-slide v-for ='item of swiperList' :key="item.id"> <img class="swiper-img" :src="item.url" alt=""> // 傳遞圖片url </swiper-slide> </swiper> 畫廊 組件關鍵參數: // observer啓動動態檢查器(OB/觀衆/觀看者),當改變swiper的樣式(例如隱藏/顯示)或者修改swiper的子元素時,自動初始化swiper。 // 默認false observer: true, observeParents: true
6. 過濾器,傳遞data中的值,而且使用v-html 顯示
v-html="$options.filters.filemotion(comment.content,emotions)" // emotions: [] 是data中自定義的值 本過濾器是對,表情的插入表情標籤的過濾 [贊] [哈哈] 替換成 圖片 方法: emotions格式 : filemotion (value, emotions) { value = value.replace(/(\[.+?\])/g, (e, e1) => { for (var i in emotions) { if ((emotions[i].value.indexOf(e1)) > -1) { return '<img src="' + emotions[i].icon + '">' } } }) return value }
7. axios 更改請求頭:
axios.post('/api/comment/',參數, { headers: { 'Content-Type': 'application/json' ...... } })
8. Proxytable設置跨域,進行數據交互
proxyTable: { '/api': { target: 'http://127.0.0.1:5000', //目標接口域名 changeOrigin: true, //是否跨域 pathRewrite: { '^/api': '/v1/api/' //重寫接口 } } }
9.router 模式
路由 mode="history"模式
當前端項目結合到flask 項目中,當vue 路由爲history模式時,出現「刷新頁面報錯404」的問題
這是由於這是單頁應用…實際上是由於調用了history.pushState API 因此全部的跳轉之類的操做 都是經過router來實現的,解決這個問題很簡單,只須要在後臺配置若是URL匹配不到任何靜態資源
進入新頁面,不回到頁面頂部解決:
scrollBehavior (to, from, savedPosition) { return { x: 0, y: 0 } },