精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

基于微前端qiankun的多頁簽緩存方案實(shí)踐

開發(fā)
本文梳理了基于阿里開源微前端框架qiankun,實(shí)現(xiàn)多頁簽及子應(yīng)用緩存的方案,同時(shí)還類比了多個(gè)不同方案之間的區(qū)別及優(yōu)劣勢,為使用微前端進(jìn)行多頁簽開發(fā)的同學(xué),提供一些參考。

作者|vivo 互聯(lián)網(wǎng)前端團(tuán)隊(duì)- Tang Xiao

本文梳理了基于阿里開源微前端框架qiankun,實(shí)現(xiàn)多頁簽及子應(yīng)用緩存的方案,同時(shí)還類比了多個(gè)不同方案之間的區(qū)別及優(yōu)劣勢,為使用微前端進(jìn)行多頁簽開發(fā)的同學(xué),提供一些參考。

一、多頁簽是什么?

我們常見的瀏覽器多頁簽、編輯器多頁簽,從產(chǎn)品角度來說,就是為了能夠?qū)崿F(xiàn)用戶訪問可記錄,快速定位工作區(qū)等作用;那對于單頁應(yīng)用,可以通過實(shí)現(xiàn)多頁簽,對用戶的訪問記錄進(jìn)行緩存,從而提供更好的用戶體驗(yàn)。

圖片

前端可以通過多種方式實(shí)現(xiàn)多頁簽,常見的方案有兩種:

  • 通過CSS樣式display:none來控制頁面的顯示隱藏模塊的內(nèi)容;
  • 將模塊序列化緩存,通過緩存的內(nèi)容進(jìn)行渲染(與vue的keep-alive原理類似,在單頁面應(yīng)用中應(yīng)用廣泛)。

相對于第一種方式,第二種方式將DOM格式存儲(chǔ)在序列化的JS對象當(dāng)中,只渲染需要展示的DOM元素,減少了DOM節(jié)點(diǎn)數(shù),提升了渲染的性能,是當(dāng)前主流的實(shí)現(xiàn)多頁簽的方式。

那么相對于傳統(tǒng)的單頁面應(yīng)用,通過微前端qiankun進(jìn)行改造后的前端應(yīng)用,在多頁簽上實(shí)現(xiàn)會(huì)有什么不同呢?

1.1 單頁面應(yīng)用實(shí)現(xiàn)多頁簽

改造前的單頁面應(yīng)用技術(shù)棧是Vue全家桶(vue2.6.10 + element2.15.1 + webpack4.0.0+vue-cli4.2.0)。

vue框架提供了keep-alive來支持緩存相關(guān)的需求,使用keep-alive即可實(shí)現(xiàn)多頁簽的基本功能,但是為了支持更多的功能,我們在其基礎(chǔ)上重新封裝了vue-keep-alive組件。

相對較于keep-alive通過include、exclude對緩存進(jìn)行控制,vue-keep-alive使用更原生的發(fā)布訂閱方式來刪除緩存,可以實(shí)現(xiàn)更完整的多頁簽功能,例如同個(gè)路由可以根據(jù)參數(shù)的不同派生出多個(gè)路由實(shí)例(如打開多個(gè)詳情頁頁簽)以及動(dòng)態(tài)刪除緩存實(shí)例等功能。

下面是vue-keep-alive自定義的拓展實(shí)現(xiàn):

created() {
// 動(dòng)態(tài)刪除緩存實(shí)例監(jiān)聽
this.cache = Object.create(null);
breadCompBus.$on('removeTabByKey', this.removeCacheByKey);
breadCompBus.$on('removeTabByKeys', (data) => {
data.forEach((item) => {
this.removeCacheByKey(item);
});
});
}

vue-keep-alive組件即可傳入自定義方法,用于自定義vnode.key,支持同一匹配路由中派生多個(gè)實(shí)例。

// 傳入`vue-keep-alive`的自定義方法
function updateComponentsKey(key, name, vnode) {
const match = this.$route.matched[1];


if (match && match.meta.multiNodeKey) {
vnode.key = match.meta.multiNodeKey(key, this.$route);
return vnode.key;
}


return key;
}

1.2 使用qiankun進(jìn)行微前端改造后,多頁簽緩存有什么不同

qiankun是由螞蟻金服推出的基于Single-Spa實(shí)現(xiàn)的前端微服務(wù)框架,本質(zhì)上還是路由分發(fā)式的服務(wù)框架,不同于原本 Single-Spa采用JS Entry用的方案,qiankun采用HTML Entry 方式進(jìn)行了替代優(yōu)化。

使用qiankun進(jìn)行微前端改造后,頁面被拆分為一個(gè)基座應(yīng)用和多個(gè)子應(yīng)用,每個(gè)子應(yīng)用都運(yùn)行在獨(dú)立的沙箱環(huán)境中。

