日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > vue >内容正文

vue

Vue隐藏技能:运行时渲染用户写入的组件代码!

發布時間:2023/12/18 vue 51 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Vue隐藏技能:运行时渲染用户写入的组件代码! 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

作者:還沒想好

https://zhuanlan.zhihu.com/p/347509262

一語驚人

前段時間接了一個需求:能不能讓用戶自制組件,從而達到定制渲染某個區域的目的。說實話接到這個需求心中一驚,感嘆這個想法真是大膽呀,但作為打工人,秉承著只要思想不滑坡,辦法總比困難多的打工魂,即使是刀山也得上呀,歷經幾日的摸索調研,發現其實 VUE 一早就支持了這么做,只不過時過境遷,漸漸被遺忘了這個隱藏的技能。

大致說一下項目的背景:我們做了一個拖拽生成報表的系統,通過拖拽內置的組件供用戶定制自己的報表形態,但畢竟內置的組件有限,可定制性不高,那么給用戶開放一個 code 組件,讓用戶自己通過寫template?+?js?+?css的方式自由定制豈不是妙哉。

重提漸進式

那么該怎么實現呢?我們先來看一 vue 官方的介紹

Vue (讀音 /vju?/,類似于 view) 是一套用于構建用戶界面的漸進式框架。與其它大型框架不同的是,Vue 被設計為可以自底向上逐層應用。[1]

很多時候我們貌似已經忽略了漸進式這回事,現在基于 VUE 開發的項目大多都采用 vue cli 生成,以 vue 單文件的方式編碼,webpack 編譯打包的形式發布。這與漸進式有什么關系呢,確實沒有關系。

漸進式其實指的在一個已存在的但并未使用 vue 的項目上接入 vue,使用 vue,直到所有的 HTML 漸漸替換為通過 vue 渲染完成,漸進開發,漸進遷移,這種方式在 vue 剛出現那幾年比較多,現在或許在一些古老的項目也會出現。

為什么要提漸進式呢?因為漸進式是不需要本地編譯的,有沒有 get 到點!對,就是不需要本地編譯,而是運行時編譯。

本地編譯與運行時編譯

用戶想通過編寫template?+?js?+?css的方式實現運行時渲染頁面,那肯定是不能本地編譯的(此處的編譯指將 vue 文件編譯為 js 資源文件),即不能把用戶寫的代碼像編譯源碼一樣打包成靜態資源文件。

這些代碼只能原樣持久化到數據庫,每次打開頁面再恢復回來,實時編譯。畢竟不是純 js 文件,是不能直接運行的,它需要一個運行時環境,運行時編譯,這個環境就是?vue 的運行時 + 編譯器[2]

有了思路也只是窺到了天機,神功練成還是要打磨細節。具體怎么做,容我一步步道來。

技術干貨

第一步:需要一個運行時編譯環境

按官方的介紹[3],通過 script 標簽引入 vue 就可以漸進式開發了,也就具備了運行時+編譯器,如下

<!DOCTYPE?html> <html?lang="en"><head><title>Document</title><script?src="https://cdn.jsdelivr.net/npm/vue"></script></head><body><div?id="app">{{message}}</div><script?type="text/javascript">var?app?=?new?Vue({el:?"#app",data:?{message:?"Hello?Vue!",},});</script></body> </html>

但通過 vue 單文件+webpack 編譯的方式,再引入一個 vue 就多余了,通過 CLI 也是可以的,只需要在 vue.config.js 中打開 runtimeCompiler 開關就行了,詳細看文檔[4]

此時我們就有了一個運行時編譯環境

第二步:把用戶的代碼注冊到系統中

