久久亚洲成a人片熟女精品色一区二区三区|国产精品视频第一精品视频|av天堂热无码手机版|亚洲?v无码久久无遮挡|国产精品偷伦视频免费观看国产|麻豆国产自产精品丰满熟妇|av无码av不卡一区二区|久久亚洲精品中文字

ARTICLE DETAIL

資訊詳情

深耕商務(wù)建站與企業(yè)官網(wǎng)運營的一線實戰(zhàn)洞察。

Vuex 4 狀態(tài)管理全解析:核心原理、模塊拆分與高頻踩坑

Vuex 4 狀態(tài)管理全解析:核心原理、模塊拆分與高頻踩坑 Vuex 這玩意兒現(xiàn)在提起來有點微妙。新項目里 Pinia 基本是默認選項很多人一上手 Vue 3 就沒碰過 Vuex。但你去翻一翻手上維護的那些跑了三四年的中后臺系統(tǒng)十有八九還在store/index.js里躺著幾十個 mutation改一個字段要先找 action、再找 mutation、最后才敢動 state。這時候你要是連 Vuex 的執(zhí)行鏈路都說不清楚排查問題基本靠猜。這篇就把 Vuex 的知識點掰開揉碎講透從“到底什么時候該用它”到“store 怎么拆模塊”再到“為什么我的 commit 沒生效”這類真實踩坑全部過一遍。適合兩類人看一類是剛接手老項目、被mapState和各種root: true繞暈的新手另一類是想把狀態(tài)管理這塊徹底搞清楚、以后不管換 Pinia 還是別的庫都能快速上手的同學。代碼以 Vuex 4 Vue 3 為主線涉及 Vue 2 的差異我會單獨標出來。1. 先搞清楚什么時候真的需要 Vuex1.1 狀態(tài)管理的邊界到底在哪我在帶人的時候發(fā)現(xiàn)一個特別普遍的問題很多人學完 Vuex 的第一反應(yīng)是“好東西全塞進去”。結(jié)果一個只有三個頁面的小工具store 里堆了二十多個字段其中一半是某個組件內(nèi)部的彈窗開關(guān)。這就屬于把狀態(tài)管理當成了全局變量倉庫最后維護成本比不用還高。判斷一個狀態(tài)該不該進 store我一般看三條第一這份數(shù)據(jù)是不是被兩個以上互不相鄰的組件同時使用。父子組件之間傳值props加emit就夠了爺孫層級深一點provide/inject也能解決。只有當兄弟組件、或者跨了好幾層的遠房親戚都要讀寫同一份數(shù)據(jù)時才輪到 Vuex 出場。第二這份數(shù)據(jù)是不是跨越了路由。比如登錄態(tài)、用戶信息、權(quán)限菜單從 A 頁面跳到 B 頁面還得用這種放在組件里必然會隨著組件銷毀而丟失必須提上去。第三這份數(shù)據(jù)變更后是不是需要留下可追溯的痕跡。Vuex 配 devtools 能記錄每一次 mutation 的時間旅行對于復雜的表單聯(lián)動、購物車增刪改這個調(diào)試能力值不少時間。反過來說哪些不該進 store組件的 loading 狀態(tài)、某個列表的滾動位置、彈窗的顯隱開關(guān)這些都屬于“局部狀態(tài)”跟著組件生命周期走才是最干凈的。我見過有人把dialogVisible放進 store結(jié)果兩個頁面復用同一個彈窗組件時互相干擾排查了半天才發(fā)現(xiàn)是狀態(tài)被共享了。記住一句話狀態(tài)放得越高耦合就越重能不升就不升。還有一種常見誤區(qū)是把接口返回的原始數(shù)據(jù)全量塞進 store然后組件里再filter一遍。這樣做的問題在于 store 變成了緩存層但你又沒做失效策略最后數(shù)據(jù)新舊不一致的 bug 特別難查。我的習慣是 store 只存“經(jīng)過業(yè)務(wù)加工、有明確語義”的狀態(tài)原始響應(yīng)體在 action 里處理完就丟掉。1.2 Vuex 和 Pinia 到底怎么選這個話題繞不開。Pinia 確實是官方現(xiàn)在主推的方案API 更簡潔、TypeScript 支持更好、沒有 mutation 這一層。但“新項目用 Pinia”不等于“Vuex 就沒用了”。我整理了一張對照表你對著自己項目的情況看就行。對比維度Vuex 4Pinia變更入口mutation 提交action 觸發(fā)直接改 stateaction 里也能改模塊機制modules namespaced 嵌套每個 store 天然獨立TypeScript 支持需要額外類型聲明較繁瑣原生推導幾乎零配置devtools 時間旅行支持粒度到 mutation支持粒度到 action代碼量一個功能要寫 state/getter/mutation/action 四份基本一份 setup 或 option 就夠?qū)W習曲線概念多鏈路長概念少接近組合式函數(shù)存量項目兼容原生可與 Vuex 共存逐模塊遷移適合場景老項目維護、團隊已有約定新項目、TS 重度使用我的實際經(jīng)驗是已經(jīng)在跑的 Vuex 項目別為了追新去動它。遷移本身不難難的是遷移期間兩套狀態(tài)管理并存帶來的心智負擔以及測試覆蓋不足時的回歸風險。真要遷也是按模塊一個個搬先把用戶模塊搬過去跑一周沒問題再搬下一個。反倒是新起的項目沒有歷史包袱直接上 Pinia 更省事。不過有一點要說清楚Vuex 那套“mutation 必須同步、action 處理異步”的約束雖然寫起來啰嗦但它強迫你把“改數(shù)據(jù)”和“做業(yè)務(wù)”分開這個思維在團隊協(xié)作里是有價值的。很多 Pinia 新手直接在 action 里一頓this.xxx yyy出了問題連是哪一步改的都定位不到。所以就算你用的是 Pinia也建議保留“純函數(shù)式改狀態(tài)”的習慣。1.3 一張判斷清單幫你決定要不要引入我給自己團隊寫過一個很土但很好用的清單五個問題中三個以上才考慮上 Vuex有沒有一份數(shù)據(jù)被三個以上的組件讀取且這些組件不在同一條父子鏈上這份數(shù)據(jù)會不會因為路由切換而需要保留這份數(shù)據(jù)的修改是否需要多人協(xié)作、且改動點分散在多個文件出問題時是否需要回放“誰在什么時候改了什么”項目規(guī)模是不是已經(jīng)超過二十個頁面或者五個以上的業(yè)務(wù)模塊如果只中一兩條老老實實用props加組合式函數(shù)封裝別給自己找事。狀態(tài)管理的本質(zhì)是降低溝通成本不是炫技。2. Vuex 的五個核心概念一次捋直2.1 state單一狀態(tài)樹和它的設(shè)計原則Vuex 把所有狀態(tài)收攏到一棵樹里官方叫單一狀態(tài)樹Single Source of Truth。好處是任何一個時刻你都能通過store.state拿到應(yīng)用完整的數(shù)據(jù)快照調(diào)試的時候特別直觀。壞處是這棵樹如果沒人管長到幾百個字段之后新人進來根本看不懂哪個字段屬于哪個業(yè)務(wù)。我的做法是按業(yè)務(wù)域切分而不是按數(shù)據(jù)類型切分。什么叫按數(shù)據(jù)類型切就是state.list、state.detail、state.loading這么平鋪看著整齊實際上一旦業(yè)務(wù)變多就全亂。按業(yè)務(wù)域切就是user、order、permission各占一塊每個模塊自洽。具體到寫法Vuex 4 里定義模塊的 state 一定要用函數(shù)返回對象// store/modules/user.js const state () ({ profile: null, token: , roles: [], permissionLoaded: false })為什么必須是函數(shù)因為模塊在注冊時會被合并進根 state如果直接寫對象字面量多個組件實例或者熱更新場景下會共享同一份引用出現(xiàn)“A 頁面改了 B 頁面也變了”的靈異事件。這個坑我在服務(wù)端渲染的項目里踩過一次排查了整整一個下午。另外 state 里的字段命名要帶語義。data、info、list這種詞盡量別用orderList、userProfile、pendingTaskCount一眼就知道是什么。字段一多命名就是最好的文檔。2.2 getters派生狀態(tài)和它的緩存機制getters 可以理解為 store 里的 computed。它的返回值會基于依賴做緩存依賴不變就不重新計算。這個特性用好了能省不少性能用不好反而會成為 bug 來源。const getters { isLogin: state Boolean(state.token), displayName: state state.profile?.nickname || state.profile?.username || 未登錄, // 依賴其他 getter第二個參數(shù)是當前模塊的 getters welcomeText: (state, getters) ${getters.displayName}歡迎回來, // 依賴根 state第四個參數(shù)是 rootState hasPermission: (state, getters, rootState) code { return state.roles.includes(code) || rootState.user.roles.includes(code) } }這里有個關(guān)鍵點getter 返回函數(shù)時緩存就失效了。上面hasPermission返回的是一個函數(shù)每次調(diào)用都會重新執(zhí)行因為 Vue 沒法追蹤函數(shù)內(nèi)部用到的參數(shù)。這種寫法適合做權(quán)限判斷這類需要傳參的場景但別在模板里高頻調(diào)用它尤其是列表渲染里v-for每一項都調(diào)一次性能會明顯下降。真要這么用先在 computed 里把結(jié)果算好。還有一個容易翻車的地方getter 里返回新對象。比如// 不推薦每次都返回新數(shù)組緩存形同虛設(shè) filteredList: state state.list.filter(item item.active)因為filter每次執(zhí)行都會產(chǎn)生新數(shù)組引用Vue 的依賴追蹤會認為結(jié)果變了導致依賴這個 getter 的組件反復更新。如果這個列表很大、更新又頻繁頁面會明顯卡頓。正確做法是把過濾邏輯放到組件 computed 里或者用shallowRef之類的思路做手動緩存。我在一個萬級數(shù)據(jù)的表格項目里就吃過這個虧后來把 getter 改成了只做簡單映射流暢度立刻回來了。2.3 mutations為什么它必須是同步的這是 Vuex 里被問得最多的問題?!拔揖驮?mutation 里發(fā)個請求怎么了”答案藏在 devtools 的工作原理里。devtools 記錄狀態(tài)變化的方式是每執(zhí)行一次 mutation就拍一張 state 的快照存進時間線。如果你在 mutation 里發(fā)異步請求那么“mutation 開始執(zhí)行”和“state 真正被改”之間存在時間差devtools 拍到的那張快照可能是請求還沒回來的中間態(tài)。等你點時間旅行回到某一步看到的狀態(tài)和實際不符調(diào)試就徹底失去了意義。所以 Vuex 強制 mutation 同步是為了保證每一幀快照都是確定性的。const mutations { SET_PROFILE(state, payload) { state.profile payload }, SET_TOKEN(state, token) { state.token token }, ADD_ROLE(state, role) { if (!state.roles.includes(role)) { state.roles.push(role) } }, RESET(state) { // 重置時不要直接替換整個 state 對象Vue 會丟失響應(yīng)式追蹤 Object.assign(state, { profile: null, token: , roles: [], permissionLoaded: false }) } }mutation 的命名我統(tǒng)一用全大寫加下劃線這是社區(qū)慣例好處是在 devtools 列表里一眼就能和 action 區(qū)分開。action 用小駝峰比如fetchProfile。這套約定看起來是小事但團隊人多的時候能省掉很多溝通。還有一個細節(jié)mutation 里不要做副作用。什么叫副作用發(fā)請求、寫 localStorage、彈 toast這些都算。mutation 應(yīng)該是一個純函數(shù)給它同樣的輸入state 就變成同樣的結(jié)果。這樣你寫單元測試的時候只需要斷言 state 變化不用 mock 一堆東西。2.4 actions異步編排和業(yè)務(wù)邏輯的落腳點action 是 Vuex 里唯一允許寫異步的地方它不直接改 state而是通過commit觸發(fā) mutation。這個設(shè)計看起來多繞了一層實際上把“業(yè)務(wù)流程”和“數(shù)據(jù)變更”解耦了。const actions { async fetchProfile({ commit, state, dispatch }, force false) { if (state.profile !force) { return state.profile } const res await api.getUserProfile() commit(SET_PROFILE, res.data) // 跨模塊調(diào)用要加 root: true await dispatch(permission/loadRoutes, res.data.roles, { root: true }) return res.data }, async login({ commit, dispatch }, { username, password }) { const { token } await api.login({ username, password }) commit(SET_TOKEN, token) await dispatch(fetchProfile, true) }, logout({ commit }) { commit(RESET) commit(permission/RESET, null, { root: true }) } }action 的返回值很重要。因為 action 內(nèi)部是 Promise你可以在組件里await store.dispatch(login, form)拿到結(jié)果后再做跳轉(zhuǎn)或者提示。很多老代碼里 action 不 return組件只能靠 watch 某個 state 來判斷成功與否這種寫法非常脆弱。養(yǎng)成習慣action 有結(jié)果就 return 出去??缒K dispatch 的{ root: true }是新手最容易漏的參數(shù)。不加這個參數(shù)Vuex 會只在當前模塊內(nèi)查找 action找不到就靜默失敗或者報unknown action type。我第一次遇到的時候盯著代碼看了半小時最后發(fā)現(xiàn)就是少了個 root。2.5 modules 和 namespaced拆分與隔離項目一大單文件 store 必然爆炸。modules 就是用來拆的而namespaced: true決定了拆完之后彼此是否隔離。// store/index.js import { createStore } from vuex import user from ./modules/user import permission from ./modules/permission import cart from ./modules/cart export default createStore({ strict: import.meta.env.DEV, modules: { user: { namespaced: true, ...user }, permission: { namespaced: true, ...permission }, cart: { namespaced: true, ...cart } } })開不開命名空間我的答案是業(yè)務(wù)模塊一律開。不開的話所有模塊的 mutation 都注冊在全局兩個模塊都定義了SET_LOADING后注冊的會覆蓋前一個這種 bug 隱蔽性極強。開了之后方法名變成user/SET_LOADING雖然寫起來長一點但邊界清晰。全局的通用狀態(tài)比如 app 級別的主題、語言可以單開一個不開命名空間的 root 模塊但數(shù)量要克制。嵌套模塊的調(diào)用鏈路也要理清楚。假設(shè)有個setting模塊掛在user下面那么在setting的 action 里調(diào)用兄弟模塊路徑要寫成dispatch(cart/addItem, item, { root: true })。這個 root 參數(shù)指的是“從根開始找”不管你現(xiàn)在在哪一層。記不住的話就記一句只要跨出當前模塊就帶 root: true。3. 從零搭一個能落地的 Store 結(jié)構(gòu)3.1 目錄設(shè)計和模塊拆分原則先看目錄這是我用了幾年、覺得最不容易亂的一種src/ ├── store/ │ ├── index.js // 入口注冊模塊和插件 │ ├── plugins/ │ │ └── persist.js // 持久化插件 │ ├── modules/ │ │ ├── user.js // 用戶信息、登錄態(tài) │ │ ├── permission.js // 路由權(quán)限、菜單 │ │ └── cart.js // 業(yè)務(wù)模塊示例 │ └── helpers.js // 通用工具比如生成 mutation types拆分粒度怎么定我的一般原則是一個模塊對應(yīng)一個業(yè)務(wù)域而不是一個頁面。比如訂單列表和訂單詳情都屬于 order 模塊不要拆成兩個。反過來用戶和權(quán)限雖然是相關(guān)的但職責不同用戶管“我是誰”權(quán)限管“我能看什么”拆開更好維護。模塊內(nèi)部的結(jié)構(gòu)我習慣按state → getters → mutations → actions → 導出的順序?qū)懞?Vuex 的執(zhí)行鏈路一致讀代碼的人從上往下看正好是數(shù)據(jù)流向。文件末尾統(tǒng)一導出export default { namespaced: true, state, getters, mutations, actions }有一點要注意如果模塊之間有數(shù)據(jù)依賴不要在模塊文件里直接import另一個模塊的 state那樣會造成循環(huán)依賴。正確方式是通過rootState讀取或者用dispatch讓對方的 action 來處理。3.2 完整實現(xiàn)一個購物車模塊光說概念沒意思直接上一個能跑的。假設(shè)我們要做一個購物車需求是加商品、改數(shù)量、刪除、算總價、選中狀態(tài)管理。// store/modules/cart.js const state () ({ items: [], // { id, name, price, count, checked } submitting: false }) const getters { totalCount: state state.items.reduce((sum, i) sum i.count, 0), checkedItems: state state.items.filter(i i.checked), totalPrice: (state, getters) { // 金額用分做單位避免浮點誤差最后再除以 100 const cents getters.checkedItems.reduce((sum, i) sum i.price * 100 * i.count, 0) return cents / 100 }, isAllChecked: state state.items.length 0 state.items.every(i i.checked) } const mutations { ADD_ITEM(state, product) { const exist state.items.find(i i.id product.id) if (exist) { exist.count 1 } else { state.items.push({ ...product, count: 1, checked: true }) } }, UPDATE_COUNT(state, { id, count }) { const item state.items.find(i i.id id) if (item) { item.count Math.max(1, Math.min(99, count)) } }, TOGGLE_CHECK(state, id) { const item state.items.find(i i.id id) if (item) item.checked !item.checked }, TOGGLE_ALL(state, checked) { state.items.forEach(i { i.checked checked }) }, REMOVE_ITEM(state, id) { state.items state.items.filter(i i.id ! id) }, SET_SUBMITTING(state, flag) { state.submitting flag }, CLEAR(state) { state.items [] } } const actions { async checkout({ commit, state, rootState }) { if (!state.items.length) return { ok: false, msg: 購物車是空的 } const payload state.items .filter(i i.checked) .map(i ({ productId: i.id, count: i.count })) commit(SET_SUBMITTING, true) try { const res await api.submitOrder({ items: payload, userId: rootState.user.profile?.id }) commit(REMOVE_ITEM_BATCH, res.data.removedIds) return { ok: true, orderId: res.data.orderId } } catch (e) { return { ok: false, msg: e.message } } finally { commit(SET_SUBMITTING, false) } } } export default { namespaced: true, state, getters, mutations, actions }這里有幾個我自己踩過坑之后固定下來的寫法。金額全部用“分”來算最后展示時再轉(zhuǎn)回元0.1 0.2那種經(jīng)典浮點問題在電商場景真的會出事。數(shù)量做了Math.max(1, Math.min(99, count))的鉗制防止用戶在輸入框里手打負號或者超大批量。checkout的返回值統(tǒng)一成{ ok, msg }結(jié)構(gòu)組件層不用 try-catch直接看ok就行。另外REMOVE_ITEM_BATCH我在 mutations 里沒寫實際項目中應(yīng)該補上避免循環(huán)提交單條刪除。這類細節(jié)在真實業(yè)務(wù)里會因為批量操作導致幾十次 commitdevtools 面板直接被刷屏。3.3 組件里怎么調(diào)用四種方式對比Vuex 提供的調(diào)用方式有好幾種很多人只會mapState遇到方法就不知道咋辦了。列個表對照著記場景選項式寫法組合式寫法setup讀 statecomputed(() this.$store.state.user.profile)const profile computed(() store.state.user.profile)讀 getterthis.$store.getters[user/isLogin]computed(() store.getters[user/isLogin])觸發(fā) mutationthis.$store.commit(user/SET_TOKEN, t)store.commit(user/SET_TOKEN, t)觸發(fā) actionawait this.$store.dispatch(user/login, f)await store.dispatch(user/login, f)批量映射...mapState(user, [profile])storeToRefs(store.state.user)配合解構(gòu)組合式 API 里推薦用useStore加storeToRefsimport { computed } from vue import { useStore } from vuex import { storeToRefs } from pinia // 注意Vuex 沒有官方 storeToRefs這里用 toRefs 替代 export default { setup() { const store useStore() // 直接解構(gòu)會丟失響應(yīng)式必須轉(zhuǎn)成 ref const { profile, token } toRefs(store.state.user) const isLogin computed(() store.getters[user/isLogin]) function handleAdd(product) { store.commit(cart/ADD_ITEM, product) } return { profile, token, isLogin, handleAdd } } }補充一句上面代碼里storeToRefs是 Pinia 的 APIVuex 項目要用 Vue 的toRefs配合store.state.模塊名。這個區(qū)別我見過不止一個人寫混。toRefs只能處理普通響應(yīng)式對象store.state本身就是響應(yīng)式的所以能用但store.getters不行因為 getters 是每次訪問時動態(tài)計算的得用computed包一層。選項式 API 里用輔助函數(shù)會簡潔很多import { mapState, mapGetters, mapActions } from vuex export default { computed: { ...mapState(cart, [items, submitting]), ...mapGetters(cart, [totalPrice, isAllChecked]), // 自己再算的派生值 isEmpty() { return this.items.length 0 } }, methods: { ...mapActions(cart, [checkout]), async onSubmit() { const res await this.checkout() if (res.ok) { // 跳轉(zhuǎn)邏輯 } } } }有個小坑要提醒mapState映射出來的名字如果和組件data里的字段重名Vue 會告警而且行為不確定。命名的時候盡量錯開或者在映射時用對象形式重命名...mapState(cart, { cartItems: items })。3.4 嚴格模式、持久化插件和 devtools 配置嚴格模式我強烈建議只在開發(fā)環(huán)境開const store createStore({ strict: import.meta.env.DEV, modules: { ... } })嚴格模式下任何不經(jīng)過 mutation 的 state 修改都會拋錯[vuex] do not mutate vuex store state outside mutation handlers。這個檢查很耗性能因為它需要深度監(jiān)聽整棵 state 樹。生產(chǎn)環(huán)境開嚴格模式在大型應(yīng)用里能明顯感覺到卡頓。用 Vite 的話import.meta.env.DEV就是現(xiàn)成的webpack 環(huán)境用process.env.NODE_ENV ! production。持久化這塊Vuex 本身不提供社區(qū)有插件但也都不太維護了我一般手寫一個三十行的插件// store/plugins/persist.js const KEY APP_STORE_V1 export default function createPersistPlugin(paths []) { return store { // 恢復 const raw localStorage.getItem(KEY) if (raw) { try { const saved JSON.parse(raw) paths.forEach(path { const [module, field] path.split(/) const target module ? store.state[module] : store.state if (saved[path] ! undefined) { target[field] saved[path] } }) } catch (e) { localStorage.removeItem(KEY) } } // 保存做節(jié)流避免頻繁寫入 let timer null store.subscribe((mutation, state) { clearTimeout(timer) timer setTimeout(() { const data {} paths.forEach(path { const [module, field] path.split(/) const target module ? state[module] : state data[path] target?.[field] }) localStorage.setItem(KEY, JSON.stringify(data)) }, 300) }) } }用它的時候只白名單需要的字段createStore({ plugins: [createPersistPlugin([user/token, cart/items])] })為什么只白名單而不是全量存因為submitting、loading這類瞬時狀態(tài)被持久化下來刷新頁面后按鈕會一直處于 loading 狀態(tài)用戶以為卡死了。我見過一個項目把整個 store 都存了 localStorage結(jié)果用戶重新打開頁面上次沒提交完的表單數(shù)據(jù)混著新數(shù)據(jù)出現(xiàn)問題反饋了一堆。4. 高頻踩坑與排查實錄4.1 報錯信息對照表先會看再看懂Vuex 的報錯信息其實寫得挺清楚只是新手不知道往哪查。整理一張表遇到問題先對號入座報錯內(nèi)容大概率原因處理方式[vuex] unknown mutation type: xxx模塊沒開 namespaced或漏寫模塊前綴檢查模塊配置commit 時補上模塊名/[vuex] unknown action type: xxx跨模塊調(diào)用漏了{ root: true }dispatch 第三個參數(shù)加上 root[vuex] unknown getter: xxxgetters 沒導出或訪問路徑錯確認 export default 里有 gettersdo not mutate vuex store state outside mutation handlers開發(fā)環(huán)境嚴格模式直接改了 state把所有賦值搬進 mutation[vuex] module namespace not found in mapState()模塊名拼錯或模塊還沒注冊檢查 createStore 的 modules 鍵名Cannot read property xxx of undefined模塊 state 寫成了對象但被復用state 改成函數(shù)返回數(shù)據(jù)改了但頁面沒更新直接改數(shù)組下標或?qū)ο笮略鰧傩杂?mutation 里整體替換或Vue.setVue 2這張表我自己貼在工位旁邊貼了兩年新人來的時候直接拍照。說實話Vuex 報錯里 80% 都是“路徑寫錯”或者“沒開命名空間”這兩類剩下 20% 是響應(yīng)式丟失。4.2 響應(yīng)式丟失的幾種典型情況Vue 2 時代最經(jīng)典的問題state.list[0] newItem頁面不更新。原因是Object.defineProperty攔截不到數(shù)組下標賦值。Vue 3 換成 Proxy 之后這個問題基本解決了但如果你維護的是 Vue 2 Vuex 3 的項目還是得注意數(shù)組按下標賦值用splice或者整體替換數(shù)組對象新增屬性用Vue.set(obj, key, val)刪除屬性用Vue.delete(obj, key)Vue 3 里雖然 Proxy 能攔截新增和刪除但還是有兩個容易忽略的點。一是reactive對象被解構(gòu)之后失去響應(yīng)式比如const { profile } store.state.user后面profile就是普通對象了怎么改頁面都不動。二是把 state 里的對象直接賦給組件里的變量做雙向綁定v-model一改就直接改了 state繞過 mutation開發(fā)環(huán)境立刻報嚴格模式錯誤。正確的v-model寫法是這樣computed: { keyword: { get() { return this.$store.state.cart.keyword }, set(val) { this.$store.commit(cart/SET_KEYWORD, val) } } }啰嗦是啰嗦但這條鏈路是完整的devtools 能記錄到每一次輸入。如果嫌麻煩就在組件內(nèi)用本地 ref提交時再一次性寫回 store。4.3 性能問題什么時候 store 成了瓶頸Vuex 的性能問題我遇到過的就那么幾類但每一類都很要命。第一類是大列表全量放進 store。有個項目把五千條訂單數(shù)據(jù)放在 state 里每次篩選都要經(jīng)過 getter頁面卡得沒法用。后來改成 store 只存篩選條件列表數(shù)據(jù)留在組件里通過 action 拿問題立刻解決。記住store 適合存“狀態(tài)”不適合存“數(shù)據(jù)集合”。第二類是在 getter 里做重計算。比如對列表做排序、格式化日期、算分組小計這些操作如果依賴頻繁變化getter 會被反復觸發(fā)。我的做法是把這類計算移到組件 computed或者在 store 里緩存一份計算結(jié)果只在源數(shù)據(jù)變化時重算。第三類是過度訂閱。mapState把整個模塊的 state 都映射進來其中某個字段高頻變化導致組件整體重新渲染。用computed精確取需要的字段能緩解一部分更好的辦法是把高頻變化的狀態(tài)比如輸入框的值、鼠標坐標留在組件本地不要進 store。還有一種不太容易發(fā)現(xiàn)的devtools 開著跑生產(chǎn)構(gòu)建。Vuex 的 devtools 集成在開發(fā)模式下才有但如果你不小心在生產(chǎn)包里引入了開發(fā)版本的 Vue性能會差好幾倍。打包配置里確認一下mode和define有沒有問題這個坑我踩過一次找了一周。4.4 老項目遷移與工程化建議如果手上的 Vuex 項目要重構(gòu)我建議按這個順序推進別一把梭。第一步先把所有this.$store的直接調(diào)用收斂成統(tǒng)一的 API 層。寫一個src/store/api.js把常用的讀寫封裝成函數(shù)比如useUser()、useCart()。這一步不改邏輯只是加一層殼風險極低。第二步把模塊的 mutation 命名規(guī)范化。原來可能叫setUser、updateUser、changeUser統(tǒng)一成SET_USER。這一步靠grep加人工核對工作量不大但收益明顯后面遷移 Pinia 時一一對應(yīng)就能改。第三步按模塊遷移。先挑一個依賴最少的模塊比如cart改成 Pinia 的defineStore然后在入口同時注冊兩套。Vuex 和 Pinia 是可以共存的只要別讓同一個業(yè)務(wù)狀態(tài)兩邊都存就行。第四步清理。所有模塊遷完之后刪掉 Vuex 依賴把mapState之類的 import 全部替換。這一步用 ESLint 的自定義規(guī)則能掃出一部分剩下的靠編譯報錯兜底。遷移過程中有個細節(jié)值得說Pinia 的storeToRefs和 Vuex 的toRefs行為不完全一樣直接在組件里解構(gòu)很容易出問題。我當時的做法是先把所有組件里的解構(gòu)都改成computed遷完之后再按需優(yōu)化。寧可多寫幾行也別在響應(yīng)式上翻車。5. 幾個真實場景下的套路組合5.1 登錄態(tài)與路由守衛(wèi)的配合登錄態(tài)是最典型的需要 store 的場景但它和路由守衛(wèi)的配合有個時序問題必須處理。守衛(wèi)在頁面渲染前執(zhí)行這時候如果 store 里的用戶信息還沒加載權(quán)限判斷就會失敗用戶被誤踢回登錄頁。我的處理方式是token 從 localStorage 同步恢復用戶信息異步加載但守衛(wèi)里做“是否已加載”的判斷沒加載就先觸發(fā) action 并等待。// permission.js router.beforeEach(async (to, from, next) { const store useStore() const token store.state.user.token if (!token) { return to.meta.public ? next() : next({ path: /login, query: { redirect: to.fullPath } }) } if (!store.state.user.permissionLoaded) { try { await store.dispatch(user/fetchProfile) await store.dispatch(permission/loadRoutes) } catch (e) { store.commit(user/RESET) return next(/login) } } if (to.meta.roles !store.getters[user/hasPermission](to.meta.roles)) { return next(/403) } next() })這里的關(guān)鍵是permissionLoaded這個標記位。沒有它每次路由跳轉(zhuǎn)都要重新拉一次用戶信息接口壓力大不說頁面還會閃。有了它第一次加載完之后所有跳轉(zhuǎn)都是同步判斷體驗就順了。異步路由用router.addRoute動態(tài)注冊注冊完再next({ ...to, replace: true })重新進入一次否則會白屏。5.2 跨模塊協(xié)作別讓模塊之間互相 import項目一大模塊之間必然有協(xié)作。比如下單成功后要清空購物車、刷新訂單列表、更新用戶積分。這三件事分屬三個模塊怎么串起來最差的做法是在order模塊里import cart from ./cart然后直接調(diào)。這樣寫會形成循環(huán)依賴打包時可能報錯運行時也可能拿到 undefined。正確做法是通過 action 互相 dispatch// order 模塊的 action async createOrder({ commit, dispatch }, payload) { const res await api.createOrder(payload) commit(ADD_ORDER, res.data) // 跨模塊通知各自處理各自的邏輯 await dispatch(cart/clearChecked, null, { root: true }) await dispatch(user/refreshPoints, null, { root: true }) return res.data }這樣order模塊不需要知道cart內(nèi)部怎么實現(xiàn)只要知道有這么個 action 就行。耦合度低測試也好寫。如果模塊數(shù)量多、協(xié)作關(guān)系復雜可以再引入一個“編排層”專門寫跨模塊的 action把業(yè)務(wù)流程集中在一處。還有個小技巧跨模塊讀取數(shù)據(jù)用 getters不要直接讀rootState.xxx.yyy。getters 是一層抽象將來內(nèi)部結(jié)構(gòu)變了只要 getter 的返回不變調(diào)用方就不用改。5.3 表單草稿和列表緩存的取舍后臺系統(tǒng)里最常見的兩個需求表單填一半切走了回來要恢復列表翻到第五頁點進詳情再返回要停在第五頁。表單草稿我的做法是不進 store用sessionStorage加組件內(nèi)的watch做防抖保存。原因很簡單草稿是頁面級的狀態(tài)多個表單同時編輯時放 store 會互相干擾還要處理各種清理邏輯。sessionStorage 天然按標簽頁隔離關(guān)掉就沒了符合直覺。列表緩存反而適合進 store。因為篩選條件、頁碼、排序方式這些是需要跨路由保留的而且詳情頁返回時要用。做法是在list模塊里存一份query對象列表頁onMounted時讀出來發(fā)起請求條件變化時同步更新。要注意的是從菜單重新點進列表時應(yīng)該重置從詳情返回時應(yīng)該保留這個區(qū)分靠路由的meta.keepAlive或者判斷from路徑來做。const actions { async loadList({ state, commit }, { reset false } {}) { if (reset) { commit(RESET_QUERY) } const res await api.getList(state.query) commit(SET_LIST, res.data) } }reset參數(shù)由調(diào)用方?jīng)Q定模塊本身不猜。這種“讓調(diào)用方明確表達意圖”的設(shè)計比在模塊里寫一堆 if 判斷當前路由要清晰得多。6. 我個人在實際項目里的幾點體會寫到這里Vuex 的主要知識點基本都覆蓋了。最后分享幾個不太適合寫進文檔、但實際干活時確實管用的經(jīng)驗。第一別怕寫重復代碼。Vuex 的四段式state/getters/mutations/actions看起來很啰嗦但每多寫一行將來排查問題時就少猜一次。我曾經(jīng)為了省事把 mutation 和 action 合并成一個函數(shù)結(jié)果 devtools 里全是匿名調(diào)用出問題時完全不知道是誰改的。后來老老實實拆開調(diào)試效率反而高了。第二給 store 加注釋比加文檔有用。每個模塊文件頂部寫清楚這個模塊管什么、依賴誰、被誰依賴比單獨維護一份文檔靠譜得多。文檔會過期代碼不會。我現(xiàn)在接手新項目第一件事就是看 store 模塊的頂部注釋五分鐘就能摸清業(yè)務(wù)脈絡(luò)。第三調(diào)試時善用 devtools 的 import/export。Vuex 面板可以把當前狀態(tài)導出成 JSON也能導入一份狀態(tài)來復現(xiàn)問題。遇到用戶反饋的詭異 bug讓對方導出一份狀態(tài)文件本地導入后就能完全復現(xiàn)當時的場景比反復溝通效率高太多。這個功能知道的人不多但真的好用。第四測試只測 action 和 getter。state 和 mutation 太簡單測了也是形式主義。真正有價值的是 action 里的業(yè)務(wù)流程和 getter 里的計算邏輯這兩塊寫單測覆蓋率能上一個大臺階。測 action 的時候記得 mock 掉commit和dispatch用jest.fn()或者vi.fn()都行斷言調(diào)用參數(shù)就夠了。最后提一句狀態(tài)管理這塊工具會換但“什么狀態(tài)該放在哪一層、變更走什么路徑、如何保證可追溯”這三個問題不會變。把 Vuex 這套東西吃透換成 Pinia、換成任何別的方案思路都是通用的。
返回列表
PREV
查看更多資訊
NEXT
返回資訊列表
精品无码久久久久久久杏吧| 亚乱色| 人妻性爱一区二区| 爽爽爽免费视频| 色官网色综合| 四虎国产精品永久在线囯在线| 国产天美传媒精品| 欧美精品四区| 国产精品自在线发布| 视频不卡中文字幕| 男人天堂网手机版婷婷| 精品一区二区3区| 国产精品免费日韩| 九九草| 91网站视频在线观看| **一级毛片国产| 久9re热视频这里只有精品| 天天做天天爱夜夜爽毛片试看| 久操大香蕉超碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰 | 骚逼自拍99| 亚洲天堂热| 大香网站| 国产精品一区av在线| 欧美性高潮| 久久久久久久久久久久久久9999| 91久久久久久| 久久久久久久久成人av解说| 人人看人人爰人人操| 色欧美综合| 九九久久久九九| 在线视频日韩欧美国产| 中文字幕在线高清男人的天堂| 干我久操| 亚洲精品成人动漫在线| 极品销魂美女一区二区 | 国产精品久久久久久久久久久久久久吹 | 嗯嗯,啊啊,国产精品| 久久久精品视频免费观看| 国产综合色精品在线观看| 91精品久久久久| 超碰地址97| 国产又大又粗又色生活片亚洲国产精品成人久久久综合免费 | 色哟哟国产精品免费网址| 熟女乱伦二区| 色色婷| 国产Aα| 国产午夜精品理论片一二三区区 | 韩国黄片aaaa| 在线无码操| 人干人人人操人人摸| ..日韩av毛片精品久久久| 一区操逼| 亚洲aV性爱| 99久视频| 亚洲中文字幕噜噜噜久久久| 色九月婷婷| 天天欧美欧美亚洲网| 天天日天天色| 亚洲人在线| 一区二区三区四区五区高清无码永久视频| 亚洲另类色图片| 日韩欧美亚洲国产日韩| 久久久久精| 欧美亚洲国产自久久| 色偷偷色偷偷欧美日韩| 欧美亚洲激情一二三| 天天香香欲综合| 欧美一区二区日韩传媒搭讪精品| 欧洲乱码视频| 78精品在线| 97在线视频网站| 天天日夜干| 一级乱伦网站| 911av网站免费观看| 在线观看AV片| 男人的天堂2010| 九九九综合精品| 天美一二三在线观看Av| 欧美洲精品一级| 久夜操| 亚洲精品少妇| 久草网站免费在线观看| 五月丁香久久| 鸥美极品| 插入逼91| 国产精品久久久久无码AV会牛| 一区二区三区精品黑丝白丝酒店对鸡| 99re8免费高清在线| 97超碰久| 人妻性爱一区二区| 亚洲AV成人无码一区二区三区在线观看 | 日韩无码操逼片| 操逼网站地址| 中文字幕神马久久| 精品人妻一区二区三区日产| 中国大陆国产高清AⅤ毛片| 久久婷婷色| 欧美拳交在线播放| 欧美色日| av亚欧| aⅴ日韩成人电影av在线免费看av大全| 五月天婷婷激情| 伊人久久大香线蕉亚洲五月天,青草青草欧美日本一区二区,欧美日产欧美日产国产 | 人人操人人插人人摸人人干| 亚洲天堂色图| 91高跟美女在线播放| 亚洲第一页综合在线| av网站免费看| 绯色AV粉色AV蜜臀AV| 东京热91| 色五月综合网| 国内成人圈中文字幕无码视频| 欧美亚洲图片| 欧美成人性爱视频大全| 亚洲色欲一区二区三区| 男人的天堂免费| 久久艹逼视频| 欧美久久婷婷| 天天视频网站黄| 91视频国品一二三区| 青青草日韩免费观看高清在线| 操一操摸一摸| 女人爽到高潮久久久| 欧美色图99| 欧美精品一区二区少妇免费A片| 国产欧美精品日韩区二区麻豆天美| 婷婷九月国产| 久久香蕉综合一本到3atv| 女生自91网站| 日va操| 性生活无遮挡纯毛片在线看| 嫩草一区二区在线观看| 国产情色在线| 国产AV超爽| 人妻少妇无码| 久久激情综合| 91亚洲网站| 你懂得91| 人妻娇喘 激情视频| 精品成人av一区二区三区在线| 婷婷激情五月综合| 怡红院一区二区熟女人妻| 夜夜福利| 国产色精品午夜大片| 精品九九淫乱男| 亚洲第2页| 91模特在线观看| 大香蕉五月天婷婷| 2019天天干| 白嫩嫩一区| 国产精品内射婷婷一级二| 欧美另类色图片| 91老司机在线| 亚洲aw毛茸茸在线| www.黄色在线| 91久| 粉嫩少妇自慰在线| 免费成人在线熟妇网| 日韩欧洲操屄视频| 在线观看中文字幕| 无码9区| 国产无码久久高清| 日韩精品三级片长长久久| 少妇人妻太紧太深av| 91狠狠狠| 色色99| 亚洲第一无码播放立川理惠| 亚洲av资源| 九九人人操| 中文字幕丰满人妻日本| 福利在线视频一区二区| 精品久久在线区一区| 日韩国产乱子伦App| 国产精品农村妇女精品| 亚洲精品天天影视综合网 | 亚洲情色五月天 | 日本操逼二区| 久久啊哟| 亚洲色综合| 日本国产欧美一区三区二区| 亚洲天堂久| 麻豆av一区二区三区| AV免费在线播放一区| 亚洲Av诱惑| 久操在97| 怡红院视频在线| 亚洲图片欧洲图片aⅴ| 精品九九九九九九| 呦女网站| 精品美女久久一二三| 中文字幕亚韩| 五十路六十路七十路熟婆| 欧美丝袜91| 在线亚洲丝袜视频网站| 激情欧美日韩女同久久| 欧美大香蕉97| www.操| 久久丁香五月天| 尤物黄色在线观看网站| 亚洲一区二区在线观看91| 亚洲综合射| 日本丝袜美腿人妻九九| 五月天开心网| 丁香五月天堂| 五月丁香婷婷色| 亚欧性爱ab| 亚洲一区二区久久久久| 欧美精品69性爱| 午夜在线播放| 亚洲性天堂| 国产2.3.4区| AV男人天堂网| 玖玖超碰熟| 青青草字幕AV| 小日子操bb在线看| 另类TS人妖一区二区三区| 一级二级在线观看| 精品无码久久久久久久杏吧| 九九九九热| 九久精品| 亚洲欧美综合网| 狠操91,com| 日韩久草| 97色操| 五月天人妻综合| 9 9无尺码天堂网| 91美女在线看| 手机av亚洲丝袜美腿日韩第一页二页| 蜜臀久久99精品| 天天摸天天碰天天添青青| 一色网男人的天堂| 99色悠悠| 伊人丝袜美腿高跟在线观看高清 | 啊啊啊网站| 久久超碰网| 亚洲天堂久久久久久粉红视频| 天天做天天爱| 亚洲日韩精品久久久久一区壹牛 | 综合久久99| 熟女精品日韩一区二区三区| 日本布卡一区二三区| 夜夜嗨一区| 国产外初女出血视频| 丝袜美腿91| 外国免费性情大片| 人人搡人人肉久久精品| 日本久久999| 后入综合久久| 人人干人人操人人爱| 欧美性爱第一页久久| 中文字幕一区二区日韩网| 91精品女厕偷拍视频| 国产伦乱91| 精品视频久久久久九九九九9999| 丝袜天堂| 春色综合网| 久久精品国产欧美日韩亚洲欧美日韩中文久久国产一区 | 欧美日韩性爱无码| 国产丝袜视频| 欧美色图97| 久久高潮妇女视频| 影音先锋每日最新资源在线观看 | 超碰激情808| 91国产美女丝袜足交精品视频| 精品无码产区一区二| 欧美成人精品一区| 性色av蜜臀av色欲aV| 色色色色综合网| 操婷婷逼| 女人的天堂大香蕉网| 中文无线日韩一区| 精品欧美А∨无码黑人大荫蒂| 粉嫩av久久一区二区三区| 色色色99| 色五月天AV| 久久大香蕉97| 亚一综合久久久久久久久久| 午夜精品99久久久久传媒| 99蜜桃臀久久久欧美精品网站| 天天操天天干美女网址导航| 天天摸夜夜添无码小视频| 正在播放:深夜激情大战,自带黑丝袜全力输出骚穴 | 精品乱码在线观看| 国产成人午夜视频网址| 91视频成人福利网站在线一区 | 俺也射| 久久在线观看免费视频| 成人国产精品三级A片| 女同女同恋久久级三级| 五月婷在线| 日本熟妇色熟妇在线视频播放| 97在线观看| 色欲日韩欧美在线一区| 婷婷激情一区二区三区俺也去| 欧美色吧综合| 97人妻免费中文字幕| 亚洲情色第一页| 男人的天堂视频精品乱在线| 国产中文字幕曰本毛片| 麻豆精品A片免费观看| 亚州91| 亚洲成A∨人影院在线欢看| 欧美第38页| 国产精品夜夜| 亚洲AV小说| 懂色Av一区二区三区| 成人免费福利在线观看| 亚洲天堂资源| 五月激情综合网| 成人AV在线网站| aⅴ日韩成人电影av在线免费看av大全 | 国产一级不卡在线观看| 日韩精品99久久久久久中文字幕 | 综合色久欲| 国产午夜激片Av毛片不卡| 成人五月天色网| 97情超碰色| 欧美激情视频一区二区| 亚洲人天堂| 蜜臀av在线播放一区二区三区| 国产精品对白自产拍| 欧美视频一区二区在线| 少妇精品久久久八区九区| 自拍偷拍 日韩无码| 亚洲日韩少妇一道本视频| 首页中文字幕中文字幕免费| 五十路成人在线视频二区三区| 天天做日日做天天欢。| 91痴汉| 亚洲天堂AV在线播放| 污电影在线观看| 成年女人18级毛片毛片免费观看| 国产视频第二页| 亚洲性综合9| 秋霞 色色| 91黑丝美女| aⅴ日韩成人电影av在线免费看av大全 | 亚洲av综合色区无码一| 丁香7月婷婷| 久久乐| 男人天堂黄片| 麻豆av一区二区| 美女淫穴| 黄色在线网站| 东北女人高潮视频| 10000部十八禁看电影| 亚欧Av| 久夜视频| 国产熟女一区二区丰满| 国产懂色精品国产av| 熟女人妻一区二区三区| 无码久| 天天爽爽爽爽| 99在线无码精品秘 入口黑人| 美女黄页网站| 一区=区三区视频| 国产 三级自拍| 色综合加勒比| 日韩成人人妻网站| 久久神马影院| 色色色色色色色色色色色色色色综合| 91免费看一区二区三区| 久操视频在线| 国产少妇内射| 婷婷五月天无码 | 青青国产在线拍揄自揄拍| 国产激情在线观看| 小日子操bb在线看| 成人怡红院| 动漫区日韩区欧美区| 五月丁香拍拍激情综合三级| 88xx成人精品视频| 精品高潮| 91亚洲人| 无套后入双马尾| 精人妻无码一区二区三区伊人直播| AV天天在线观看| 亚洲高清无码AAA久久久精品| 性爱视频免费网址| 日本道不卡| 日躁天天爽爽| www.男人的天堂| 在线小说视频一区| 欧美青青视频| 蜜桃久久精品一区二区三区| 国产农村妇女精品一二区| 五月丁香激情综合网| av日韩在线观看电影| 最新国内自拍av免费| 久久男人的天堂| 欧美偷拍| 亚洲不雅视频1区二区| 韩国毛片一区二区三区| 台湾佬中文娱乐网久久久久久久久久com | 人人摸人人干| 精品视频97| 亚洲丝袜B诱惑| 麻豆精品久久久久久久| 天天操夜夜操| 91蜜臀熟女| 麻豆天美国美国产AV| 首页亚洲国产高跟丝袜诱惑视频 | 中文字幕 码 自拍 视频 区| 色九区| 天天日夜夜爽| 亚洲av夫妻操穴网| 欧美亚州综合图片| 本道在线| 大香蕉99re| 东京热毛片调教| 少妇三p| 美女黄站| 台湾大香蕉99热| laoshunv91| 东方亚洲在线操逼天堂| 97欧美色| 91春色| 以及麻豆国产入口在线观看免费| 少妇啪啪自拍| 亚洲精品三| 亚洲天堂人妻一区二区| 自拍欧美| 久久久女人| 欧美激情激情xxxx欧美专区| 思思热在线视频免费| 性爱视频啪啪啪啪| 再深点灬舒服灬太大了好硬好爽| 欧美图片偷拍| 成人在线视频一区| 中文字幕免费在线观看| 日韩欧无码一区二区三区免费不卡 | 欧美一品道| 偷拍盗拍亚洲色图图片| 桃花色综合影院| 久久久久人妻二区精品叶可怜| 日韩欧美中文| 亚洲精品日韩国产欧美| 老鸭窝亚洲毛片| 综合av影片| AV女资源| 欧美日韩大黄片| 韩国黄色片精品久久久| 秋霞男人网| 亚洲精品蜜桃久久久| 久久久新亚洲AV| 操逼逼福利视频| 操九九九九九九| 亚洲亚洲亚洲天堂天堂| 国产午夜在线观看| 天美麻花大全视频| 欧洲精品网| 啊啊啊爽爽| 亚欧高清在线| 亚洲大胆人体av| 亚洲天天更新| 精品9999| 伊人一区二区在线播放| 天美传媒国产原创中文字幕亚洲欧美另类 | 99久久9| 91性高朝久久久久久久久| 亚洲国产激情国产av| 樱花草社区www中国| 亚洲综合伊人无码久久| 成年女人黄网站| www.狠狠| 97在线日韩中文字幕| 一个色导综合| 国产精品制服丝袜中文字幕日韩一区二区三区 | 欧美日韩久久精品爱爱| 日本性爱不卡视频| 久久精品视频28| 天天做天天爱| 99热思思| 91高清欧美| 久久‘黄片视频| 国产女人9999| 乱伦AVxx| 国产视频97| 国产亚洲精品玖玖玖在线观看| 亚洲另类色图片| 欧美成人一级麻豆| 久久色人体| 不卡在线观看视频| 丁香六月婷婷| 极品色综合| 婷婷激情五月| 久夜视频| 午夜激情床戏激情| 午夜精品久久一区二区| 九九无码久久精品视频| 日本色色色网站免费看不卡| 黄页大片在线观看| 中国AAAAAA黄色片| 久久久99免费| 国模不卡一本二本三电影| 97超碰人人操人人操| 久悠悠av| 亚洲精品人妻在线| 蜜桃中文字日产乱幕4区| 久久岛国| 人妻精品综合中文字幕在线| 亚洲欧美国产中文视频| 色综合久久夜色精品国产天堂| 曰韩操B| 亚州色阁| 91美女丝袜诱惑视频| 中文字幕欧美日本乱码一线二线| 亚卅熟女乱色| 精品午夜福利| 精吧天堂| 98一区二区精品| 老熟女乱伦一区| 亚洲、日韩、综合、另类| 2018天天日天天日| 亚洲激情天堂网| 欧美中出1| 999综合网| 亚洲精品骚逼| 国产日比| Sekablack无码一区| 精品一区二区三区四区外站| 99综合视频| 欧美黑人极品高潮喷吹熟女黑人性暴力日韩在线欧美极品一区二区老师黑人潮喷一 | 伊人影院中文字幕| 十八禁成人网站在线观看| 这里只有精品97| 熟妇艹鸡八| 国产精选三级在线观看| 久久久久久久唑| 精品人妻视频一区二区三区蜜桃视频| 欧美强奸一区二区诱惑| 秋霞色色影院| 亚洲日本大香蕉1| 射 色综合| 精品v日韩欧美国产| 97天天摸天天爽| 欧美日韩人人精品| 天天干夜夜肏| 毛片17S| 中国国国产一级特黄毛片| 乱伦熟女论坛| 久久粉色| 综合网欧| 青青草九九九九九| 亚洲精品三| 91无遮挡| 天天天肏屄肏屄肏屄欧美欧美| 国产精品视频播放| 操人无码| 性爱乱伦网址| 可以在线观看的黄色网址| 精品欧美乱码久| 国产尤物在线三区| 久久伦理视频久久大香蕉视频| 屌逼麻豆| 啪啪一区| 国产福利第一视频| 日韩乱伦影音先锋| 少妇人妻太紧太深av| 青娱乐二区免费| 91老熟女| 日韩熟女精一区二区三区不卡| 啊啊啊啊好疼视频| 大香蕉92| 久久99干一本高清| 久久精品国产97欧美精品亚洲| 女上位精品在线| 夜夜操夜夜高潮夜夜爽国产精品区| 日夜干射色啊| 久久男人网| 91黑丝美女| 少妇第一页| 国产情色第一第二页在线观看| 精品乱码久久久久| 男人的天堂日韩| 青青操日韩| 欧美宗合色| 欧美色网| 欧美日韩不卡a片| 婷婷丁香五月天亚洲天堂网| 日本精品一区二区中文字幕| 国产精品在线免费| 国产h小视频在线观看免费| 亚洲中文字幕在现观看| 国产精品盗摄 偷窥盗摄| 人人看人人爰人人操| hd成人一区二区在线| 爱我干综合| 亚洲天堂性爱| 性交一区二区在线播放| 夜夜骑日日| 成人精品无码| av在线一区二区三区| 337p大胆噜噜噜噜噜91Av| 爱爱60秒免费视频| 亚洲色资源| 亚洲情色 自拍| 国产呦精品系列在线观看| 黄色片,com| 色五月网址| 青娱乐大香蕉| 欧美色综合网| 爽极品影院| 五月婷视频| 久久大线蕉一区| 99re黄| 强奸乱伦AV网站| 啊…啊…操我用力操我| 97色涩| 超碰在线一区二区三区| yellow网站免费观看日韩高清无码| 丁香久久| 亚洲欧美在线综合| 久久大黄片| 亚洲国产欧美中文永久| 97欧美精品综合| 国内一级精品| 最新中文字幕在线亚洲| 中文字幕一区 二 区 三 四 五 区日 日 骚 | 我想要啊 啊 啊| 91视频伊人| 天天做天天爽| 人人妻天天做天天爽| 久久精品国产精品一区| www.色五月| 国产和美国毛片| 国产第12页| 国产精品青青草| 精品人妻高清麻豆av| 乱伦一区二区三区‘| 四月丁香婷婷| 天天日夜干| 影音先锋国产精品| 91精品久久久久久77777| PMv在线观看| 91蜜臀在线久久久久| 玖玖爱视频网站| 日本一区二区不卡精品| 久偷拍欧美日韩三区| 亚洲成人黄色在线观看| 男人天堂婷婷五月天校园春色| 91插B网站| 黄色高清无码无码破解免费暗网| 日本欧美色| 国产Av超碰| 91成人国产综合久久精品蜜月| 天天综合网91| 中文字幕av色| 国产视频人人网| 18一区二区三区| 黄片www视频免费| 91女在线观看| 囯产精品久久久久久久久久梁医生| 九九在线视频| 91精品老女人| GVH-003 母子姦 青木玲-麻豆视频,麻豆视传媒短视频网站入口,麻豆视传媒官网直 | 国产中文大片资源中文字幕 | 日韩精品色呦呦| 麻豆一区二区三区精品| 中文字幕丝袜国产第一页不卡| 级品肉射| 五月天婷精品激情| 国产AB视频| 激情五月天丁香社区| 久久久女人| 玖玖视频在线资源一区二区三区| 亚洲色图欧美色图另类图片| 日韩情色视频| 91午夜无码| 日韩av电影网站| 强奸乱亚洲| 青青草好吊色| 69人妻精品丰满熟女区| 国产久久av| 奶水 人妻 哺乳 在线| 超碰人人乐97| 福利社区午夜一区二区| 色婷婷一区二区三区久久午夜成人不| 色婷婷久久| 日韩在线国产字幕| 日影院久久婷婷夜夜网| 欧美黄片视频在线观看免费 | 日韩一级成人毛片免费观看| 久99在线免费观看视频| 精品一区二区3区| 波多野结衣一级视频| 国产91丝袜在线播放蜜月| 一起草AV| 成人七区| 亚洲综合在线第一页| 欧美日韩人人早| 国产乱伦一二三区| 99婷婷一区二区| 亚洲文学偷乱拍啪啪啪啪 | 揉揉日日日日| 国产亚洲日本| 天综合网| 十八禁的黄污污免费网站| 97操b| 91久久国产综合精品| 任你草| 97在线视频观看网站| 亚洲无码一区成人免费午夜| 国产白丝在线| 日韩乱码Av| 99热这里只有精品地址| 日韩av在线精品观看| 男人天堂导航| 国产一区二区三区,在线观看观看| 五月天啪啪| 超碰成人最新最好看| 美女久久久久久久久久久| 夜夜操一区二区| 99国产精品人妻人伦| 多乙久久久久久| 久久伊人亚洲AV无码网站| 91中出视频| 久久久精品一区二区| 爽爽爽免费视频| 日本熟妇一区二区三区| 欧美黑人精品一区二区| 国产高清精品一区二区三区毛片| 亚洲国产成人精品女人久久久| 亚洲中文字幕一区| www.91欧美| av午夜玫瑰| 日本韩国一本产品小视频日本韩国一本产品久久久产品小视频日本韩国一本产品久 | 超碰97久| 久久久九| 久草毛片| 亚洲综人网| 亚洲男人天堂视频| 超碰视97中文| 日韩av情韩国爱禁区av一区二区| 97在线观看免费视频l| 台湾肥佬网一区二区三区| 亚洲五月丁香花狠狠干一区二区三区| 在线v中文字幕一区二区三区| 麻花传媒免费网站在线观看| 国产操逼视频在线观看| 人人操人人插 - 百度 - 百度| 夜夜骑夜夜操| 大象AV在线| 青娱乐淫乱1314| 丁香婷婷五月| 国产亚洲深夜激情| 天天激情综合站| 五十路六十路七十路熟婆| 老熟女乱伦一区| 成人免费看吃奶视频网站| 国产兽交视频在线播放| 呦呦影院| 少妇xx精品| 婷婷五月天激情网| 欧美性爱另类综合| 国产精品色色| 小草精彩毛片| 久久久久久91香蕉国产| 精品人妻一区春色| 果冻传媒一区二区三区| 97伊人超碰| 成人怡红院| 中文字幕在线免费观看2| 被男人吃奶很爽的毛片| 亚洲最新av无码成人精品区| 欧美黄片欧美黄片xxx| 亚洲免费人妻在| 97五月天| 午夜成人福利影视| 超碰免费欧美7| 999热日韩精品| 东北毛片| 国产精品一区午夜福利| 自偷自拍的亚洲视频| 这里有精品| 东北老女人的激情视频| 精品人妻伦一区二区三区久久| 精品人妻一区二区三区不卡断| 综合网天天| 377p欧洲日本亚洲大胆| 免费黄色片子| 密臀在线免费观看| 久操| 高清无码久操视频| 黄片在线免费在线观看| 天美av在线观看| 桑老女人九区| 亚洲成人色情五月天丁香花| 成人免费性爱视视| 日韩三级伦理中文字幕| 国产日韩欧美亚洲精品95| 日韩精品一区的| 久久夜夜| 亚洲乱码尤物193YW| 精品久久久无码| 嫩草黄页| 激情黄色片在线观看| 8050无码八戒| 色老汉色| 日韩久射综合| 殴美在线AⅤ| 久久精品免费| 秘书高跟黑色丝袜国产91在线| 秋霞网无码| 亚洲欧洲国产综合av| 国产白嫩精品久久| 亚洲 欧美 色图| 日本性爱网址| 秋霞男人网| 深喉吞精| 久草福利在线资源站| 91色黑人少妇| 欧美色图亚洲色| 精品国产久热在线观看| 日欧毛片久久| 欧美性爱精品七区| 91麻豆天美国产欧美日| 天操天操夜操夜月操月年年操操| 日韩免费福利在线观看| 思思99热| 亚洲激情在线| 熟女人妻一区二区三区| 中文字幕久久亚州无码| 美日韩男女操屄视频| 开心激情婷婷| 美女91网| 香蕉久久国产AV一区二区| 射丝袜大香蕉| 国产熟女完整版中字| 激情欧美日韩女同久久| 一道α片欧美| 国产综合久久久鬼色| 色欲久久久久综合网| 亚洲国产综合久久天堂| 亚洲色图欧美色图另类图片| 先锋精品av色鲁| 妇女一区二区三区| 开心激情站| 青青草好吊色| 天天日天天舔天天喷天天射| 青草地一本线一区二区三区| 婷婷色网| 深夜视频| 天天透伊人| 欧州一区二区三区四区| 亚洲AV资源| 欧洲亚洲国产综合在线| 东北女人操比视频| 欧美劲爆视频一区二区| 大色网久久| 六十路日本| 国产熟女无套内射| 欧洲无码一区二区| 日本伦乱九九九综合| 熟女自慰久久久| 人人操人人摸人人看人人干| 欲女人妻性色av| 丁香六月啪| 久久久久久9| 精品国产99| 亚洲二区精品在线观看| 久久大香蕉97| 九一屌逼| 日本精品无码三级网站| 久9久9久9久9久9久9| 黑丝少妇| 欧美精品久久久久久久丰满| 96国产污污污丝袜| 3p国产欧美99热| 78久久| 99re95| 亚州AV无码国产精品| 91欧美www| 人人污日韩一区二区| 天天做日日做天天欢。| 欧美激情精品| 97一区二区三区视频| av九九| 第四色奇米影视777| 亚洲双插| 1二区9| 五月激情在线| 亚洲一曲日韩精品| 欧美美女视频| 亚洲综合情色| 少妇无码太爽| 日本性爱网址| 99精品人妻| 中文字幕88av在线| 国内亚洲精彩视频在线| 人乳av| 91爱综合| 天天天天天天天天天天干美女| 四虎免费在线播放| 91中文精品日韩欧美在线 | 91天堂丝袜美腿| 亚洲狼狼干综合1| 国产一区二区在线电影| 91色交| 日日躁狠狠躁天天躁精品| 97天天摸天天碰| 欧美性爱一级操| 亚洲天堂五月天国产| 亚洲做性| 欧美亚洲se91| 黄色网址久久精品欧美喷水| 特级毛片特黄久久免费看 | 91大神电影天堂| 成人 日本A片无码8888| 亚洲无码国产探花在线观看| 91精品丝袜久久久久久| 淫乱图区 | 午夜无遮挡男女啪啪视频| 黄色交缠性感爆操91国产精品免费一区二区三区 | 久久色人体 | 9999亚洲精品| 国产60区。| 99超碰色| 国模精品娜娜一二三区| 丰满人妻无码一区二区三区| 26uuu成人影片| 久久久久女教师免费一区 | 蜜乳AV.COM| 亚洲无码视频免费在线观看网址!| 国产又粗又长的视频| 欧美韩国你懂得在线 | 欧美性天天影院| 男人久久精品| 嗯嗯啊啊操死我| 欧美久久草熟女| 九九性视频| 丁香五月天啪啪| 久久婷婷五月天| 熟女六十路| 激情五月天丁香社区| 午夜影美女日鸡鸡天天视频国产 | 四虎国产成人精品免费一女五男| 久久久久久大| 一品道视频一区二区三区| 天天日天天色| 黄色av一区二区在线| 精品超碰国产| 色色五月天婷婷| 婷婷六月色开| 久久极品一区二区| 青青爽| 情侣开房子拍 日韩无码 女的很漂亮| 久久黄黄| 人妻密肉在线观看| yirendaxiangjiashipin| 国产自产91区13区| 人妻天天爽夜夜爽精品2| 天天看人人操屄犊摸阴| 青青草字幕AV| 97超碰超欧美。| 高潮9999外国| 91亚洲高清| 操国产高清| 日韩三A大片在线观看| 嗯啊抽插大香蕉网页| 黄片com.| 婷色五月天| 亚洲情色电影网| 一区| 中文字幕欧洲有码| 91天美免费| 26uuu最新| 男人高清无码一区二区| 97摸视频| 亚洲熟妇图片| 色哟哟av网址| 91熟女视频网| 男女无套 免费网站| 久久亚洲欧美中文字幕国语| 精品久久久久av影院| 丁香五月婷婷五月| 国产v片在线免费观看| 再深点灬舒服灬太大了添视频| 图片区小说区| 五月天激情网图片| 久久、1234| 三级色影综合网| 人妻无一区二区三区| 三级片网站在线播放| 亚洲欧美九九九| 国产热av| 激情黄色片在线观看| 中文字幕亚洲在线一区| 东京热男人的天堂网| 蘋果手機免費看成人Av| 久久久久99999| 天天色天天干天天爱| 五月婷婷丁香| 性交一区二区在线播放| 欧美情色亚洲| 日韩Va亚洲va欧美Ⅴa久久| 久久久精品国产亚洲伊人| 歐美性天天| 91天天看| 亚洲超碰在线| 国产丝袜美腿美女麻豆| 不卡视频一区蜜桃视频 | 97国产天堂岛| 夜夜躁狠狠躁日日躁av| 五月婷婷丁香六月丁香| 少妇超碰在线| 亚洲91射| 国产在线视频二区| 啊啊啊用力在线观看| 日本高清视频在线观看黄已三辽| 超碰97久| 国产av美女被艹的乱叫| 99热精品国产| 午夜传煤十二区精品| 深夜国产一区二区三区在线看| 一区二区三区日韩欧美| 亚洲,欧美,综合网| 人人人人插| 99www.bibizy香蕉资源国产一区二区三区高清 | 黄片无码在线制服| 1204av韩国| 亚洲 小说 欧美 激情 另类| 欧亚在线视频| 综合天天。| 亚洲成人福利电影免费| 啊啊啊com| 久久91| 国产女人高潮视频| 超碰9 7女人| 91精品人妻电影| 好爽免费视频,| 亚洲性爱成人| julia高潮后不停追击中出| 国产精品久久久久久久久久久久久久久久 | 日韩在线电影| 超碰狠狠操| 欧美第二页午夜| 国产女人极品高潮毛片| 天天舔天天日天天射| 亚洲天堂精品日韩电影| 91色碰| 免费在线看黄片av| 亚洲精品99| 天天亚洲| 无码91| 蜜臀99久| 亚洲中文字幕97久久精品少妇| 91久久婷婷| 亚码激情| 超碰97护士| 久久伊人在线五区| 亚洲成人精品在线一区| 旡码电影特区| 亚洲av综合伊人久久| 夜草欧美| 精品人体无圣光凹凸| 天天操天天看| 9久久精品| 日韩人妻丝袜中文字幕| 七久久久| 日本中文字幕不卡视频| 精品网站99999| 国产欧美成人第一页在线观看| 人妻素股| 丁香五月成人| 亚洲欧美情色| 欧美熟女妇同| 大伊香蕉在线视频免费| 插B在线观看| 欧美久久九九| 久久精品中文字幕观看| 日韩成人人妻网站| 九九热九九| 中文字幕丰满人妻日本| 美女的肌被草喷水视频| 日韩综合成人免费视频| 九九九九九九九| 青青网三级视频| 亚洲精品国语在线播放| 亚洲伊人久久精品影院| 色色综合网站| 日韩精品在线放| 人妻黑丝袜电影| 天天摸,夜夜摸| 精品国产无码中文| 久9爱经典视频| 青青草原人妻| 色欲蜜臀AV| 啊啊啊好舒服视频| 性色高清在线| 亚洲精品日日夜夜52| 97干色| 97在线无精品| 国内91熟女人妻丝袜天天精品视频在线 | 亚洲精品人妻吞精av| 久久精品区| 中文字幕、久久精品国产2020、久久综合久久自在自线精品自、亚洲 | 欧美78P| 久久久久久中文版| 亚州精人品大香蕉| 人人人人插| 欧美人妻熟女在线| 天天影视激情欧美| 色婷婷香蕉| 人妻丰满熟妇一区二区三| 久久熟女嫩草成人片免费| 日日干夜夜操视频h| 综合久久婷婷| 国产成人99久久亚洲综合| 精品欧美乱码久| 国产少妇内射| 操逼999| 欧美综合站| 国产精品老师| 51一区二区三区| 肏逼福利网站| 欧美性五月| 亚洲 另类 丝袜 自拍 动漫| 骚乳在线| 超碰在线成人| 亚洲古典另类欧美在线| 久久首页| 人妻二区| 综合久久2017| 九九九999久久久网站| 中文字幕精品专区搜索结果91| 99热免费精品| 亚洲综合网电影91| 97干在线视频| 丁香五月激情综合国产| 影音先锋少妇| ,成人免费啪啪视频| 啪啪视频免费在线观看| 日韩97P| 上床啊啊啊| 日韩人妻无码不卡网站| 中文字幕欧洲有码| 亚洲激情深爱文学小说网站| 884t在线| 日本精品性生活久久久| 99xav| 美女AV一区二区| 爽爽爽免费视频| 狠狠干精品一二三四五六2022| 超碰激情808| 老鸭窝亚洲毛片| 99re3这里只有精品| 97亚洲一区| 亚洲码和欧洲精品激情系列| 成人欧美一区二区三区黑人一| 91一起操| 五月激情综合网| 国产成人资源| 综合网欧美在线| 丰满人妻一区二区三区在线| 97蜜桃综合| 久久久久亚洲精品| 97露脸精品丝袜| 97国产色图| 激情小说五月天|