圖片

相對于單頁面應(yīng)用中通過keep-alive管控組件實(shí)例的方式,拆分后的各個(gè)子應(yīng)用的keep-alive并不能管控到其他子應(yīng)用的實(shí)例,我們需要緩存對所有的應(yīng)用生效,那么只能將緩存放到基座應(yīng)用中。

這個(gè)就存在幾個(gè)問題:

  1. 加載:主應(yīng)用需要在什么時(shí)候,用什么方式來加載子應(yīng)用實(shí)例?
  2. 渲染:通過緩存實(shí)例來渲染子應(yīng)用時(shí),是通過DOM顯隱方式渲染子應(yīng)用還是有其他方式?
  3. 通信:關(guān)閉頁簽時(shí),如何判斷是否完全卸載子應(yīng)用,主應(yīng)用應(yīng)該使用什么通信方式告訴子應(yīng)用?

二、方案選擇

通過在Github issues及掘金等平臺(tái)的一系列資料查找和對比后,關(guān)于如何在qiankun框架下實(shí)現(xiàn)多頁簽,在不修改qiankun源碼的前提下,主要有兩種實(shí)現(xiàn)的思路。

2.1 方案一:多個(gè)子應(yīng)用同時(shí)存在

實(shí)現(xiàn)思路:

  • 在dom上通過v-show控制顯示哪一個(gè)子應(yīng)用,及display:none;控制不同子應(yīng)用dom的顯示隱藏。
  • url變化時(shí),通過loadMicroApp手動(dòng)控制加載哪個(gè)子應(yīng)用,在頁簽關(guān)閉時(shí),手動(dòng)調(diào)用unmount方法卸載子應(yīng)用。

示例:

<template>
<div id="app">
<header>
<router-link to="/app-vue-hash/">app-vue-hash</router-link>
<router-link to="/app-vue-history/">app-vue-history</router-link>
<router-link to="/about">about</router-link>
</header>
<div id="appContainer1" v-show="$route.path.startsWith('/app-vue-hash/')"></div>
<div id="appContainer2" v-show="$route.path.startsWith('/app-vue-history/')"></div>
<router-view></router-view>
</div>
</template>


<script>
import { loadMicroApp } from 'qiankun';


const apps = [
{
name: 'app-vue-hash',
entry: 'http://localhost:1111',
container: '#appContainer1',
props: { data : { store, router } }
},
{
name: 'app-vue-history',
entry: 'http://localhost:2222',
container: '#appContainer2',
props: { data : store }
}
]


export default {
mounted() {
// 優(yōu)先加載當(dāng)前的子項(xiàng)目
const path = this.$route.path;
const currentAppIndex = apps.findIndex(item => path.includes(item.name));
if(currentAppIndex !== -1){
const currApp = apps.splice(currentAppIndex, 1)[0];
apps.unshift(currApp);
}
// loadMicroApp 返回值是 app 的生命周期函數(shù)數(shù)組
const loadApps = apps.map(item => loadMicroApp(item))
// 當(dāng) tab 頁關(guān)閉時(shí),調(diào)用 loadApps 中 app 的 unmount 函數(shù)即可
},
}
</script>

具體的DOM展示(通過display:none;控制不同子應(yīng)用DOM的顯隱):

圖片

方案優(yōu)勢:

  1. loadMicroApp是qiankun提供的API,可以方便快速接入;
  2. 該方式不卸載子應(yīng)用,頁簽切換速度比較快。

方案不足:

  1. 子應(yīng)用切換時(shí)不銷毀DOM,會(huì)導(dǎo)致DOM節(jié)點(diǎn)和事件監(jiān)聽過多,嚴(yán)重時(shí)會(huì)造成頁面卡頓;
  2. 子應(yīng)用切換時(shí)未卸載,路由事件監(jiān)聽也未卸載,需要對路由變化的監(jiān)聽做特殊的處理。

2.2  方案二:同一時(shí)間僅加載一個(gè)子應(yīng)用,同時(shí)保存其他應(yīng)用的狀態(tài)

實(shí)現(xiàn)思路:

  • 通過registerMicroApps注冊子應(yīng)用,qiankun會(huì)通過自動(dòng)加載匹配的子應(yīng)用;
  • 參考keep-alive實(shí)現(xiàn)方式,每個(gè)子應(yīng)用都緩存自己實(shí)例的vnode,下次進(jìn)入子應(yīng)用時(shí)可以直接使用緩存的vnode直接渲染為真實(shí)DOM。