把代碼渲染出來有兩個方案

  • 通過?注冊組件[5]?的方式,把代碼注冊為 vue 實例的組件,注冊組件又分 全局注冊 和 局部注冊 兩種方式

  • 通過掛載點直接掛載 vue 實例, 即通過new Vue({ el: '#id' })的方式

  • 第一種方案:動態組件

    對于這種方式,在官方文檔中,組件注冊章節,最后給出了一個注意點

    記住全局注冊的行為必須在根 Vue 實例 (通過 new Vue)?創建之前發生。

    因此,并不能通過調用Vue.component('my-component-name', {/* */})的方式將用戶的代碼注冊到系統中,因為運行時 Vue 實例已經創建完,用戶的代碼是在實例完 Vue 后才進來的,那我們只能通過局部注冊的方式了,類似這樣

    var?ComponentB?=?{components:?{"component-a":?{...customJsLogic,name:?"custom-component",template:?"<div>custom?template</div>",},},//?... };

    但想一下,好像不太對,這還是在寫源碼,運行時定義了ComponentB組件怎么用呢,怎么把ComponentB在一個已經編譯完頁面上渲染出來呢?找不到入口點,把用戶代碼注入到components對象上也無法注冊到系統中,無法渲染出來。

    就止步于此了嗎?該怎么辦呢?

    想一下為什么要在components中先注冊(聲明)下組件,然后才能使用?component 本質上只不過是一個 js object 而已。其實主要是為了服務于 template 模板語法,當你在 template 中寫了?<compA propA='value'/>,有了這個注冊聲明才能在編譯時找到compA。如果不使用 template,那么這個注冊就可以省了。

    不使用 template 怎么渲染呢,使用render 函數[6]呀!

    在 render 函數中如果使用 createElement 就比較麻煩了,API 很復雜,對于渲染一整段用戶定義的 template 也略顯吃力,使用 jsx 就方便多了,都 1202 年了,想必大家對 jsx 都應該有所了解。

    回到項目上,需要使用用戶代碼的地方不止一處,都用 render 函數寫一遍略顯臃腫,那么做一個 code 的容器,容器負責渲染用戶的代碼,使用地方把容器掛上就行了。

    • 容器核心代碼

    export?default?{name:?"customCode",props:?{template:?String,?//?template模板js:?String,?//?js邏輯css:?String,?//?css樣式},computed:?{className()?{//?生成唯一class,主要用于做scoped的樣式const?uid?=?Math.random().toString(36).slice(2);return?`custom-code-${uid}`;},scopedStyle()?{if?(this.css)?{const?scope?=?`.${this.className}`;const?regex?=?/(^|\})\s*([^{]+)/g;//?為class加前綴,做類似scope的效果return?this.css.trim().replace(regex,?(m,?g1,?g2)?=>?{return?g1???`${g1}?${scope}?${g2}`?:?`${scope}?${g2}`;});}return?"";},component()?{//?把代碼字符串轉成js對象const?component?=?safeStringToObject(this.js);//?去掉template的前后標簽const?template?=?(this.template?||?"").replace(/^?*<?*template?*>|<\/?*template?*>?*$/g,?"").trim();//?注入template或render,設定template優先級高于renderif?(this.template)?{component.template?=?this.template;component.render?=?undefined;}?else?if?(!component.render)?{component.render?=?"<div>未提供模板或render函數</div>";}return?component;},},render()?{const?{?component?}?=?this;return?(<div?class={this.className}><style>{this.scopedStyle}</style><component?/></div>);}, };
    • 容器使用

    <template><custom-code?:js="js"?:template="template"?:css="css"?/> </template>

    以上只是核心的邏輯部分,除了這些,在項目實戰中還應考慮容錯處理,錯誤大致可以分兩種

  • 用戶代碼語法錯誤

    主要是 js 部分,對于 css 和 template 的錯誤,瀏覽器有一定的糾錯的機制,不至于崩了。

    這部分的處理主要借助于safeStringToObject這個函數,如果有語法錯誤,則返回 Error,處理一下回顯給用戶,代碼大致如下

    //?component對象在result.value上取,如果result.error有值,則代表出現了錯誤 component()?{//?把代碼字符串轉成js對象const?result?=?safeStringToObject(this.js)const?component?=?result.valueif?(result.error)?{console.error('js?腳本錯誤',?result.error)result.error?=?{msg:?result.error.toString(),type:?'js腳本錯誤',}result.value?=?{?hasError:?true?}return?result}//?...retrun?result }
  • 組件運行時錯誤

    既然把 js 邏輯交給了用戶控制,那么像類型錯誤,從 undefined 中讀值,把非函數變量當函數運行,甚至拼寫錯誤等這些運行時錯誤就很有可能發生。

    這部分的處理需要通過在容器組件上添加?`errorCaptured`這個官方鉤子[7],來捕獲子組件的錯誤,因為并沒有一個途徑可以獲取組件自身運行時錯誤的鉤子。代碼大致如下

    errorCaptured(err,?vm,?info)?{this.subCompErr?=?{msg:?err?&&?err.toString?&&?err.toString()?||?err,type:?'自定義組件運行時錯誤:',}console.error('自定義組件運行時錯誤:',?err,?vm,?info) },
  • 結合錯誤處理,如果希望用戶能看到錯誤信息,則 render 函數需要把錯誤展示出來,代碼大致如下

    render()?{const?{?error:?compileErr,?value:?component?}?=?this.componentconst?error?=?compileErr?||?this.subCompErrlet?errorDomif?(error)?{errorDom?=?<div?class='error-msg-wrapper'><div>{error.type}</div><div>{error.msg}</div></div>}return?<div?class='code-preview-wrapper'><div?class={this.className}><style>{this.scopedStyle}</style><component?/></div>{errorDom}</div> },

    這里還有一個點,用戶發現組件發生了錯誤后會修改代碼,使其再次渲染,錯誤的回顯需要特別處理下。

    對于 js 腳本錯誤,因 component 是計算屬性,隨著 computed 計算屬性再次計算,如果 js 腳本沒有錯誤,導出的 component 可重繪出來,

    但對于運行時錯誤,使用this.subCompErr內部變量保存,props 修改了,這個值卻不會被修改,因此需要打通 props 關聯,通過添加 watch 的方式解決,這里為什么沒有放在 component 的計算屬性中做,一是違背計算屬性設計原則,二是 component 可能并不僅僅依賴 js,css,template 這個 props 的變化,而this.subCompErr只需要和這個三個 props 關聯,這么做會有多余的重置邏輯。

    還有一種場景就是子組件自身可能有定時刷新邏輯,定期或不定期的重繪,一旦發生了錯誤,也會導致一直顯示錯誤信息,因為用戶的代碼拿不到this.subCompErr的值,因此也無法重置此值,這種情況,可通過注入beforeUpdate鉤子解決,代碼大致如下

    computed:?{component()?{//?把代碼字符串轉成js對象const?result?=?safeStringToObject(this.js)const?component?=?result.value//?...//?注入mixinscomponent.mixins?=?[{//?注入?beforeUpdate?鉤子,用于子組件重繪時,清理父組件捕獲的異常beforeUpdate:?()?=>?{this.subCompErr?=?null},}]//?...return?result}, }, watch:?{js()?{//?當代碼變化時,清空error,重繪this.subCompErr?=?null},template()?{//?當代碼變化時,清空error,重繪this.subCompErr?=?null},css()?{//?當代碼變化時,清空error,重繪this.subCompErr?=?null},},

    完整的代碼見:https://github.com/merfais/vue-demo/blob/main/src/views/customCode/withComponent.vue[8]

    完整的 demo 見:https://merfais.github.io/vue-demo/#/custom-code[9]

    第二種方案:動態實例

    我們知道在利用 vue 構建的系統中,頁面由組件構成,頁面本身其實也是組件,只是在部分參數和掛載方式上有些區別而已。這第二種方式就是將用戶的代碼視為一個 page,通過 new 一個 vm 實例,再在 DOM 掛載點掛載 vm(new Vue(component).$mount('#id'))的方式渲染。

    動態實例方案與動態組件方案大致相同,都要通過 computed 屬性,生成component對象和scopedStyle對象進行渲染,但也有些許的區別,動態實例比動態組件需要多考慮以下幾點:

  • 需要一個穩定的掛載點

    從 vue2.0 開始,vue 實例的掛載策略變更為,所有的掛載元素會被 Vue 生成的 DOM 替換[10],在此策略下,一旦執行掛載,原來的 DOM 就會消失,不能再次掛載。但我們需要實現代碼變更后能夠重新渲染,這就要求掛載點要穩定存在,解決方案是對用戶的 template 進行注入,每次渲染前,在 template 外層包一層帶固定 id 的 DOM

  • 運行時錯誤捕獲errorCaptured需要注入到component對象上,不再需要注入beforeUpdate鉤子

    因為通過new Vue()的方式創建了一個新的 vm 實例,不再是容器組件的子組件,所以容器組件上的errorCaptured無法捕獲新 vm 的運行時錯誤,new Vue(component)中參數 component 是頂層組件,根據?Vue 錯誤傳播規則[11]?可知,在非特殊控制的情況下,頂層的?errorCaptured?會捕獲到錯誤

  • 首次掛載需要制造一定的延遲才能渲染

    由于掛載點含在 DOM 在容器內,與計算屬性導出的component對象在首次掛載時時序基本是一致的,導致掛載 vm($mount('#id'))時,DOM 可能還沒有渲染到文檔流上,因此在首次渲染時需要一定的延遲后再掛載 vm。

  • 以上的不同點,并未給渲染用戶自定義代碼帶來任何優勢,反而增加了限制,尤其?需要穩定掛載點?這一條,需要對用戶提供的 template 做二次注入,包裹掛載點,才能實現用戶修改組件后的實時渲染更新,因此,也不能支持用戶定義 render 函數,因為無法獲取未經運行的 render 函數的返回值,也就無法注入外層的掛載點。

    另外一點也需要注意,這種方式也是無法在容器組件中使用 template 定義渲染模板的,因為如果在 template 中寫 style 標簽會出現以下編譯錯誤,但 style 標簽是必須的,需要為自定義組件提供 scoped 的樣式。(當然,也可以通過提供 appendStyle 函數實現動態添加 style 標簽,但這樣并沒有更方便,因此沒有必要)

    ??Errors?compiling?template:Templates?should?only?be?responsible?for?mapping?the?state?to?the?UI.?Avoid?placing?tags?with?side-effects?in?your?templates,?such?as?<style>,?as?they?will?not?be?parsed.2??|??<span :class="className">3??|????<span id="uid"?/>4??|????<style>{this.scopedStyle}</style>|????^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^5??|??</span>|??^^^^^^^

    鑒于以上缺點,就不提供核心代碼示范了,直接給源碼和 demo

    完整的代碼見:https://github.com/merfais/vue-demo/blob/main/src/views/customCode/withMount.vue[12]

    完整的 demo 見:https://merfais.github.io/vue-demo/#/custom-code[13]

    想一下,如果動態實例方案僅僅有以上缺點,那考慮這種方案有什么意義呢?其實,它的意義在于,動態實例方案主要應用于 iframe 渲染,而使用 iframe 渲染的目的則是為了隔離。

    iframe 會創建獨立于主站的一個域,這種隔離可以很好地防止 js 污染和 css 污染,隔離方式又分為跨域隔離和非跨域隔離兩種,跨域則意味著完全隔離,非跨域則是半隔離,其主要區別在于安全策略的限制,這個我們最后再說。

    iframe 是否跨域由 iframe 的 src 的值決定,設置同域的 src 或不設置 src 均符合同域策略,否則是跨域。對于沒有設置 src 的 iframe,頁面只能加載一個空的 iframe,因此還需要在 iframe 加載完后再動態加載依賴的資源,如:vuejs,其他運行時的依賴庫(示例 demo 加載了 ant-design-vue)等。如果設置了 src,則可以將依賴通過 script 標簽和 link 標簽提前寫到靜態頁面文件中,使依賴資源在加載 iframe 時自動完成加載。

    先介紹半隔離方式,即通過非跨域 iframe 渲染,首先需要渲染一個 iframe,我們使用不設置 src 的方式,這樣更具備通用性,可以用于任意的站點。核心代碼如下

    <template><iframe?ref="iframe"?frameborder="0"?scrolling="no"?width="100%"?/> </template>

    由于是位于同域,主站與 iframe 可以互相讀取 window 和 document 引用,因為,可以動態加載資源,核心代碼如下

    methods:?{mountResource()?{//?添加依賴的cssappendLink('https://cdn.bootcdn.net/ajax/libs/ant-design-vue/1.7.2/antd.min.css',?this.iframeDoc)//?添加依賴的js,保留handler用于首次渲染的異步控制this.mountResourceHandler?=?appendScriptLink([{src:?'https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js',defer:?true,},?{src:?'https://cdn.bootcdn.net/ajax/libs/ant-design-vue/1.7.2/antd.min.js',defer:?true,}],?this.iframeDoc)}, }, mounted()?{this.iframeDoc?=?this.$refs.iframe.contentDocumentthis.mountResource() },

    接下來是組件對象組裝和掛載,基本上和動態組件的大同小異,只是掛載不再通過 render 函數。先上核心代碼,再說注意點。

    ??computed:?{component()?{//?把代碼字符串轉成js對象const?component?=?safeStringToObject(this.js)//?關聯css,為的是修改css后可自動重繪component.css?=?this.css//?去掉template的前后標簽const?template?=?(this.template?||?'').replace(/^?*<?*template?*>|<\/?*template?*>?*$/g,?'').trim()//?注入template或render,設定template優先級高于renderif?(template)?{component.template?=?templatecomponent.render?=?undefined}?else?if?(!component.render)?{component.template?=?'<span>未提供模板或render函數</span>'}return?component},},watch:?{component()?{if?(this.hasInit)?{this.mountCode()}?else?if?(this.mountResourceHandler)?{this.mountResourceHandler.then(()?=>?{this.hasInit?=?truethis.mountCode()})}},},methods:?{mountCode()?{//?添加cssconst?css?=?this.component.cssdelete?this.component.cssremoveElement(this.styleId,?this.iframeDoc)this.styleId?=?appendStyle(css,?this.iframeDoc)//?重建掛載點if?(this.iframeDoc.body.firstElementChild)?{this.iframeDoc.body.removeChild(this.iframeDoc.body.firstElementChild)}prependDom({?tag:?'div',?id:?'app'?},?this.iframeDoc)//?掛載實例const?Vue?=?this.iframeWin.Vuenew?Vue(this.component).$mount('#app')},},

    注意點:

  • iframe 的渲染到文檔流后才能添加依賴資源,依賴資源加載完才能執行 vm 的掛載,首次加載時需要控制時序

  • vm 掛載點的重建采用了永遠添加在 body 的第一個子元素的方式,這么做的原因是一些第三方的庫(如 ant-design-vue)也會向 body 中動態添加 element,雖然采用docment.body.innerHTML=''的方式可以快速且干凈的清空 body 內容,但也會將第三方庫添加的內容給干掉,導致第三方庫全部或部分不可用。

  • 為了使 css 變化后也引發重繪,在計算屬性component中也綁定了 css 的值,但這對于新建 vm 實例這個字段是無用的,也可以通過 watch css 的方式實現

  • 接下來考慮錯誤處理,對于 iframe 掛載的錯誤處理稍有不同,為了盡量不干預用戶的代碼,此模式下的錯誤渲染采用重建 DOM,重新渲染 vm 的策略,即發生錯誤后,無論是靜態的語法錯誤還是運行時錯誤,都重繪。當然這種做法也就丟失了組件自刷新的功能,因為一旦發生錯誤,原來的組件會被卸載,渲染為錯誤信息。核心代碼如下

    ?computed:?{component()?{if?(this.subCompErr)?{return?this.renderError(this.subCompErr)}//?把代碼字符串轉成js對象const?result?=?safeStringToObject(this.js)if?(result.error)?{return?this.renderError({type:?'js腳本錯誤',msg:?result.error.toString(),})}const?component?=?result.value//?注入errorCaptured,?用于錯誤自定義組件運行時捕獲component.errorCaptured?=?(err,?vm,?info)?=>?{this.subCompErr?=?{msg:?err?&&?err.toString?&&?err.toString(),type:?'自定義組件運行時錯誤:',}console.error('自定義組件運行時錯誤:',?err,?vm,?info)}return?component},},watch:?{js()?{//?當代碼變化時,清空error,重繪this.subCompErr?=?null},template()?{//?當代碼變化時,清空error,重繪this.subCompErr?=?null},css()?{//?當代碼變化時,清空error,重繪this.subCompErr?=?null},},methods:?{renderError({?type,?msg?})?{return?{render()?{return?<div?style='color:?red'><div>{type}</div><div>{msg}</div></div>},}},},

    除了錯誤處理,還需解決一下 iframe 的一些特性,比如邊框,滾動條,默認寬高,其中比較棘手是 iframe 高度有默認值,并不會隨著 iframe 的內容自適應高度,但對于自定義組件的渲染,需要動態計算高度,固定高度是不行的。

    邊框,滾動條,寬度可通過修改 iframe 的屬性解決,見上面的 template 代碼。

    高度自適應的解決方案是通過MutationObserver觀測 iframe 的 body 變化,在回調中計算掛載點(第一個子元素)的高度,然后再修改 iframe 本身的高度。之所以沒有直接使用 body 的高度,是因為 body 有默認的高度,當被渲染的組件高度小于 body 高度時,直接使用 body 的高度是錯的。核心代碼如下

    mounted()?{//?通過觀察器觀察iframe的body變化后修改iframe的高度,//?使用iframe后垂直的margin重合效果會丟失const?observer?=?new?MutationObserver(()?=>?{const?firstEle?=?this.iframeDoc.body.firstElementChildconst?rect?=?firstEle.getBoundingClientRect()const?marginTop?=?parseFloat(window.getComputedStyle(firstEle).marginTop,?10)const?marginBottom?=?parseFloat(window.getComputedStyle(firstEle).marginBottom,?10)this.$refs.iframe.height?=?`${rect.height?+?marginTop?+?marginBottom}px`})observer.observe(this.iframeDoc.body,?{?childList:?true?}) },

    使用 iframe 還存在一些局限性,最需要注意的一點就是由于 iframe 是獨立的窗體,那么渲染出來的組件只能封在這個窗體內,因此,像一些本應該是全局的 toast, modal, drawer 都會被局限在 iframe 內,無法覆蓋到全局上。

    完整的代碼見:https://github.com/merfais/vue-demo/blob/main/src/views/customCode/mountSameIframe.vue[14]

    完整的 demo 見:https://merfais.github.io/vue-demo/#/custom-code[15]

    至此非跨域 iframe 渲染全部邏輯介紹完畢,接下來看一下跨域 iframe 的渲染。跨域 iframe 與非跨域 iframe 的渲染過程基本是一致的,只是有由于跨域,隔離的更徹底。其主要體現在主域與 iframe 域不能互相讀寫對方的文檔流 document。

    此限制帶來的變化有以下幾點

  • 依賴的資源需要提前內置在 iframe 內。

    內置指的是將依賴的資源通過 script,link 標簽添加到 html 文件中,隨 html 一并加載。有一點還需要注意,如果掛載 vm 時需要依賴某些資源,需要添加資源加載的回調,加載成功后再通知主域掛載。

  • iframe 重新繪制需要各種元素操作只能由 iframe 自己完成

    在非跨域 iframe 模式下所有的元素操作都在主域中完成,在跨域模式下這些操作和流程控制都需要以 script 編碼的方式內置在 html 內,在接到主域的掛載消息后,完整掛載過程。

  • 主域與 iframe 的通信需要通過postMessage。

    為了通用性,調用postMessage時可以設置origin = *,但由于接收 postMessage 消息通過?window.addEventListener("message", callback)這種通用的方式,可能會接受來自多個域的非期待的消息,因此,需要對通信消息定制特殊協議格式,防止出現處理了未知消息而發生異常。

    兩者間通信是雙向的,主站向 iframe 只需傳遞一種消息,即含組件完整內容的掛載消息,iframe 接到消息后執行重繪渲染邏輯;iframe 向主站傳遞兩種消息,一是可以掛載的狀態消息,主站接到消息后執行首次渲染邏輯,即發送首次掛載消息,二是 body size 變化的消息,主站接到消息后修改 iframe 的尺寸。

  • 在處理主域將組件內容通過postMessage傳給 iframe 時,碰到了一個棘手的問題,postMessage 對可傳遞的數據有限制,具體的限制可查看?The structured clone algorithm[16],這個限制導致Function類型的數據無法傳過去,但組件很多功能需要使用函數才能實現,無法跨越這個限制,組件能力將損失過半或更甚。

    對于這個限制的解決方案是:對不支持的數據類型進行序列化,轉成支持的類型,如 string,渲染時再反序列化回來。核心代碼如下

    //?序列化 function?serialize(data)?{//?對象深度遞歸if?(Object.prototype.toString.call(data)?===?"[object?Object]")?{const?result?=?{};forEach(data,?(item,?key)?=>?{result[key]?=?this.serialize(item);});return?result;}if?(Array.isArray(data))?{return?data.map((item)?=>?this.serialize(item));}//?函數前后打上特殊標記后轉成stringif?(typeof?data?===?"function")?{return?encodeURI(`##${data.toString()}##`);}//?其他類型直接返回return?data; } //?反序列化 function?deserialize(data)?{//?對象深度遞歸if?(Object.prototype.toString.call(data)?===?"[object?Object]")?{const?result?=?{};Object.keys(data).forEach((key)?=>?{result[key]?=?this.deserialize(data[key]);});return?result;}if?(Array.isArray(data))?{return?data.map((item)?=>?this.deserialize(item));}//?string類型嘗試解析if?(typeof?data?===?"string")?{const?str?=?decodeURI(data);//?匹配特殊標記,匹配成功,反轉為functionconst?matched?=?str.match(/^##([^#]*)##$/);if?(matched)?{//?string轉成function可以用eval也可用new?Functionreturn?newFn(matched[1]);}return?data;}//?其他類型直接返回return?data; }

    序列化方案看似完美,其實也有諸多的不便,畢竟是一種降級,需要特別注意的一點是,閉包被破壞,或者說是不支持閉包函數,舉個例子:

    computed:?{component()?{//?把代碼字符串轉成js對象const?result?=?safeStringToObject(this.js)if?(result.error)?{return?this.renderError({type:?'js腳本錯誤',msg:?result.error.toString(),})}//?...return?component}, }, methods:?{renderError({?type,?msg?})?{return?{//?這里用到了閉包,render函數使用了外層變量type和msg,//?renderError函數執行結束后這兩個變量并不會釋放,需等render函數執行后才會釋放render()?{return?<div?style='color:?red'><div>{type}</div><div>{msg}</div></div>}}}, },

    上面在生成 component 對象時調用了函數renderError,此函數返回了一個函數render,且使用了外層函數renderError的兩個參數,正常情況下運行是沒有問題的,type和msg的引用(引用計數)會等到render函數執行后才會釋放(引用計數清零)。

    但 component 對象經過序列化后,其內部的函數被轉成了字符串,因而丟失了函數的所有特性,閉包也因此丟失,經反序列化回來后,雖然還原了函數,但閉包關系無法恢復,因此,這種寫法,在執行 render 時,type和msg兩個參數會變為undefined。

    為了規避這種限制,應在導出 component 對象時避免使用含閉包的函數, 上例中的錯誤處理可通過以下方式解決

    computed:?{component()?{//?把代碼字符串轉成js對象const?result?=?safeStringToObject(this.js)if?(result.error)?{const?template?=?this.genErrorTpl({type:?'js腳本錯誤',msg:?result.error.toString(),})return?{?template?}}//?...return?component}, }, methods:?{genErrorTpl({?type,?msg?})?{return?`<div?style='color:?red'><div>${type}</div><div>${msg}</div></div>`}, }

    完整的代碼見:

    • 組件:https://github.com/merfais/vue-demo/blob/main/src/views/customCode/mountCrossIframe.vue[17]

    • iframe:?https://gitlab.com/merfais/static-page/-/blob/master/public/iframe.html[18]

    完整的 demo 見:https://merfais.github.io/vue-demo/#/custom-code[19]

    XSS 注入與安全

    通常情況下,在需要將用戶輸入持久化的系統中,都要考慮 XSS 的注入攻擊,而防止注入的主要表現則是使用戶輸入的數據不被執行,或不能被執行。

    而前文介紹的要支持用戶自定義組件的渲染,恰好就是要執行用戶代碼,可見,此功能勢必會帶來 XSS 注入風險。

    因此,在使用此功能時要慎重,在不同的應用場景中,要根據系統的安全級別,選取相應的方案。對比以上四種方案(1 種動態組件,3 種動態掛載)可做以下選擇

    在一些相對安全(允許 xss 注入,注入后沒有安全問題)的系統中,可以使用前三種方案中的任意一種,這三種都是可以通過注入獲取用戶 cookie 的。個人推薦使用第一種動態渲染方案,因為此方案靈活性和渲染完整度都是最高的。

    在一些不太安全(xss 注入可能會泄露 cookie 中的身份信息)的系統中,推薦使用最后一種跨域組件掛載方案,通過完全隔離策略可以最大程度的降低風險,當然此方案也有很多的局限性。

    參考資料

    [1]

    Vue (讀音 /vju?/,類似于 view) 是一套用于構建用戶界面的漸進式框架。與其它大型框架不同的是,Vue 被設計為可以自底向上逐層應用。:?https://cn.vuejs.org/v2/guide/index.html#Vue-js-%E6%98%AF%E4%BB%80%E4%B9%88

    [2]

    vue 的運行時 + 編譯器:?https://cn.vuejs.org/v2/guide/installation.html#%E8%BF%90%E8%A1%8C%E6%97%B6-%E7%BC%96%E8%AF%91%E5%99%A8-vs-%E5%8F%AA%E5%8C%85%E5%90%AB%E8%BF%90%E8%A1%8C%E6%97%B6

    [3]

    官方的介紹:?https://learning.dcloud.io/#/?vid=2

    [4]

    詳細看文檔:?https://cli.vuejs.org/zh/config/#runtimecompiler

    [5]

    注冊組件:?https://cn.vuejs.org/v2/guide/components-registration.html

    [6]

    render 函數:?https://cn.vuejs.org/v2/guide/render-function.html

    [7]

    errorCaptured這個官方鉤子:?https://cn.vuejs.org/v2/api/index.html#errorCaptured

    [8]

    https://github.com/merfais/vue-demo/blob/main/src/views/customCode/withComponent.vue:?https://github.com/merfais/vue-demo/blob/main/src/views/customCode/withComponent.vue

    [9]

    https://merfais.github.io/vue-demo/#/custom-code:?https://merfais.github.io/vue-demo/#/custom-code

    [10]

    所有的掛載元素會被 Vue 生成的 DOM 替換:?https://cn.vuejs.org/v2/api/#el

    [11]

    Vue 錯誤傳播規則:?https://cn.vuejs.org/v2/api/#errorCaptured

    [12]

    https://github.com/merfais/vue-demo/blob/main/src/views/customCode/withMount.vue:?https://github.com/merfais/vue-demo/blob/main/src/views/customCode/withMount.vue

    [13]

    https://merfais.github.io/vue-demo/#/custom-code:?https://merfais.github.io/vue-demo/#/custom-code

    [14]

    https://github.com/merfais/vue-demo/blob/main/src/views/customCode/mountSameIframe.vue:?https://github.com/merfais/vue-demo/blob/main/src/views/customCode/mountSameIframe.vue

    [15]

    https://merfais.github.io/vue-demo/#/custom-code:?https://merfais.github.io/vue-demo/#/custom-code

    [16]

    The structured clone algorithm:?https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm

    [17]

    https://github.com/merfais/vue-demo/blob/main/src/views/customCode/mountCrossIframe.vue:?https://github.com/merfais/vue-demo/blob/main/src/views/customCode/mountCrossIframe.vue

    [18]

    https://gitlab.com/merfais/static-page/-/blob/master/public/iframe.html:?https://gitlab.com/merfais/static-page/-/blob/master/public/iframe.html

    [19]

    https://merfais.github.io/vue-demo/#/custom-code:?https://merfais.github.io/vue-demo/#/custom-code

    關注公眾號秋風的筆記,一個專注于前端面試、工程化、開源的前端公眾號

    • 關注后回復簡歷獲取100+套的精美簡歷模板

    • 關注后回復好友拉你進技術交流群+面試交流群

    • 歡迎關注秋風的筆記

    總結

    以上是生活随笔為你收集整理的Vue隐藏技能:运行时渲染用户写入的组件代码!的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    99在线精品观看 | 久久免费黄色网址 | 亚洲久草在线视频 | 欧美精品一区二区性色 | 精品亚洲视频在线 | 91九色在线播放 | 色之综合网| 国产成人精品av在线 | 免费观看的黄色 | 国产中文字幕网 | 久草精品网 | 国产一级91 | 欧美日韩在线视频免费 | 国产精品免费久久久久久 | 精品国产精品久久 | 国产五月色婷婷六月丁香视频 | 丁香六月婷婷综合 | 五月婷婷中文 | 午夜精品久久久久 | 亚洲免费精品视频 | 国产午夜免费视频 | 久久综合久色欧美综合狠狠 | 中文字幕永久 | 黄在线免费看 | 黄色软件视频网站 | 日韩资源在线播放 | 不卡精品 | 丝袜美腿亚洲综合 | 日本在线观看黄色 | 日日麻批40分钟视频免费观看 | 91黄色视屏 | 日韩在线观看网站 | 丁香狠狠 | 97超碰在线免费观看 | 99精品欧美一区二区 | a视频免费在线观看 | 97在线视频免费播放 | 福利网址在线观看 | 97电影院在线观看 | 狠狠综合久久 | 香蕉久草在线 | 一区二区三区日韩视频在线观看 | 在线视频一区观看 | 欧美亚洲精品一区 | 免费亚洲视频在线观看 | 国产精品久久久久久久久久久久午夜 | 欧美精品九九99久久 | 狠狠色综合欧美激情 | 有没有在线观看av | 国产在线观看av | 99久久国产免费看 | 日本精品一二区 | 亚洲精品免费在线视频 | 91麻豆精品国产 | 久久人人爽人人人人片 | 日韩高清一二区 | 久久亚洲综合国产精品99麻豆的功能介绍 | 人人草在线视频 | 特级毛片aaa | 亚洲综合激情小说 | 日韩有码专区 | 国产精品福利在线观看 | 99久久日韩精品视频免费在线观看 | 顶级bbw搡bbbb搡bbbb | 最新国产精品视频 | 中文字幕成人网 | 日韩免费三级 | avav99| 久久久久观看 | 精品99在线视频 | av线上免费看 | 日本久久久亚洲精品 | 天天干天天在线 | 亚洲精品国产高清 | 日批视频国产 | 国产免费人成xvideos视频 | 亚洲日b视频 | 天天干天天操天天做 | 嫩草伊人久久精品少妇av | 久久黄色小说 | 国产一区二区久久久 | 免费日韩av片 | 精油按摩av | 久久成人亚洲欧美电影 | 国产精品久久久久久久久免费 | 日本女人在线观看 | 精品久久久久久久久亚洲 | 免费福利在线视频 | 国产成人精品区 | 91视频亚洲 | 激情欧美xxxx | 探花视频免费观看 | 久精品视频免费观看2 | 久久精品国产亚洲 | 久久久久亚洲精品国产 | 中文一二区 | 六月丁香六月婷婷 | 午夜影院日本 | 444av| 日韩性色 | 国产理论一区二区三区 | 免费在线观看的av网站 | 日韩国产在线观看 | 91亚洲成人| 婷婷网站天天婷婷网站 | 美女视频黄免费的 | 夜色成人av | 欧美日本在线视频 | 人人搞人人爽 | 亚洲精品videossex少妇 | a天堂一码二码专区 | 中文字幕在线免费看 | 日本韩国在线不卡 | a极黄色片 | 91久久丝袜国产露脸动漫 | 日韩精品中文字幕在线 | 久久视频网 | 69精品视频在线观看 | 91成人短视频在线观看 | 91麻豆精品国产91久久久使用方法 | 99热在线精品观看 | 日韩精品一区不卡 | 欧美一区在线观看视频 | 久久理伦片 | 欧美 日韩 国产 中文字幕 | 中文字幕制服丝袜av久久 | 97视频在线观看成人 | 日韩精品中文字幕在线 | 一区二区三区 中文字幕 | 日韩高清在线一区二区三区 | 欧美日韩在线播放 | 欧美日本不卡高清 | 精品国产精品一区二区夜夜嗨 | 91黄色在线看 | 国产高清在线视频 | 国产成人免费av电影 | 日本精品在线看 | 四虎国产精品免费 | 亚洲一区欧美精品 | 精品国自产在线观看 | 中文字幕在线电影 | 狠狠色狠狠色综合日日小说 | 亚洲精品无 | 日韩欧美视频在线免费观看 | 伊人久久婷婷 | av蜜桃在线 | 中文字幕在线播放一区 | 国产一区二区三区在线免费观看 | 在线免费试看 | 国产免费又黄又爽 | 国产又粗又硬又爽的视频 | 国产一区二区三区网站 | 中文字幕一区二区三区四区 | 久久精品久久精品久久39 | 国产精品18p| 国产成人av在线影院 | 日日夜夜天天久久 | 天天插综合 | 久久激情小视频 | 国产精品久久久久婷婷二区次 | 日本久久精品 | 成人av在线看 | av性网站 | 91精彩视频在线观看 | 天天干天天搞天天射 | 久久久国产日韩 | 国产一区 在线播放 | 97超碰在线资源 | 中文字幕在线播放视频 | 日韩网站在线免费观看 | 国产99久久99热这里精品5 | 日韩mv欧美mv国产精品 | 91精品国产高清自在线观看 | 成 人 黄 色 视频免费播放 | 人人狠 | 天天操狠狠操网站 | 久久不卡日韩美女 | 免费在线激情电影 | 国产999精品久久久久久 | 四虎永久国产精品 | 久久永久视频 | 亚洲精品乱码久久久久久蜜桃动漫 | 天天干天天干天天干天天干天天干天天干 | 在线观看免费国产小视频 | 免费看国产黄色 | 成人三级视频 | 国产手机在线观看视频 | 日本中文字幕在线视频 | 中文字幕av最新更新 | 中文字幕一区二区三区在线视频 | 国产小视频在线免费观看 | 亚洲va在线va天堂 | 人人爽人人看 | 久久影院精品 | 国产伦精品一区二区三区免费 | 国产日本亚洲 | 欧美性受极品xxxx喷水 | 青青草国产在线 | 日韩,中文字幕 | 97成人资源 | 日韩三级视频在线观看 | 最近日本mv字幕免费观看 | 91综合久久一区二区 | 日韩精品久久久久久久电影99爱 | 久久久2o19精品 | 亚洲视频高清 | 在线 精品 国产 | 亚洲免费资源 | 国产高清一级 | 欧美激情视频一二区 | 玖草在线观看 | 久久久99久久 | av中文字幕第一页 | 色偷偷97 | 久久免费看a级毛毛片 | 欧美日韩高清在线 | 日韩欧美精品免费 | 成人蜜桃 | 久久影院午夜论 | www激情com| 狠狠搞,com| 国产日韩欧美在线 | 五月激情综合婷婷 | 麻豆网站免费观看 | 九九色在线观看 | 五月天国产精品 | 中国黄色一级大片 | 81国产精品久久久久久久久久 | 国产原厂视频在线观看 | 亚洲精品乱码久久久久 | 成人一级片在线观看 | 精品久久久免费 | 91精品国产91热久久久做人人 | 日本激情中文字幕 | 国产成人区 | 日韩在线中文字幕 | 国产精品二区在线 | 91丨九色丨国产丨porny精品 | 国产精品一区二区三区久久 | 国产精品中文在线 | 亚洲精品久久久蜜桃直播 | 亚洲免费观看视频 | 狠狠地操| 最近最新中文字幕 | 婷婷夜夜 | 亚洲综合成人在线 | 欧美一区三区四区 | 免费日韩电影 | 久久免费黄色网址 | 亚洲蜜桃av | 2017狠狠干 | 天天爽夜夜爽精品视频婷婷 | 日本三级在线观看中文字 | 99久e精品热线免费 99国产精品久久久久久久久久 | 国产精品va在线观看入 | 91高清免费看 | 免费在线成人av | 草免费视频 | 中文字幕一区在线观看视频 | 四虎国产精品成人免费4hu | 97中文字幕| 中文字幕在线观看亚洲 | 欧美日韩网站 | 成人av一区二区在线观看 | 中文字幕高清免费日韩视频在线 | 中日韩免费视频 | 天天色.com| 干狠狠 | www.天天操.com | 国产成人中文字幕 | 午夜精品av | 9999精品 | 天天干天天做 | 免费网址你懂的 | 日韩精品久久久久久中文字幕8 | 全黄网站 | 国产精品久久久久永久免费 | av网址在线播放 | 激情伊人五月天 | 视频在线一区二区三区 | 99视频在线精品 | 国产小视频你懂的在线 | 18国产精品白浆在线观看免费 | 精品在线播放视频 | 成人免费视频a | 一区二区三区在线电影 | 中日韩免费视频 | 最新av网址在线 | 亚洲精品麻豆视频 | 91av在线视频免费观看 | 视频一区视频二区在线观看 | 久热久草| 男女免费av| 毛片网在线播放 | 激情图片久久 | 免费视频黄色 | 国产在线观看av | 日本激情视频中文字幕 | 久久夜视频 | 日本黄色免费观看 | 色综合久久88色综合天天 | 中文字幕资源在线观看 | 99re8这里有精品热视频免费 | 草久在线 | 又黄又刺激的视频 | 亚洲欧美国产精品久久久久 | 久久综合丁香 | 国产一区二区电影在线观看 | 91精品视频播放 | 国产黄色成人av | av免费看av | 国产在线观看h | 色婷婷久久一区二区 | 亚洲成a人片77777kkkk1在线观看 | 在线最新av| 天天射天天操天天色 | 亚洲午夜av | 亚洲最新视频在线播放 | 精品在线观看一区二区三区 | 中文字幕精品www乱入免费视频 | 久久神马影院 | 久久久国产精品麻豆 | 精品中文字幕在线观看 | 91av手机在线观看 | 日韩一区二区久久 | 成人黄大片 | 久久99影院| 一本—道久久a久久精品蜜桃 | 欧美网址在线观看 | 狠狠操狠狠 | 三级av免费观看 | 亚洲国产精品久久久久久 | 成人免费网站在线观看 | 日韩精品视频一二三 | 国产精品女主播一区二区三区 | 在线天堂中文www视软件 | 国产一区视频在线播放 | 欧美日韩在线播放一区 | 黄色a级片在线观看 | 在线播放日韩av | 精品99在线 | 国产免费不卡 | 日本黄色免费观看 | 天天干天天操av | 午夜视频色| 97精品在线视频 | 国产精品一区二区三区免费看 | av高清不卡 | 久久综合狠狠综合久久狠狠色综合 | 香蕉久久久久久久 | 99re中文字幕| 久久久久国产a免费观看rela | 日韩中文字幕在线不卡 | www.com操| 99视频在线免费观看 | 国产高清综合 | 久久尤物电影视频在线观看 | 欧美一级片免费 | 欧美日韩中文在线观看 | 免费三级av | 国产无区一区二区三麻豆 | 国产成人精品一区二区三区免费 | 亚洲 欧洲av | 国产精品va在线播放 | 国产一区福利在线 | 欧美日韩另类在线观看 | 成人国产精品免费观看 | 中文资源在线播放 | 婷婷伊人综合亚洲综合网 | 五月婷香蕉久色在线看 | 在线播放你懂 | 中文字幕在线乱 | 国产又粗又猛又黄视频 | 精品国产午夜 | 就要干b| 97人人澡人人爽人人模亚洲 | 亚洲欧美日本国产 | 摸bbb搡bbb搡bbbb | 91色视频| 亚洲无吗视频在线 | 国产无遮挡猛进猛出免费软件 | 亚洲高清视频一区二区三区 | h视频日本 | 成人黄色在线观看视频 | 一级性视频 | 亚洲精品国产高清 | 欧美精品在线观看 | 国产精品99久久久久久久久 | 日日夜夜狠狠操 | 综合网天天色 | 中文字幕一区二 | 婷婷色av| 91视频免费看片 | 97香蕉久久超级碰碰高清版 | 国产精品一区欧美 | 最新久久久 | 免费黄在线观看 | a在线视频v视频 | 最近中文字幕大全中文字幕免费 | 美女视频a美女大全免费下载蜜臀 | 欧美一区二区三区在线播放 | 99久久精品国产一区 | 狠狠干狠狠操 | 国产精品成人自产拍在线观看 | 日韩精品一区二区电影 | 精品国产乱码久久久久久1区2匹 | 中文字幕视频 | 亚洲精品大片www | 一本色道久久综合亚洲二区三区 | 17婷婷久久www | 国产精品自在线拍国产 | 天堂va在线观看 | 久久综合精品国产一区二区三区 | 久久不卡电影 | 国产在线中文 | 国产精品久久久久久999 | 男女视频91| 日韩视频专区 | 天天天天天操 | 中文字幕一区二区三区在线观看 | 波多野结衣在线视频一区 | 中文在线 | 日日操天天操夜夜操 | 久久午夜网| 日本公妇色中文字幕 | 精品女同一区二区三区在线观看 | 日韩av电影网站在线观看 | 久久久久久久18 | 午夜精品一二区 | 夜夜操天天操 | 最近免费中文字幕大全高清10 | 狠狠的操你 | 久久99久久久久 | 亚洲精品国偷拍自产在线观看蜜桃 | 久久久精品国产一区二区三区 | 久久三级视频 | 99视频网址 | 色婷婷综合视频在线观看 | 国产黄av | 亚洲五月激情 | 成人黄色毛片 | 四虎在线视频 | 99在线看| 黄色av影院 | 久久久污| 欧美一二三专区 | 亚洲国产成人久久综合 | 中文字幕 国产精品 | 岛国一区在线 | 热精品| 久草视频视频在线播放 | 最新av在线网址 | 欧美亚洲久久 | 中文字幕在线免费观看 | 久久人网 | 美女黄频在线观看 | 狠狠色丁香久久婷婷综 | 久久久久国产精品厨房 | 国产麻豆精品95视频 | 一本—道久久a久久精品蜜桃 | 亚洲国产影院 | 国产亚洲精品久久久久动 | 超碰97久久 | 日韩女同av | 日韩欧美在线免费观看 | av在线免费观看黄 | 欧美性生活小视频 | 天天躁天天躁天天躁婷 | 日韩在线观看网站 | 在线观看中文字幕视频 | 免费男女羞羞的视频网站中文字幕 | 久久久久久在线观看 | aaawww| 精品国产片 | 丝袜足交在线 | 日韩激情第一页 | 最近日本mv字幕免费观看 | 99久久精品费精品 | 久久久免费精品 | 中文字幕日韩高清 | 欧美激情视频在线免费观看 | 超碰在线人人艹 | 黄色网www | 开心激情久久 | 国产精品久久久久免费 | 四虎免费在线观看视频 | 欧美黑人性猛交 | 国产伦理久久精品久久久久_ | 天堂va在线高清一区 | 888av| 一级黄色在线视频 | 欧美日韩高清国产 | 欧美一级看片 | 久久97久久97精品免视看 | 精品欧美一区二区在线观看 | 美女一级毛片视频 | 九九热视频在线播放 | 玖玖在线观看视频 | 97精品视频在线 | 国产精品成人在线 | 国产手机在线视频 | 亚洲aⅴ免费在线观看 | 二区三区中文字幕 | 99精品视频在线 | 少妇精品久久久一区二区免费 | 成人小视频在线观看免费 | 国产一区精品在线观看 | 国产九九在线 | 91精品视频在线免费观看 | 精品在线观看免费 | 日韩一区二区三区在线观看 | 开心色婷婷 | 啪啪免费观看网站 | 免费黄a| 99精品亚洲 | 免费在线观看国产精品 | 欧美日韩国产精品一区二区 | 天天色图| 深夜免费福利 | 国产高清精 | 国产国产人免费人成免费视频 | 婷婷激情在线 | 69av免费视频 | 91完整版 | 国产黄色理论片 | 国产精品9999久久久久仙踪林 | 欧美最猛性xxxx | 欧美美女视频在线观看 | 久久国产a| 欧美日韩精品二区第二页 | 国产黄色视| 欧美精品亚洲精品日韩精品 | av一区二区在线观看中文字幕 | 国产裸体永久免费视频网站 | 亚洲一区二区三区在线看 | 国产精彩视频一区二区 | 激情五月播播久久久精品 | 伊人影院av | 成年人av在线播放 | 国产精品 中文字幕 亚洲 欧美 | 国产黄视频在线观看 | 亚洲黄色区 | 国产精品9999久久久久仙踪林 | 日韩午夜av| 成人宗合网 | 色综合色综合色综合 | 国产96av| 四虎成人精品永久免费av | 91麻豆精品国产午夜天堂 | 欧美日韩一区二区三区不卡 | 精品99在线视频 | 色夜视频 | 日韩免费视频网站 | 天天干天天天 | 国产精品视频地址 | 国产精品中文字幕在线 | 亚洲午夜av久久乱码 | 99精品在线视频观看 | 欧美色婷婷 | 亚洲精品国产自产拍在线观看 | 亚洲欧洲精品一区二区精品久久久 | 91人人爽久久涩噜噜噜 | 日日夜夜国产 | 又黄又爽又无遮挡免费的网站 | 国产精品12345| 91精品国产乱码久久 | 91丨九色丨国产在线观看 | 久久免费视频8 | 日韩在线视频免费播放 | 国产男女无遮挡猛进猛出在线观看 | 中文字幕电影在线 | 99热国内精品 | 免费看网站在线 | 丁香5月婷婷久久 | 国产黄a三级三级 | 久久嗨| 夜夜婷婷 | 黄色av免费看 | 久久久综合九色合综国产精品 | 久久久久久免费视频 | 国产在线播放一区 | 国产日韩精品在线观看 | 国产小视频你懂的在线 | 狠狠色丁香婷婷综合久小说久 | 91免费的视频在线播放 | 黄色av一级片 | 夜夜夜精品 | a午夜电影| 欧美精品久久久久久久免费 | 1024手机基地在线观看 | 成人h在线| www.色五月.com | 99精品在线免费 | 国产精品久久麻豆 | 精品国产亚洲一区二区麻豆 | avwww在线观看 | 亚洲色图 校园春色 | 天天射天天爽 | 国产在线色视频 | 五月婷婷综合网 | 国产精品剧情 | 夜夜操天天摸 | 欧美性脚交| 婷婷丁香自拍 | 在线观看免费av网 | 精品一区二区免费在线观看 | 特片网久久| 国产高清av在线播放 | 国产美女精品人人做人人爽 | 欧美日韩在线免费观看 | 性色av一区二区三区在线观看 | 色综合欧洲 | 色射爱| aaa亚洲精品一二三区 | 日韩在线资源 | 黄色大片免费网站 | 天天色天天操综合 | 日韩a在线| 成人免费观看视频网站 | 国产精品免费麻豆入口 | 国产资源在线视频 | 日韩欧美在线视频一区二区 | 国产精品毛片一区视频播 | 国产精品久久久久久久久久三级 | 久久综合免费 | 国产看片 色 | 蜜桃视频成人在线观看 | 久久全国免费视频 | 天天爱天天操天天干 | 一级欧美一级日韩 | 黄色免费在线视频 | 久久国产精品久久久久 | 激情小说网站亚洲综合网 | 亚洲国产欧美在线人成大黄瓜 | 中文字幕在线观看网 | 久久免费观看视频 | 国产一区二区三精品久久久无广告 | 在线观看久 | 91高清一区 | 天天在线操 | 久久久综合香蕉尹人综合网 | 人人cao| 国产精品久久久久亚洲影视 | 绯色av一区 | 久久99精品热在线观看 | 中国一级片视频 | 久精品一区 | 日韩中文字幕91 | 欧美国产日韩一区二区三区 | 99精品国产福利在线观看免费 | 久草在线最新视频 | 国产精品99久久久久久武松影视 | 精品亚洲二区 | 正在播放国产一区 | av中文字幕网站 | 国产精品一区二区三区观看 | 久久男女视频 | 欧美日韩视频在线观看一区二区 | 欧美三级在线播放 | 久久成人精品视频 | 波多野结衣理论片 | 国产福利精品一区二区 | 国产精品第三页 | 日韩精品一区二区三区视频播放 | 国产精品爽爽爽 | 激情五月***国产精品 | 毛片网站在线观看 | www.狠狠色 | 日韩网站在线免费观看 | 中文字幕在线免费看 | 国产精品久久婷婷六月丁香 | 精品久久久国产 | 国内精品久久久久久久久久久 | 欧美一二三专区 | 丝袜+亚洲+另类+欧美+变态 | 成人99免费视频 | 日韩视频一区二区在线观看 | av观看免费在线 | 91精彩视频在线观看 | 在线观看涩涩 | 国产精品久久片 | 综合色久| 免费精品国产va自在自线 | 欧美另类xxxx | 久久久久久久久久久久久久av | 91视频免费播放 | 成人久久精品视频 | 色综合久久88色综合天天 | 中文av网| 久久免费久久 | 久久亚洲私人国产精品 | 999久久久 | 久草亚洲视频 | 99视频 | 久久国产片| 日韩系列在线 | 国模一二三区 | 日韩美在线观看 | 蜜臀久久99精品久久久久久网站 | 久久艹影院 | 精品欧美在线视频 | 五月天婷亚洲天综合网鲁鲁鲁 | 亚洲免费永久精品国产 | 成人精品影视 | 日韩久久视频 | avove黑丝| 婷婷六月天在线 | 最新日韩中文字幕 | 亚洲精品午夜久久久久久久 | 免费看一级一片 | 特级西西人体444是什么意思 | 色在线亚洲 | 免费电影播放 | 久久精品国产v日韩v亚洲 | 久久五月情影视 | 黄色毛片在线看 | 国产精品久久久久永久免费 | 亚洲婷婷综合色高清在线 | 国产日产亚洲精华av | 97超视频在线观看 | 91精品视频网站 | 丁香婷婷激情五月 | 久久丁香 | 久久精品视频在线 | 亚洲国产精品成人精品 | 婷婷婷国产在线视频 | 不卡的av电影在线观看 | 国产中文字幕久久 | 国产精品婷婷 | 天天综合成人 | 亚洲区色 | 国产精品福利在线播放 | 久久影院亚洲 | 97精品在线| 美女视频网站久久 | 久久精品二区 | 国内精品久久久久久久影视简单 | 日韩视频一 | 成年一级片 | 久久av一区二区三区亚洲 | 在线免费色视频 | 国产一级片免费视频 | 成人免费电影 | 亚州av成人 | 久久资源在线 | 超碰在线天天 | 久久99精品久久久久婷婷 | 激情在线网址 | 超碰在线最新地址 | 国产精品免费久久久久 | 国产精品一区二区久久精品爱涩 | av电影中文 | 91精品国自产拍天天拍 | 91黄色在线看 | 网站免费黄| 国产精品第72页 | 五月天六月丁香 | 亚州精品国产 | 黄色三级免费片 | 成人av亚洲| 丁香激情综合久久伊人久久 | 狠狠狠狠狠狠狠狠 | 九九在线视频免费观看 | 国产123区在线观看 国产精品麻豆91 | 色五月激情五月 | 国产色视频123区 | 国产一级片网站 | 99在线国产| 成 人 黄 色 免费播放 | 狠狠躁夜夜躁人人爽视频 | 精品久久亚洲 | 在线 欧美 日韩 | 丁香5月婷婷久久 | 久草视频在线免费播放 | 欧美,日韩 | 久久这里只有精品9 | 日本狠狠色 | 日韩黄色影院 | 成人永久免费 | 激情视频二区 | 国产免费观看久久黄 | 五月婷在线观看 | 西西444www大胆高清图片 | 91xav| 美女视频久久久 | 欧美日韩高清不卡 | 日韩激情影院 | 成人国产网站 | 热久久99这里有精品 | 国产高清视频免费观看 | 久久精品伊人 | 夜夜骑首页 | 91免费在线播放 | 日本午夜在线观看 | 国产黄a三级三级 | 国产精品精品久久久久久 | 日韩av不卡在线观看 | 亚洲成人免费在线观看 | 麻豆免费视频网站 | 久热免费在线 | 国产一级片网站 | av日韩不卡 | 国产精品白丝jk白祙 | 青青河边草免费观看完整版高清 | 伊人五月天婷婷 | 在线观看免费视频你懂的 | 天天操狠狠操夜夜操 | 成人黄色影片在线 | 国产在线一卡 | 区一区二区三在线观看 | 国产精品久久久久aaaa九色 | 婷婷5月激情5月 | 久久情侣偷拍 | 免费视频久久久久久久 | 日韩精品一区二区免费 | 黄网站www| 九九九在线观看视频 | 欧美精品久久久久久久久老牛影院 | 中文字幕资源站 | 免费男女羞羞的视频网站中文字幕 | 二区三区在线视频 | 免费亚洲视频 | 91亚洲国产成人久久精品网站 | 超碰在线97免费 | 在线亚洲精品 | 欧美成人区| 久久综合中文色婷婷 | 国产日产精品久久久久快鸭 | 国产精品女视频 | 免费看色的网站 | 亚洲干 | 午夜三级福利 | 久久免费视频网 | 天天干,天天射,天天操,天天摸 | 亚洲四虎影院 | 精品视频区 | 韩国三级在线一区 | 亚洲伊人网在线观看 | 91精品国产99久久久久 | 色综合久久88色综合天天6 | 国产日韩精品在线 | 色婷婷电影 | 在线免费观看黄 | 久久国产热 | 中文字幕亚洲欧美日韩2019 | 色资源在线观看 | 日韩二区在线 | 色先锋av资源中文字幕 | 激情在线免费视频 | 国模视频一区二区三区 | 综合中文字幕 | 久久久亚洲国产精品麻豆综合天堂 | 少妇性aaaaaaaaa视频 | 一级黄色大片 | 日b黄色片 | 又黄又爽的免费高潮视频 | 欧美日韩国产欧美 | 视频三区在线 | 波多野结衣久久资源 | 嫩模bbw搡bbbb搡bbbb| 欧美激情精品久久久久久变态 | 99视频国产精品免费观看 | 丰满少妇在线观看资源站 | 天天综合网在线观看 | 久久久免费国产 | 久久久久国产精品免费免费搜索 | 操高跟美女 | 精品自拍av | 亚洲国产av精品毛片鲁大师 | 在线 影视 一区 | 青青久草在线视频 | 伊人黄色网 | 九九综合在线 | 亚洲精品视频国产 | 911亚洲精品第一 | 五月激情六月丁香 | 丁香五月亚洲综合在线 | 国内精品久久久久久久影视麻豆 | 久久久久久国产精品 | 成人va视频| 五月天视频网 | 亚洲精品网址在线观看 | 久久少妇免费视频 | 91原创在线观看 | 精品视频亚洲 | 人人爽影院 | 91丨九色丨蝌蚪丨对白 | 91成人精品国产刺激国语对白 | 天堂av免费看 | 四虎视频| 黄网在线免费观看 | 国产91丝袜在线播放动漫 | 91看片看淫黄大片 | 国产精品一区二区av | 成人一级电影在线观看 | 99久久婷婷国产综合亚洲 | 精品亚洲成人 | 日韩性网站 | 91激情视频在线观看 | 91av播放| 亚洲精品国产拍在线 | 福利电影一区二区 | 成人一区二区在线观看 | 亚洲dvd | 最近中文字幕在线中文高清版 | 黄色特级片| 99精品国产aⅴ| 久久久国产毛片 | 日本中文字幕系列 | 韩国一区二区av | 亚洲免费专区 | 欧美国产日韩一区 | 中文字幕在线资源 | 欧美成人在线免费 | 国产午夜精品福利视频 | 久久精品国产免费观看 | 日韩av在线不卡 | 九九免费精品视频在线观看 | 色97在线 | 成人在线黄色 | 91精品少妇偷拍99 | 亚洲精品美女在线 | 美女国产在线 | 在线观看国产区 | 亚洲成人av片在线观看 | 日本黄色大片免费 | 亚洲国产精久久久久久久 | 99久久久国产精品 | 97视频成人| 久久er99热精品一区二区 | 久久久久久久毛片 | 国产亚洲精品久久 | 色资源二区在线视频 | 久草五月 | 三级午夜片 | 丁香婷婷综合激情五月色 | 国产专区精品视频 | 久久蜜臀一区二区三区av | 天天搞夜夜骑 | 国产精品一区二区三区在线免费观看 | 亚洲精品视频网址 | 91看成人| 国产精品高潮呻吟久久久久 | 午夜精品一区二区三区免费 | 中文字幕中文字幕在线一区 | 在线观看视频一区二区 | 99视频在线精品国自产拍免费观看 | 国产在线一卡 | 精品一区二区免费在线观看 | 国产亚洲精品综合一区91 | 国产精品久久久久久电影 | www日韩在线观看 | 国产亚洲婷婷免费 | 懂色av懂色av粉嫩av分享吧 | 91黄色在线看 | 亚洲蜜桃在线 | 在线观看视频你懂的 | 国产一区观看 | 免费看污在线观看 | 麻豆视频免费播放 | 久久在线精品 | 国产经典三级 | 美女网站在线 | 高清久久久久久 | 亚洲精品小视频在线观看 | 亚洲欧洲精品视频 | 国产高清视频免费在线观看 | 麻豆激情电影 | 天天插狠狠插 | 91桃色在线播放 | 91插插视频| 国产录像在线观看 | 免费看黄网站在线 | 久久精品成人热国产成 | 久在线| 欧美午夜精品久久久久久浪潮 | 国产精品久久一区二区无卡 | 成人三级黄色 | 麻豆果冻剧传媒在线播放 | 日韩一区在线播放 | 中文字幕超清在线免费 | 免费av片在线 | 日韩二区在线 | 中国老女人日b | 国产亚洲综合精品 | 亚洲精品视频大全 | 亚洲国产色一区 | 国产美女无遮挡永久免费 | 色噜噜狠狠色综合中国 | 精品国产理论片 | 在线一二区 | 欧美俄罗斯性视频 | 美国三级黄色大片 | 精品久久久久亚洲 | 久久av在线| 激情六月婷婷久久 | 色综合久久99 | 99久久精|