方案優(yōu)勢:

  • 同一時(shí)間,只是展示一個(gè)子應(yīng)用的active頁面,可減少DOM節(jié)點(diǎn)數(shù);
  • 非active子應(yīng)用卸載時(shí)同時(shí)會(huì)卸載DOM及不需要的事件監(jiān)聽,可釋放一定內(nèi)存。

方案不足:

  • 沒有現(xiàn)有的API可以快速實(shí)現(xiàn),需要自己管理子應(yīng)用緩存,實(shí)現(xiàn)較為復(fù)雜;
  • DOM渲染多了一個(gè)從虛擬DOM轉(zhuǎn)化為真實(shí)DOM的一個(gè)過程,渲染時(shí)間會(huì)比第一種方案稍多。

vue組件實(shí)例化過程簡介

這里簡單的回顧下vue的幾個(gè)關(guān)鍵的渲染節(jié)點(diǎn):

圖片

vue關(guān)鍵渲染節(jié)點(diǎn)(來源:掘金社區(qū))

  • compile:對template進(jìn)行編譯,將AST轉(zhuǎn)化后生成render function;
  • render:生成VNODE虛擬DOM;
  • patch :將虛擬DOM轉(zhuǎn)換為真實(shí)DOM;

因此,方案二相對于方案一,就是多了最后patch的過程。

2.3 最終選擇

根據(jù)兩種方案優(yōu)勢與不足的評估,同時(shí)根據(jù)我們項(xiàng)目的具體情況,最終選擇了方案二進(jìn)行實(shí)現(xiàn),具體原因如下:

  • 過多的DOM及事件監(jiān)聽,會(huì)造成不必要的內(nèi)存浪費(fèi),同時(shí)我們的項(xiàng)目主要以編輯器展示和數(shù)據(jù)展示為主,單個(gè)頁簽內(nèi)內(nèi)容較多,會(huì)更傾向于關(guān)注內(nèi)存使用情況;
  • 方案二在子應(yīng)用二次渲染時(shí)多了一個(gè)patch過程,渲染速度不會(huì)慢多少,在可接受范圍內(nèi)。

三、具體實(shí)現(xiàn)

在上面一部分我們簡單的描述了方案二的一個(gè)實(shí)現(xiàn)思路,其核心思想就是是通過緩存子應(yīng)用實(shí)例的vnode,那么這一部分,就來看下它的一個(gè)具體的實(shí)現(xiàn)的過程。

3.1 從組件級別的緩存到應(yīng)用級別的緩存

在vue中,keep-alive組件通過緩存vnode的方式,實(shí)現(xiàn)了組件級別的緩存,對于通過vue框架實(shí)現(xiàn)的子應(yīng)用來說,它其實(shí)也是一個(gè)vue實(shí)例,那么我們同樣也可以做到通過緩存vnode的方式,實(shí)現(xiàn)應(yīng)用級別的緩存。

通過分析keep-alive源碼,我們了解到keep-alive是通過在render中進(jìn)行緩存命中,返回對應(yīng)組件的vnode,并在mounted和upda

// keep-alive核心代碼
render () {
const slot = this.$slots.default
const vnode: VNode = getFirstComponentChild(slot)
const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions
if (componentOptions) {
// 更多代碼...
// 緩存命中
if (cache[key]) {
vnode.componentInstance = cache[key].componentInstance
// make current key freshest
remove(keys, key)
keys.push(key)
} else {
// delay setting the cache until update
this.vnodeToCache = vnode
this.keyToCache = key
}
// 設(shè)置keep-alive,防止再次觸發(fā)created等生命周期
vnode.data.keepAlive = true
}
return vnode || (slot && slot[0])
}
// mounted和updated時(shí)緩存當(dāng)前組件的vnode
mounted() {
this.cacheVNode()
}
updated() {
this.cacheVNode()
}

相對于keep-alive需要在mounted和updated兩個(gè)生命周期中對vnode緩存進(jìn)行更新,在應(yīng)用級的緩存中,我們只需要在子應(yīng)用卸載時(shí),主動(dòng)對整個(gè)實(shí)例的vnode進(jìn)行緩存即可。

// 父應(yīng)用提供unmountCache方法
function unmountCache() {
// 此處永遠(yuǎn)只會(huì)保存首次加載生成的實(shí)例
const needCached = this.instance?.cachedInstance || this.instance;
const cachedInstance = {};
cachedInstance._vnode = needCached._vnode;
// keepalive設(shè)置為必須 防止進(jìn)入時(shí)再次created,同keep-alive實(shí)現(xiàn)
if (!cachedInstance._vnode.data.keepAlive) cachedInstance._vnode.data.keepAlive = true;
// 省略其他代碼...


// loadedApplicationMap用于是key-value形式,用于保存當(dāng)前應(yīng)用的實(shí)例
loadedApplicationMap[this.cacheKey] = cachedInstance;
// 省略其他代碼...


// 卸載實(shí)例
this.instance.$destroy();
// 設(shè)置為null后可進(jìn)行垃圾回收
this.instance = null;
}


// 子應(yīng)用在qiankun框架提供的卸載方法中,調(diào)用unmountCache
export async function unmount() {
console.log('[vue] system app unmount');
mainService.unmountCache();
}

3.2 移花接木——將vnode重新掛載到一個(gè)新實(shí)例上

將vnode緩存到內(nèi)存中后,再將原有的instance卸載,重新進(jìn)入子應(yīng)用時(shí),就可以使用緩存的vnode進(jìn)行render渲染。

// 創(chuàng)建子應(yīng)用實(shí)例,有緩存的vnode則使用緩存的vnode
function newVueInstance(cachedNode) {
const config = {
router: this.router,
store: this.store,
render: cachedNode ? () => cachedNode : instance.render, // 優(yōu)先使用緩存vnode
});
return new Vue(config);
}


// 實(shí)例化子應(yīng)用實(shí)例,根據(jù)是否有緩存vnode確定是否傳入cachedNode
this.instance = newVueInstance(cachedNode);
this.instance.$mount('#app');

那么,這里不禁就會(huì)有些疑問:

  1. 如果我們每次進(jìn)入子應(yīng)用時(shí),都重新創(chuàng)建一個(gè)實(shí)例,那么為什么還要卸載,直接不卸載就可以了嗎?
  2. 將緩存vnode使用到一個(gè)新的實(shí)例上,不會(huì)有什么問題嗎?

首先我們回答一下第一個(gè)問題,為什么在切換子應(yīng)用時(shí),要卸載掉原來的子應(yīng)用實(shí)例,有兩個(gè)考慮方面:

  • 其一,是對內(nèi)存的考量,我們需要的其實(shí)僅僅是vnode,而不是整個(gè)實(shí)例,緩存整個(gè)實(shí)例是方案一的實(shí)現(xiàn)方案,所以,我們僅需要緩存我們需要的對象即可;
  • 其二,卸載子應(yīng)用實(shí)例可以移除不必要的事件監(jiān)聽,比如vue-router對popstate事件就進(jìn)行了監(jiān)聽,我們在其他子應(yīng)用操作時(shí),并不希望原來的子應(yīng)用也對這些事件進(jìn)行響應(yīng),那么在子應(yīng)用卸載時(shí),就可以移除掉這些監(jiān)聽。

對于第二個(gè)問題,情況會(huì)更加復(fù)雜一點(diǎn),下面一個(gè)部分,就主要來看下主要遇到了哪些問題,又該如何去解決。

3.3 解決應(yīng)用級緩存方案的問題

3.3.1 vue-router相關(guān)問題
  • 在實(shí)例卸載后對路由變化監(jiān)聽失效;
  • 新的vue-router對原有的router params等參數(shù)記錄失效。

首先我們需要明確這兩個(gè)問題的原因:

  • 第一個(gè)是因?yàn)樵谧討?yīng)用卸載時(shí)移除了對popstate事件的監(jiān)聽,那么我們需要做的就是重新注冊對popstate事件的監(jiān)聽,這里可以通過重新實(shí)例化一個(gè)vue-router解決;
  • 第二問題是因?yàn)橥ㄟ^重新實(shí)例化vue-router解決第一個(gè)問題之后,實(shí)際上是一個(gè)新的vue-router,我們需要做的就是不僅要緩存vnode,還需要緩存router相關(guān)的信息。

大致的解決實(shí)現(xiàn)如下:

// 實(shí)例化子應(yīng)用vue-router
function initRouter() {
const { router: originRouter } = this.baseConfig;
const config = Object.assign(originRouter, {
base: `app-kafka/`,
});
Vue.use(VueRouter);
this.router = new VueRouter(config);
}


// 創(chuàng)建子應(yīng)用實(shí)例,有緩存的vnode則使用緩存的vnode
function newVueInstance(cachedNode) {
const config = {
router: this.router, // 在vue init過程中,會(huì)重新調(diào)用vue-router的init方法,重新啟動(dòng)對popstate事件監(jiān)聽
store: this.store,
render: cachedNode ? () => cachedNode : instance.render, // 優(yōu)先使用緩存vnode
});
return new Vue(config);
}


function render() {
if(isCache) {
// 場景一、重新進(jìn)入應(yīng)用(有緩存)
const cachedInstance = loadedApplicationMap[this.cacheKey];


// router使用緩存命中
this.router = cachedInstance.$router;
// 讓當(dāng)前路由在最初的Vue實(shí)例上可用
this.router.apps = cachedInstance.catchRoute.apps;
// 使用緩存vnode重新實(shí)例化子應(yīng)用
const cachedNode = cachedInstance._vnode;
this.instance = this.newVueInstance(cachedNode);
} else {
// 場景二、首次加載子應(yīng)用/重新進(jìn)入應(yīng)用(無緩存)
this.initRouter();
// 正常實(shí)例化
this.instance = this.newVueInstance();
}
}


function unmountCache() {
// 省略其他代碼...
cachedInstance.$router = this.instance.$router;
cachedInstance.$router.app = null;
// 省略其他代碼...
}

3.3.2父子組件通信

多頁簽的方式增加了父子組件通信的頻率,qiankun有提供setGlobalState通信方式,但是在單應(yīng)用模式下,同一時(shí)間僅支持和一個(gè)子應(yīng)用進(jìn)行通行,對于unmount 的子應(yīng)用來說,無法接收到父應(yīng)用的通信,因此,對于不同的場景,我們需要更加靈活的通信方式。

子應(yīng)用——父應(yīng)用:使用qiankun自帶通信方式;

從子到父的通信場景較為簡單,一般只有路由變化時(shí)進(jìn)行上報(bào),并且僅為激活狀態(tài)的子應(yīng)用才會(huì)上報(bào),可直接使用qiankun自帶通信方式;

父應(yīng)用——子應(yīng)用:使用自定義事件通信;

父應(yīng)用到子應(yīng)用,不僅需要和active狀態(tài)的子應(yīng)用通信,還需要和當(dāng)前處于緩存中子應(yīng)用通信;

因此,父應(yīng)用到子應(yīng)用,通過自定義事件的方式,能夠?qū)崿F(xiàn)父應(yīng)用和多個(gè)子應(yīng)用的通信。

// 自定義事件發(fā)布
const evt = new CustomEvent('microServiceEvent', {
detail: {
action: { name: action, data },
basePath, // 用于子應(yīng)用唯一標(biāo)識
},
});
document.dispatchEvent(evt);


// 自定義事件監(jiān)聽
document.addEventListener('microServiceEvent', this.listener);

3.3.3 緩存管理,防止內(nèi)存泄露

使用緩存最重要的事項(xiàng)就是對緩存的管理,在不需要的時(shí)候及時(shí)清理,這在JS中是非常重要但很容易被忽略的事項(xiàng)。

應(yīng)用級緩存

  • 子應(yīng)用vnode、router等屬性,子應(yīng)用切換時(shí)緩存;

頁面級緩存

  • 通過vue-keep-alive緩存組件的vnode;
  • 刪除頁簽時(shí),監(jiān)聽remove事件,刪除頁面對應(yīng)的vnode;
  • vue-keep-alive組件中所有緩存均被刪除時(shí),通知?jiǎng)h除整個(gè)子應(yīng)用緩存;

3.4 整體框架

最后,我們從整體的視角來了解下多頁簽緩存的實(shí)現(xiàn)方案。

因?yàn)椴粌H僅需要對子應(yīng)用的緩存進(jìn)行管理,還需要將vue-keep-alive組件注冊到各個(gè)子應(yīng)用中等事項(xiàng),我們將這些服務(wù)統(tǒng)一在主應(yīng)用的mainService中進(jìn)行管理,在registerMicroApps注冊子應(yīng)用時(shí)通過props傳入子應(yīng)用,這樣就能夠?qū)崿F(xiàn)同一套代碼,多處復(fù)用。

圖片

// 子應(yīng)用main.js
let mainService = null;


export async function mount(props) {
mainService = null;
const { MainService } = props;
// 注冊主應(yīng)用服務(wù)
mainService = new MainService({
// 傳入對應(yīng)參數(shù)
});
// 實(shí)例化vue并渲染
mainService.render(props);
}
export async function unmount() {
mainService.unmountCache();
}

最后對關(guān)鍵流程進(jìn)行梳理:

圖片

四、現(xiàn)有問題

4.1 暫時(shí)只支持vue框架的實(shí)例緩存

該方案也是基于vue現(xiàn)有特性支持實(shí)現(xiàn)的,在react社區(qū)中對于多頁簽實(shí)現(xiàn)并沒有統(tǒng)一的實(shí)現(xiàn)方案,筆者也沒有過多的探索,考慮到現(xiàn)有項(xiàng)目是以vue技術(shù)棧為主,后期升級也會(huì)只升級到vue3.0,在一段時(shí)間內(nèi)是可以完全支持的。

五、總結(jié)

相較于社區(qū)上大部分通過方案一進(jìn)行實(shí)現(xiàn),本文提供了另一種實(shí)現(xiàn)多頁簽緩存的一種思路,主要是對子應(yīng)用緩存處理上有些許的不同,大致的思路及通信的方式都是互通的。

另外本文對qiankun框架的使用沒有做太多的發(fā)散總結(jié),官網(wǎng)和Github上已經(jīng)有很多相關(guān)問題的總結(jié)和踩坑經(jīng)驗(yàn)可供參考。

責(zé)任編輯:未麗燕 來源: vivo互聯(lián)網(wǎng)技術(shù)
相關(guān)推薦

2020-05-06 09:25:10

微前端qiankun架構(gòu)

2022-02-13 23:00:48

前端微前端qiankun

2022-10-09 14:05:24

前端single-spa

2022-01-17 11:41:50

前端Vite組件

2020-11-09 11:10:56

前端api緩存

2017-09-01 18:27:36

前端 RxJs數(shù)據(jù)層

2023-03-10 10:29:19

前端邏輯拆分

2022-09-07 21:31:19

微前端架構(gòu)iframe

2023-11-03 08:04:47

Web微前端框架

2024-04-26 09:33:18

攜程實(shí)踐

2022-01-24 12:38:58

Vite插件開發(fā)

2022-05-26 21:33:09

業(yè)務(wù)前端測試

2022-08-27 21:37:57

PrometheusRedis?監(jiān)控

2024-05-16 08:18:55

TabsArkUI增刪頁簽功能

2022-08-10 10:32:47

編程實(shí)踐

2022-05-26 10:12:21

前端優(yōu)化測試

2023-06-12 21:32:56

卡口服務(wù)系統(tǒng)

2022-06-27 09:36:29

攜程度假GraphQL多端開發(fā)

2020-06-02 09:45:07

微前端組件代碼

2021-09-09 09:43:38

MaxComputePAI 阿里云
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

日本xxx在线播放| 成人一对一视频| 国产丝袜在线视频| 亚洲国产三级| 日韩激情在线视频| 手机在线免费观看毛片| 最新超碰在线| 成人h动漫精品一区二区| 日本欧美一级片| 日韩在线一卡二卡| 日韩大尺度在线观看| 欧美日韩成人综合在线一区二区| 日本黄xxxxxxxxx100| 天堂成人在线观看| 日韩不卡一区二区三区 | 久色视频在线| 精品亚洲国内自在自线福利| 欧美亚州一区二区三区| 亚洲一级二级片| 免费一区二区| 精品日韩在线一区| 日韩一区二区三区久久| 国产在线天堂www网在线观看| 国产精品色眯眯| 精品在线一区| aaa国产视频| 蜜臀久久久99精品久久久久久| 97视频网站入口| 久久中文免费视频| 欧洲乱码伦视频免费| 亚洲第一精品久久忘忧草社区| 天堂av8在线| 亚洲1234区| 亚洲3atv精品一区二区三区| 国产又黄又爽免费视频| 成a人片在线观看www视频| 99久久久免费精品国产一区二区| 91亚洲一区精品| 丰满人妻一区二区三区四区| 国产精品视频| 97欧美精品一区二区三区| 日韩欧美综合视频| 小处雏高清一区二区三区| 国产小视频国产精品| 亚洲久久久久久| 成人午夜网址| 欧美videossexotv100| 日韩av自拍偷拍| 久草综合在线| 欧美日韩在线播| 黄色在线视频网| 99riav视频一区二区| 在线观看av一区| 亚洲视频在线a| 春暖花开亚洲一区二区三区| 色综合天天视频在线观看 | а√天堂资源官网在线资源| 一区二区三区四区在线免费观看| 国产精品啪啪啪视频| 国产在线一区二区视频| 亚洲美女屁股眼交| 精品无码av无码免费专区| 性欧美高清come| 一区二区高清免费观看影视大全 | 免费看裸体网站| 成人aaaa| 爱福利视频一区| 国产av无码专区亚洲av毛网站| 欧美成人有码| 亚洲 日韩 国产第一| 国产高潮久久久| 日本伊人色综合网| 国产专区欧美专区| 亚洲AV无码成人片在线观看| 99视频精品免费视频| 蜜桃导航-精品导航| 成a人片在线观看www视频| 亚洲丝袜制服诱惑| 岛国大片在线播放 | 成人www视频在线观看| 国产永久免费视频| 国产精品一区在线| 精品欧美国产| 91在线直播| 亚洲猫色日本管| 97超碰青青草| 日韩福利在线观看| 亚洲成成品网站| 国产亚洲精品熟女国产成人| 久久久久国产| 51色欧美片视频在线观看| 成人毛片一区二区三区| 国产精品自拍一区| 欧美xxxx黑人又粗又长密月| 暖暖日本在线观看| 懂色aⅴ精品一区二区三区蜜月| 国产主播在线看| av在线国产精品| 亚洲老司机av| 国产麻豆视频在线观看| 亚洲影视在线| 亚洲www永久成人夜色| 亚洲AV第二区国产精品| 亚洲天堂免费在线观看视频| 久激情内射婷内射蜜桃| 日日夜夜精品| 日韩精品视频在线观看网址| 色偷偷www8888| 亚洲欧美日韩专区| 51蜜桃传媒精品一区二区| 国产在线中文字幕| 午夜精品123| 青青草原国产在线视频| 台湾色综合娱乐中文网| 欧美另类暴力丝袜| 一本色道久久综合熟妇| 久久综合久久99| 欧美黄色免费网址| 伊人亚洲精品| 国产一区二区三区直播精品电影| 日韩 欧美 自拍| 亚洲第一av| 精品国一区二区三区| 亚洲天堂av中文字幕| 国产精品入口| 国产精品中出一区二区三区| 精精国产xxxx视频在线| 欧美午夜精品久久久久久超碰 | 久久久精品一品道一区| 777久久精品一区二区三区无码| 素人一区二区三区| 亚洲精品一区在线观看香蕉| 精品无码久久久久久久久| 久久精品国产网站| 国产精品福利网| 亚洲无码精品一区二区三区| av毛片久久久久**hd| 日本大胆人体视频| 玖玖玖视频精品| 久久久国产精品一区| 97人妻精品一区二区三区视频| 国产香蕉久久精品综合网| 国产精品亚洲a| 一区二区三区视频免费观看| 91国内在线视频| 日本xxxxwww| 亚洲一区二区欧美日韩| 欧洲成人午夜精品无码区久久| 五月激情综合| 亚洲qvod图片区电影| 国产精品va在线观看视色| 91麻豆精品国产自产在线观看一区 | 超碰97成人| 久久久免费电影| 神宫寺奈绪一区二区三区| 一区二区久久久久| 国产人妻黑人一区二区三区| 亚洲麻豆av| 久久久久网址| 电影天堂国产精品| 色综合伊人色综合网站| 国产精品久久久久久久免费| 亚洲久草在线视频| 911亚洲精选| 国产精品普通话对白| 欧美一级片免费观看| 欧美激情福利| 欧美成人黄色小视频| 亚洲精品视频网| 精品久久久久久久久中文字幕 | 好吊色一区二区| 午夜欧美视频在线观看| 久久久久久久久久久国产精品| 老牛影视一区二区三区| 亚洲看片网站| 亚洲一区二区电影| …久久精品99久久香蕉国产| 成年人在线观看网站| 91麻豆精品国产91久久久使用方法 | 亚洲伦理在线精品| 色婷婷免费视频| 日韩和的一区二区| 9色视频在线观看| 日韩高清一级| 国产欧美一区二区三区久久人妖 | 又紧又大又爽精品一区二区| 亚洲麻豆一区二区三区| 性久久久久久| 在线免费观看成人| 久久精品国产亚洲blacked| 国产999精品| 主播国产精品| 亚洲美女免费精品视频在线观看| 91精品视频免费在线观看 | 91精品国产日韩91久久久久久| 激情五月综合色婷婷一区二区| 美女色狠狠久久| 欧美激情在线观看| 国产成人天天5g影院在线观看| 91麻豆精品91久久久久久清纯 | 欧美做受喷浆在线观看| 奇米精品一区二区三区在线观看 | 久久91精品国产91久久小草| 屁屁影院ccyy国产第一页| 国内精品伊人久久久| 99九九视频| 成人午夜毛片| 欧美亚洲日本网站| 黄在线免费看| 精品一区二区三区电影| 99热精品在线播放| 在线一区二区三区| 男女视频免费看| 亚洲三级在线观看| 久久久久久国产免费a片| 成人午夜又粗又硬又大| 国产三级生活片| 久色成人在线| 精品久久一二三| 欧美精品午夜| 国产麻豆电影在线观看| 欧美偷拍自拍| 欧美在线一二三区| 久久九九热re6这里有精品 | 欧美影院天天5g天天爽| 亚洲一区二区三区视频| av在线不卡精品| 日本电影亚洲天堂| 成人ssswww在线播放| 欧美黑人又粗大| 免费在线视频欧美| 色偷偷亚洲男人天堂| 国产一级网站视频在线| 亚洲乱码一区av黑人高潮| 欧美一区二区在线观看视频| 欧美一区二区日韩| 91久久国语露脸精品国产高跟| 欧洲精品中文字幕| 天天干天天插天天射| 欧美性猛交xxxx乱大交3| 日韩毛片在线播放| 亚洲福中文字幕伊人影院| 免费人成年激情视频在线观看| 国产精品无码永久免费888| 久久成人激情视频| 91香蕉视频黄| 日本japanese极品少妇| 不卡一区中文字幕| 可以看的av网址| 国产黄色成人av| 色欲欲www成人网站| 国产suv一区二区三区88区| 国产精品偷伦视频免费观看了 | 欧美日韩免费一区二区三区视频| 国产99免费视频| 欧美伊人久久大香线蕉综合69 | 日韩久久久久久| 亚洲男人天堂久久| 亚洲成色www8888| 香蕉视频免费在线看| 亚洲毛片一区二区| 国产中文字幕在线视频| 丝袜亚洲另类欧美重口| 精品美女在线观看视频在线观看 | 国产在线精品视频| 男生和女生一起差差差视频| 成人免费视频免费观看| 一起草在线视频| 久久久久久日产精品| 亚洲精品视频网址| 亚洲欧洲三级电影| 劲爆欧美第一页| 欧美日韩激情网| 波多野结衣二区三区| 7777精品伊人久久久大香线蕉完整版 | 久久老司机精品视频| 欧美日韩国产区| 国产成人av免费| 日韩欧美亚洲一区二区| 亚洲人视频在线观看| 国产一区二区三区视频在线观看| 日本成人在线播放| 欧美激情亚洲一区| 新片速递亚洲合集欧美合集| 国产欧美中文字幕| 大伊香蕉精品在线品播放| 免费成人av网站| 99视频精品全国免费| 青草视频在线观看视频| 日韩国产精品久久久久久亚洲| 国产精品嫩草影视| 91视频91自| 91九色丨porny丨极品女神| 一级中文字幕一区二区| 一级片免费在线播放| 欧美女孩性生活视频| 午夜激情在线视频| 精品国产一区av| 中文一区一区三区高中清不卡免费 | 在线观看日本一区| 国产一区二区三区久久| 精品综合久久久久| 久久中文娱乐网| 欧美日韩精品在线观看视频 | 97成人精品区在线播放| 色噜噜成人av在线| 久久久久久九九九九| 欧美影视一区| 三年中国国语在线播放免费| 成人动漫一区二区| 粉嫩av性色av蜜臀av网站| 欧美性受xxxx| 天堂在线免费av| 欧美激情精品在线| 激情不卡一区二区三区视频在线 | 都市激情在线视频| 午夜精品久久久久久99热软件| 日韩在线激情| 亚洲精品不卡| 日韩制服丝袜av| 7788色淫网站小说| 亚洲一区二区中文在线| 国产精品国产精品国产专区| 国产亚洲在线播放| 欧美xxxhd| 国产综合第一页| 亚洲性图久久| 国产精品一区二区无码对白| 亚洲色图另类专区| 97超碰人人草| 色yeye香蕉凹凸一区二区av| 182在线播放| 国产欧美在线一区二区| 国产精品大片| 中文字幕永久免费| 一区二区三区国产豹纹内裤在线| 97成人在线观看| 北条麻妃99精品青青久久| 国产亚洲欧美日韩精品一区二区三区| 美女一区视频| 蜜桃久久av| 四虎影成人精品a片| 欧美日韩国产一区二区| 四虎在线观看| 欧美一级淫片播放口| 亚洲精品白浆高清| 黄在线观看网站| 国产午夜精品久久久久久久| 久久久久久无码精品大片| 国产一区二区三区在线视频| 日韩成人高清| 正在播放一区| 国产麻豆成人精品| 欧美国产在线看| 亚洲精品国产精品久久清纯直播| 精精国产xxxx视频在线野外| 久久人人97超碰人人澡爱香蕉| 亚洲欧美成人| 国产精品av久久久久久无| 欧美日韩中文另类| 国产精品实拍| 操一操视频一区| 一本色道久久综合亚洲精品不卡| 久久精品老司机| 欧美在线视频日韩| 制服丝袜在线播放| 国产伦精品一区二区三区视频免费 | 风间由美中文字幕在线看视频国产欧美| 999一区二区三区| 99久久精品国产观看| 亚洲精品国产无码| 久久国产精品久久国产精品| 综合激情五月婷婷| 男女av免费观看| 国产精品国产成人国产三级| 亚洲国产综合网| 欧洲亚洲妇女av| 婷婷综合伊人| 四季av综合网站| 欧美性受极品xxxx喷水| 美洲精品一卡2卡三卡4卡四卡| 蜜桃网站成人| 国产一区二区在线看| 99视频在线看| 最新国产成人av网站网址麻豆| 97se亚洲| www.夜夜爽| 性欧美疯狂xxxxbbbb| av免费在线一区二区三区| 成人在线观看av| 免费在线观看精品| 韩国av免费观看| 久久综合久久美利坚合众国| 亚洲v天堂v手机在线| 视频免费1区二区三区| 精品久久久精品| 在线观看a级片| 色噜噜狠狠一区二区三区| 风间由美一区二区三区在线观看| 波多野结衣日韩|