整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          通告ImageMagick再爆核心漏洞 站長小心

          前所有版本的GraphicsMagick和ImageMagick都支持打開文件,當文件名的第一個字符為“|”,則文件名會被傳遞給shell程序執行,導致(可能遠程)代碼執行。

          文件打開操作位于源代碼文件blob.c中的OpenBlob函數,不同于CVE-2016-3714的是,此漏洞存在于軟件處理的核心代碼中。

          綠盟科技威脅預警級別

          什么是ImageMagick?

          ImageMagick軟件是用C語言編寫的,可用來顯示、轉換以及編輯圖形,支持超過200中圖像文件格式,并且可以跨平臺運行。

          ImageMagick軟件被許多編程語言所支持,包括Perl,C++,PHP,Python和Ruby等,并被部署在數以百萬計的網站,博客,社交媒體平臺和流行的內容管理系統(CMS)。

          什么是GraphicsMagick?

          GraphicsMagick號稱圖像處理領域的瑞士軍刀。 短小精悍的代碼卻提供了一個魯棒、高效的工具和庫集合,來處理圖像的讀取、寫入和操作,支持超過88種圖像格式,包括重要的DPX、GIF、JPEG、JPEG-2000、PNG、PDF、PNM和TIFF,可以在絕大多數的平臺上使用,Linux、Mac、Windows等,GaphicsMagick不僅支持命令行的模式,同時也支持C、C++、Perl、PHP、Tcl、 Ruby等的調用,是從ImageMagick5.5.2 分支出來的。

          影響的版本

          • 目前所知到的所有版本

          不受影響的版本

          • 暫無

          漏洞影響

          可以通過如下方法測試系統是否受影響:

          命令行測試,創建hello.txt文件

          % rm -f hello.txt
          % convert '|echo Hello > hello.txt;' :
          % ls hello.txt
          hello.txt

          SVG文件

          <?xml version="1.0" standalone="no"?>
          <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
           "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
          <svg width="4in" height="3in" version="1.1"
           xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
           <desc>Illustrates how a shell command may be embedded in a SVG.</desc>
           <image x="200" y="200" width="100px" height="100px"
           xlink:href="|echo Hello > hello.txt; cat /usr/lib/firefox/browser/icons/mozicon128.png">
           <title>My image</title>
           </image>
          </svg>

          MVG文件

          push graphic-context
          viewbox 0 0 640 480
          image copy 200,200 100,100 "|echo Hello > hello.txt; cat /usr/lib/firefox/browser/icons/mozicon128.png"
          pop graphic-context

          緩解方法

          • 編譯過程中GraphicsMagick禁用HAVE_POPEN宏和ImageMagick禁用MAGICKCORE_HAVE_POPEN宏。

          • 在配置文件中增加如下內容:

            <policy domain="path" rights="none" pattern="|*" />

          • 在源代碼中增加如下項:

          GraphicsMagick代碼magick/blob.c中增加#undef HAVE_POPEN。

          ImageMagick代碼MagickCore/blob.c中增加#undef MAGICKCORE_HAVE_POPEN。

          修復方案:

          請關注官方網站,及時升級到最新版本!

          綠盟科技安全團隊會持續關注事態變化,后續會發布詳細的分析報告、產品升級及解決方案,請廣大用戶隨時關注。

          綠盟科技威脅事件定級標準

          級別

          描述

          影響范圍比較廣,危害嚴重,利用難度較低,7*24小時內部應急跟蹤,24小時內完成技術分析、產品升級和防護方案。

          影響范圍可控,危害程度可控,利用難度較高,7*8小時內部應急跟蹤,72小時內完成技術分析、產品升級和防護方案。

          影響較小,危害程度較小。

          聲明

          本安全公告僅用來描述可能存在的安全問題,綠盟科技不為此安全公告提供任何保證或承諾。


          由于傳播、利用此安全公告所提供的信息而造成的任何直接或者間接的后果及損失,均由使用者本人負責,綠盟科技以及安全公告作者不為此承擔任何責任。


          綠盟科技擁有對此安全公告的修改和解釋權。如欲轉載或傳播此安全公告,必須保證此安全公告的完整性,包括版權聲明等全部內容。


          未經綠盟科技允許,不得任意修改或者增減此安全公告內容,不得以任何方式將其用于商業目的。

          關于綠盟科技

          綠盟科技(NSFOCUS Co., Ltd.)是中國網絡安全領域的領導企業,致力于網絡和系統安全問題的研究、高端網絡安全產品的研發、銷售與網絡安全服務,在入侵檢測/保護、遠程評估、 DDoS攻擊防護等方面提供具有國際競爭能力的先進產品,是國內最具安全服務經驗的專業公司。

          有關綠盟科技的詳情請參見:

          http://www.nsfocus.com

          請點擊屏幕右上方“…”

          關注綠盟科技公眾號

          NSFOCUS-weixin

          ↑↑↑長按二維碼,下載綠盟云APP

          Vue 3.x 的Pre-Alpha 版本。后面應該還會有 Alpha、Beta 等版本,預計至少要等到 2020 年第一季度才有可能發布 3.0 正式版;
          所以應該趁還沒出來加緊打好 Vue2.x 的基礎;
          Vue基本用法很容易上手,但是有很多優化的寫法你就不一定知道了,本文從列舉了 36 個 vue 開發技巧;
          后續 Vue 3.x 出來后持續更新.

          1.require.context()

          1.場景:如頁面需要導入多個組件,原始寫法:

          import titleCom from '@/components/home/titleCom'
          import bannerCom from '@/components/home/bannerCom'
          import cellCom from '@/components/home/cellCom'
          components:{titleCom,bannerCom,cellCom}
          復制代碼

          2.這樣就寫了大量重復的代碼,利用 require.context 可以寫成

          const path = require('path')
          const files = require.context('@/components/home', false, /\.vue$/)
          const modules = {}
          files.keys().forEach(key => {
            const name = path.basename(key, '.vue')
            modules[name] = files(key).default || files(key)
          })
          components:modules
          復制代碼

          這樣不管頁面引入多少組件,都可以使用這個方法

          3.API 方法

          實際上是 webpack 的方法,vue 工程一般基于 webpack,所以可以使用
          require.context(directory,useSubdirectories,regExp)
          接收三個參數:
          directory:說明需要檢索的目錄
          useSubdirectories:是否檢索子目錄
          regExp: 匹配文件的正則表達式,一般是文件名
          復制代碼

          2.watch

          2.1 常用用法

          1.場景:表格初始進來需要調查詢接口 getList(),然后input 改變會重新查詢

          created(){
            this.getList()
          },
          watch: {
            inpVal(){
              this.getList()
            }
          }
          復制代碼

          2.2 立即執行

          2.可以直接利用 watch 的immediate和handler屬性簡寫

          watch: {
            inpVal:{
              handler: 'getList',
                immediate: true
            }
          }
          復制代碼

          2.3 深度監聽

          3.watch 的 deep 屬性,深度監聽,也就是監聽復雜數據類型

          watch:{
            inpValObj:{
              handler(newVal,oldVal){
                console.log(newVal)
                console.log(oldVal)
              },
              deep:true
            }
          }
          復制代碼

          此時發現oldVal和 newVal 值一樣; 因為它們索引同一個對象/數組,Vue 不會保留修改之前值的副本; 所以深度監聽雖然可以監聽到對象的變化,但是無法監聽到具體對象里面那個屬性的變化

          3. 14種組件通訊

          3.1 props

          這個應該非常屬性,就是父傳子的屬性; props 值可以是一個數組或對象;

          // 數組:不建議使用
          props:[]
          
          // 對象
          props:{
           inpVal:{
            type:Number, //傳入值限定類型
            // type 值可為String,Number,Boolean,Array,Object,Date,Function,Symbol
            // type 還可以是一個自定義的構造函數,并且通過 instanceof 來進行檢查確認
            required: true, //是否必傳
            default:200,  //默認值,對象或數組默認值必須從一個工廠函數獲取如 default:()=>[]
            validator:(value) {
              // 這個值必須匹配下列字符串中的一個
              return ['success', 'warning', 'danger'].indexOf(value) !== -1
            }
           }
          }
          復制代碼

          3.2 $emit

          這個也應該非常常見,觸發子組件觸發父組件給自己綁定的事件,其實就是子傳父的方法

          // 父組件
          <home @title="title">
          // 子組件
          this.$emit('title',[{title:'這是title'}])
          復制代碼

          3.3 vuex

          1.這個也是很常用的,vuex 是一個狀態管理器 2.是一個獨立的插件,適合數據共享多的項目里面,因為如果只是簡單的通訊,使用起來會比較重 3.API

          state:定義存貯數據的倉庫 ,可通過this.$store.state 或mapState訪問
          getter:獲取 store 值,可認為是 store 的計算屬性,可通過this.$store.getter 或
                 mapGetters訪問
          mutation:同步改變 store 值,為什么會設計成同步,因為mutation是直接改變 store 值,
                   vue 對操作進行了記錄,如果是異步無法追蹤改變.可通過mapMutations調用
          action:異步調用函數執行mutation,進而改變 store 值,可通過 this.$dispatch或mapActions
                 訪問
          modules:模塊,如果狀態過多,可以拆分成模塊,最后在入口通過...解構引入
          復制代碼

          3.4attrs和attrs和attrs和listeners

          2.4.0 新增 這兩個是不常用屬性,但是高級用法很常見; 1.attrs場景:如果父傳子有很多值,那么在子組件需要定義多個props解決:attrs 場景:如果父傳子有很多值,那么在子組件需要定義多個 props 解決:attrs場景:如果父傳子有很多值,那么在子組件需要定義多個props解決:attrs獲取子傳父中未在 props 定義的值

          // 父組件
          <home title="這是標題" width="80" height="80" imgUrl="imgUrl"/>
          
          // 子組件
          mounted() {
            console.log(this.$attrs) //{title: "這是標題", width: "80", height: "80", imgUrl: "imgUrl"}
          },
          復制代碼

          相對應的如果子組件定義了 props,打印的值就是剔除定義的屬性

          props: {
            width: {
              type: String,
              default: ''
            }
          },
          mounted() {
            console.log(this.$attrs) //{title: "這是標題", height: "80", imgUrl: "imgUrl"}
          },
          復制代碼

          2.listeners場景:子組件需要調用父組件的方法解決:父組件的方法可以通過v?on="listeners 場景:子組件需要調用父組件的方法 解決:父組件的方法可以通過 v-on="listeners場景:子組件需要調用父組件的方法解決:父組件的方法可以通過v?on="listeners" 傳入內部組件——在創建更高層次的組件時非常有用

          // 父組件
          <home @change="change"/>
          
          // 子組件
          mounted() {
            console.log(this.$listeners) //即可拿到 change 事件
          }
          復制代碼

          如果是孫組件要訪問父組件的屬性和調用方法,直接一級一級傳下去就可以

          3.inheritAttrs

          // 父組件
          <home title="這是標題" width="80" height="80" imgUrl="imgUrl"/>
          
          // 子組件
          mounted() {
            console.log(this.$attrs) //{title: "這是標題", width: "80", height: "80", imgUrl: "imgUrl"}
          },
          
          inheritAttrs默認值為true,true的意思是將父組件中除了props外的屬性添加到子組件的根節點上(說明,即使設置為true,子組件仍然可以通過$attr獲取到props意外的屬性)
          將inheritAttrs:false后,屬性就不會顯示在根節點上了
          復制代碼

          3.5 provide和inject

          2.2.0 新增 描述: provide 和 inject 主要為高階插件/組件庫提供用例。并不推薦直接用于應用程序代碼中; 并且這對選項需要一起使用; 以允許一個祖先組件向其所有子孫后代注入一個依賴,不論組件層次有多深,并在起上下游關系成立的時間里始終生效。

          //父組件:
          provide: { //provide 是一個對象,提供一個屬性或方法
            foo: '這是 foo',
            fooMethod:()=>{
              console.log('父組件 fooMethod 被調用')
            }
          },
          
          // 子或者孫子組件
          inject: ['foo','fooMethod'], //數組或者對象,注入到子組件
          mounted() {
            this.fooMethod()
            console.log(this.foo)
          }
          //在父組件下面所有的子組件都可以利用inject
          復制代碼

          provide 和 inject 綁定并不是可響應的。這是官方刻意為之的。 然而,如果你傳入了一個可監聽的對象,那么其對象的屬性還是可響應的,對象是因為是引用類型

          //父組件:
          provide: { 
            foo: '這是 foo'
          },
          mounted(){
            this.foo='這是新的 foo'
          }
          
          // 子或者孫子組件
          inject: ['foo'], 
          mounted() {
            console.log(this.foo) //子組件打印的還是'這是 foo'
          }
          復制代碼

          provide和inject響應方法

          // 父組件
          provide() {
              return {
                staticValue: this.staticValue, // 直接返回值,不可響應
                staticObject: this.staticObject, // 返回一個對象,可響應
                getReactiveValue: () => this.staticValue // 返回一個對象的函數,可響應
              }
            },
            
          // 子組件
          inject: ["staticValue", "getReactiveValue", "staticObject"],
          computed: {
              reactiveValue() {
                return this.getReactiveValue(); // 返回注入的對象函數,通過計算屬性來監聽值的變化
              },
            },
          復制代碼

          所以provide返回一個對象或者函數是可以響應的, 因為對象和函數是引用類型, 實際上改變也不是vue做的,而是JS的引用類型特性

          3.6parent和parent和parent和children

          parent:父實例parent:父實例parent:父實例children:子實例

          //父組件
          mounted(){
            console.log(this.$children) 
            //可以拿到 一級子組件的屬性和方法
            //所以就可以直接改變 data,或者調用 methods 方法
          }
          
          //子組件
          mounted(){
            console.log(this.$parent) //可以拿到 parent 的屬性和方法
          }
          復制代碼

          children和children和children和parent 并不保證順序,也不是響應式的 只能拿到一級父組件和子組件

          3.7 $refs

          // 父組件
          <home ref="home"/>
          
          mounted(){
            console.log(this.$refs.home) //即可拿到子組件的實例,就可以直接操作 data 和 methods
          }
          復制代碼

          3.8 $root

          // 父組件
          mounted(){
            console.log(this.$root) //獲取根實例,最后所有組件都是掛載到根實例上
            console.log(this.$root.$children[0]) //獲取根實例的一級子組件
            console.log(this.$root.$children[0].$children[0]) //獲取根實例的二級子組件
          }
          復制代碼

          3.9 .sync

          在 vue@1.x 的時候曾作為雙向綁定功能存在,即子組件可以修改父組件中的值; 在 vue@2.0 的由于違背單項數據流的設計被干掉了; 在 vue@2.3.0+ 以上版本又重新引入了這個 .sync 修飾符;

          // 父組件
          <home :title.sync="title" />
          //編譯時會被擴展為
          <home :title="title"  @update:title="val => title = val"/>
          
          // 子組件
          // 所以子組件可以通過$emit 觸發 update 方法改變
          mounted(){
            this.$emit("update:title", '這是新的title')
          }
          復制代碼

          3.10 v-slot

          2.6.0 新增 1.slot,slot-cope,scope 在 2.6.0 中都被廢棄,但未被移除 2.作用就是將父組件的 template 傳入子組件 3.插槽分類: A.匿名插槽(也叫默認插槽): 沒有命名,有且只有一個;

          // 父組件
          <todo-list> 
              <template v-slot:default>
                 任意內容
                 <p>我是匿名插槽 </p>
              </template>
          </todo-list> 
          
          // 子組件
          <slot>我是默認值</slot>
          //v-slot:default寫上感覺和具名寫法比較統一,容易理解,也可以不用寫
          復制代碼

          B.具名插槽: 相對匿名插槽組件slot標簽帶name命名的;

          // 父組件
          <todo-list> 
              <template v-slot:todo>
                 任意內容
                 <p>我是匿名插槽 </p>
              </template>
          </todo-list> 
          
          //子組件
          <slot name="todo">我是默認值</slot>
          復制代碼

          C.作用域插槽: 子組件內數據可以被父頁面拿到(解決了數據只能從父頁面傳遞給子組件)

          // 父組件
          <todo-list>
           <template v-slot:todo="slotProps" >
             {{slotProps.user.firstName}}
           </template> 
          </todo-list> 
          //slotProps 可以隨意命名
          //slotProps 接取的是子組件標簽slot上屬性數據的集合所有v-bind:user="user"
          
          // 子組件
          <slot name="todo" :user="user" :test="test">
              {{ user.lastName }}
           </slot> 
          data() {
              return {
                user:{
                  lastName:"Zhang",
                  firstName:"yue"
                },
                test:[1,2,3,4]
              }
            },
          // {{ user.lastName }}是默認數據  v-slot:todo 當父頁面沒有(="slotProps")
          復制代碼

          3.11 EventBus

          1.就是聲明一個全局Vue實例變量 EventBus , 把所有的通信數據,事件監聽都存儲到這個變量上; 2.類似于 Vuex。但這種方式只適用于極小的項目 3.原理就是利用on和on和on和emit 并實例化一個全局 vue 實現數據共享

          // 在 main.js
          Vue.prototype.$eventBus=new Vue()
          
          // 傳值組件
          this.$eventBus.$emit('eventTarget','這是eventTarget傳過來的值')
          
          // 接收組件
          this.$eventBus.$on("eventTarget",v=>{
            console.log('eventTarget',v);//這是eventTarget傳過來的值
          })
          復制代碼

          4.可以實現平級,嵌套組件傳值,但是對應的事件名eventTarget必須是全局唯一的

          3.12 broadcast和dispatch

          vue 1.x 有這兩個方法,事件廣播和派發,但是 vue 2.x 刪除了 下面是對兩個方法進行的封裝

          function broadcast(componentName, eventName, params) {
            this.$children.forEach(child => {
              var name = child.$options.componentName;
          
              if (name === componentName) {
                child.$emit.apply(child, [eventName].concat(params));
              } else {
                broadcast.apply(child, [componentName, eventName].concat(params));
              }
            });
          }
          export default {
            methods: {
              dispatch(componentName, eventName, params) {
                var parent = this.$parent;
                var name = parent.$options.componentName;
                while (parent && (!name || name !== componentName)) {
                  parent = parent.$parent;
          
                  if (parent) {
                    name = parent.$options.componentName;
                  }
                }
                if (parent) {
                  parent.$emit.apply(parent, [eventName].concat(params));
                }
              },
              broadcast(componentName, eventName, params) {
                broadcast.call(this, componentName, eventName, params);
              }
            }
          }
          復制代碼

          3.13 路由傳參

          1.方案一

          // 路由定義
          {
            path: '/describe/:id',
            name: 'Describe',
            component: Describe
          }
          // 頁面傳參
          this.$router.push({
            path: `/describe/${id}`,
          })
          // 頁面獲取
          this.$route.params.id
          復制代碼

          2.方案二

          // 路由定義
          {
            path: '/describe',
            name: 'Describe',
            component: Describe
          }
          // 頁面傳參
          this.$router.push({
            name: 'Describe',
            params: {
              id: id
            }
          })
          // 頁面獲取
          this.$route.params.id
          復制代碼

          3.方案三

          // 路由定義
          {
            path: '/describe',
            name: 'Describe',
            component: Describe
          }
          // 頁面傳參
          this.$router.push({
            path: '/describe',
              query: {
                id: id
            `}
          )
          // 頁面獲取
          this.$route.query.id
          復制代碼

          4.三種方案對比 方案二參數不會拼接在路由后面,頁面刷新參數會丟失 方案一和三參數拼接在后面,丑,而且暴露了信息

          3.14 Vue.observable

          2.6.0 新增 用法:讓一個對象可響應。Vue 內部會用它來處理 data 函數返回的對象; 返回的對象可以直接用于渲染函數和計算屬性內,并且會在發生改變時觸發相應的更新; 也可以作為最小化的跨組件狀態存儲器,用于簡單的場景。 通訊原理實質上是利用Vue.observable實現一個簡易的 vuex

          // 文件路徑 - /store/store.js
          import Vue from 'vue'
          
          export const store = Vue.observable({ count: 0 })
          export const mutations = {
            setCount (count) {
              store.count = count
            }
          }
          
          //使用
          <template>
              <div>
                  <label for="bookNum">數 量</label>
                      <button @click="setCount(count+1)">+</button>
                      <span>{{count}}</span>
                      <button @click="setCount(count-1)">-</button>
              </div>
          </template>
          
          <script>
          import { store, mutations } from '../store/store' // Vue2.6新增API Observable
          
          export default {
            name: 'Add',
            computed: {
              count () {
                return store.count
              }
            },
            methods: {
              setCount: mutations.setCount
            }
          }
          </script>
          復制代碼

          4.render 函數

          1.場景:有些代碼在 template 里面寫會重復很多,所以這個時候 render 函數就有作用啦

          // 根據 props 生成標簽
          // 初級
          <template>
            <div>
              <div v-if="level === 1"> <slot></slot> </div>
              <p v-else-if="level === 2"> <slot></slot> </p>
              <h1 v-else-if="level === 3"> <slot></slot> </h1>
              <h2 v-else-if="level === 4"> <slot></slot> </h2>
              <strong v-else-if="level === 5"> <slot></slot> </stong>
              <textarea v-else-if="level === 6"> <slot></slot> </textarea>
            </div>
          </template>
          
          // 優化版,利用 render 函數減小了代碼重復率
          <template>
            <div>
              <child :level="level">Hello world!</child>
            </div>
          </template>
          
          <script type='text/javascript'>
            import Vue from 'vue'
            Vue.component('child', {
              render(h) {
                const tag = ['div', 'p', 'strong', 'h1', 'h2', 'textarea'][this.level-1]
                return h(tag, this.$slots.default)
              },
              props: {
                level: {  type: Number,  required: true  } 
              }
            })   
            export default {
              name: 'hehe',
              data() { return { level: 3 } }
            }
          </script>
          
          復制代碼

          2.render 和 template 的對比 前者適合復雜邏輯,后者適合邏輯簡單; 后者屬于聲明是渲染,前者屬于自定Render函數; 前者的性能較高,后者性能較低。

          5.異步組件

          場景:項目過大就會導致加載緩慢,所以異步組件實現按需加載就是必須要做的事啦 1.異步注冊組件 3種方法

          // 工廠函數執行 resolve 回調
          Vue.component('async-webpack-example', function (resolve) {
            // 這個特殊的 `require` 語法將會告訴 webpack
            // 自動將你的構建代碼切割成多個包, 這些包
            // 會通過 Ajax 請求加載
            require(['./my-async-component'], resolve)
          })
          
          // 工廠函數返回 Promise
          Vue.component(
            'async-webpack-example',
            // 這個 `import` 函數會返回一個 `Promise` 對象。
            () => import('./my-async-component')
          )
          
          // 工廠函數返回一個配置化組件對象
          const AsyncComponent = () => ({
            // 需要加載的組件 (應該是一個 `Promise` 對象)
            component: import('./MyComponent.vue'),
            // 異步組件加載時使用的組件
            loading: LoadingComponent,
            // 加載失敗時使用的組件
            error: ErrorComponent,
            // 展示加載時組件的延時時間。默認值是 200 (毫秒)
            delay: 200,
            // 如果提供了超時時間且組件加載也超時了,
            // 則使用加載失敗時使用的組件。默認值是:`Infinity`
            timeout: 3000
          })
          復制代碼

          異步組件的渲染本質上其實就是執行2次或者2次以上的渲染, 先把當前組件渲染為注釋節點, 當組件加載成功后, 通過 forceRender 執行重新渲染?;蛘呤卿秩緸樽⑨尮濣c, 然后再渲染為loading節點, 在渲染為請求完成的組件

          2.路由的按需加載

          webpack< 2.4 時
          {
            path:'/',
            name:'home',
            components:resolve=>require(['@/components/home'],resolve)
          }
          
          webpack> 2.4 時
          {
            path:'/',
            name:'home',
            components:()=>import('@/components/home')
          }
          
          import()方法由es6提出,import()方法是動態加載,返回一個Promise對象,then方法的參數是加載到的模塊。類似于Node.js的require方法,主要import()方法是異步加載的。
          復制代碼

          6.動態組件

          場景:做一個 tab 切換時就會涉及到組件動態加載

          <component v-bind:is="currentTabComponent"></component>
          復制代碼

          但是這樣每次組件都會重新加載,會消耗大量性能,所以 就起到了作用

          <keep-alive>
            <component v-bind:is="currentTabComponent"></component>
          </keep-alive>
          復制代碼

          這樣切換效果沒有動畫效果,這個也不用著急,可以利用內置的

          <transition>
          <keep-alive>
            <component v-bind:is="currentTabComponent"></component>
          </keep-alive>
          </transition>
          復制代碼

          7.遞歸組件

          場景:如果開發一個 tree 組件,里面層級是根據后臺數據決定的,這個時候就需要用到動態組件

          // 遞歸組件: 組件在它的模板內可以遞歸的調用自己,只要給組件設置name組件就可以了。
          // 設置那么House在組件模板內就可以遞歸使用了,不過需要注意的是,
          // 必須給一個條件來限制數量,否則會拋出錯誤: max stack size exceeded
          // 組件遞歸用來開發一些具體有未知層級關系的獨立組件。比如:
          // 聯級選擇器和樹形控件 
          
          <template>
            <div v-for="(item,index) in treeArr">
                子組件,當前層級值: {{index}} <br/>
                <!-- 遞歸調用自身, 后臺判斷是否不存在改值 -->
                <tree :item="item.arr" v-if="item.flag"></tree>
            </div>
          </template>
          <script>
          export default {
            // 必須定義name,組件內部才能遞歸調用
            name: 'tree',
            data(){
              return {}
            },
            // 接收外部傳入的值
            props: {
               item: {
                type:Array,
                default: ()=>[]
              }
            }
          }
          </script>
          復制代碼

          遞歸組件必須設置name 和結束的閥值

          8.函數式組件

          定義:無狀態,無法實例化,內部沒有任何生命周期處理方法 規則:在 2.3.0 之前的版本中,如果一個函數式組件想要接收 prop,則 props 選項是必須的。 在 2.3.0 或以上的版本中,你可以省略 props 選項,所有組件上的特性都會被自動隱式解析為 prop 在 2.5.0 及以上版本中,如果你使用了單文件組件(就是普通的.vue 文件),可以直接在 template 上聲明functional 組件需要的一切都是通過 context 參數傳遞

          context 屬性有: 1.props:提供所有 prop 的對象 2.children: VNode 子節點的數組 3.slots: 一個函數,返回了包含所有插槽的對象 4.scopedSlots: (2.6.0+) 一個暴露傳入的作用域插槽的對象。也以函數形式暴露普通插槽。 5.data:傳遞給組件的整個數據對象,作為 createElement 的第二個參數傳入組件 6.parent:對父組件的引用 7.listeners: (2.3.0+) 一個包含了所有父組件為當前組件注冊的事件監聽器的對象。這是 data.on 的一個別名。 8.injections: (2.3.0+) 如果使用了 inject 選項,則該對象包含了應當被注入的屬性

          <template functional>
            <div v-for="(item,index) in props.arr">{{item}}</div>
          </template>
          復制代碼

          9.components和 Vue.component

          components:局部注冊組件

          export default{
            components:{home}
          }
          復制代碼

          Vue.component:全局注冊組件

          Vue.component('home',home)
          復制代碼

          10.Vue.extend

          場景:vue 組件中有些需要將一些元素掛載到元素上,這個時候 extend 就起到作用了 是構造一個組件的語法器 寫法:

          // 創建構造器
          var Profile = Vue.extend({
            template: '<p>{{extendData}}</br>實例傳入的數據為:{{propsExtend}}</p>',//template對應的標簽最外層必須只有一個標簽
            data: function () {
              return {
                extendData: '這是extend擴展的數據',
              }
            },
            props:['propsExtend']
          })
          
          // 創建的構造器可以掛載到元素上,也可以通過 components 或 Vue.component()注冊使用
          // 掛載到一個元素上??梢酝ㄟ^propsData傳參.
          new Profile({propsData:{propsExtend:'我是實例傳入的數據'}}).$mount('#app-extend')
          
          // 通過 components 或 Vue.component()注冊
          Vue.component('Profile',Profile)
          復制代碼

          11.mixins

          場景:有些組件有些重復的 js 邏輯,如校驗手機驗證碼,解析時間等,mixins 就可以實現這種混入 mixins 值是一個數組

          const mixin={
              created(){
                this.dealTime()
              },
              methods:{
                dealTime(){
                  console.log('這是mixin的dealTime里面的方法');
                }
            }
          }
          
          export default{
            mixins:[mixin]
          }
          復制代碼

          12.extends

          extends用法和mixins很相似,只不過接收的參數是簡單的選項對象或構造函數,所以extends只能單次擴展一個組件

          const extend={
              created(){
                this.dealTime()
              },
              methods:{
                dealTime(){
                  console.log('這是mixin的dealTime里面的方法');
                }
            }
          }
          
          export default{
            extends:extend
          }
          復制代碼

          13.Vue.use()

          場景:我們使用 element時會先 import,再 Vue.use()一下,實際上就是注冊組件,觸發 install 方法; 這個在組件調用會經常使用到; 會自動組織多次注冊相同的插件.

          14.install

          場景:在 Vue.use()說到,執行該方法會觸發 install 是開發vue的插件,這個方法的第一個參數是 Vue 構造器,第二個參數是一個可選的選項對象(可選)

          var MyPlugin = {};
            MyPlugin.install = function (Vue, options) {
              // 2. 添加全局資源,第二個參數傳一個值默認是update對應的值
              Vue.directive('click', {
                bind(el, binding, vnode, oldVnode) {
                  //做綁定的準備工作,添加時間監聽
                  console.log('指令my-directive的bind執行啦');
                },
                inserted: function(el){
                //獲取綁定的元素
                console.log('指令my-directive的inserted執行啦');
                },
                update: function(){
                //根據獲得的新值執行對應的更新
                //對于初始值也會調用一次
                console.log('指令my-directive的update執行啦');
                },
                componentUpdated: function(){
                console.log('指令my-directive的componentUpdated執行啦');
                },
                unbind: function(){
                //做清理操作
                //比如移除bind時綁定的事件監聽器
                console.log('指令my-directive的unbind執行啦');
                }
              })
          
              // 3. 注入組件
              Vue.mixin({
                created: function () {
                  console.log('注入組件的created被調用啦');
                  console.log('options的值為',options)
                }
              })
          
              // 4. 添加實例方法
              Vue.prototype.$myMethod = function (methodOptions) {
                console.log('實例方法myMethod被調用啦');
              }
            }
          
            //調用MyPlugin
            Vue.use(MyPlugin,{someOption: true })
          
            //3.掛載
            new Vue({
              el: '#app'
            });
          復制代碼

          更多請戳 vue中extend,mixins,extends,components,install的幾個操作

          15. Vue.nextTick

          2.1.0 新增 場景:頁面加載時需要讓文本框獲取焦點 用法:在下次 DOM 更新循環結束之后執行延遲回調。在修改數據之后立即使用這個方法,獲取更新后的 DOM

          mounted(){ //因為 mounted 階段 dom 并未渲染完畢,所以需要$nextTick
            this.$nextTick(() => {
              this.$refs.inputs.focus() //通過 $refs 獲取dom 并綁定 focus 方法
            })
          }
          復制代碼

          16.Vue.directive

          16.1 使用

          場景:官方給我們提供了很多指令,但是我們如果想將文字變成指定的顏色定義成指令使用,這個時候就需要用到Vue.directive

          // 全局定義
          Vue.directive("change-color",function(el,binding,vnode){
            el.style["color"]= binding.value;
          })
          
          // 使用
          <template>
          <div v-change-color=“color”>{{message}}</div>
          </template>
          <script>
            export default{
              data(){
                return{
                  color:'green'
                }
              }
            }
          </script>
          復制代碼

          16.2 生命周期

          1.bind 只調用一次,指令第一次綁定到元素時候調用,用這個鉤子可以定義一個綁定時執行一次的初始化動作。 2.inserted:被綁定的元素插入父節點的時候調用(父節點存在即可調用,不必存在document中) 3.update: 被綁定與元素所在模板更新時調用,而且無論綁定值是否有變化,通過比較更新前后的綁定值,忽略不必要的模板更新 4.componentUpdate :被綁定的元素所在模板完成一次更新更新周期的時候調用 5.unbind: 只調用一次,指令月元素解綁的時候調用

          17. Vue.filter

          場景:時間戳轉化成年月日這是一個公共方法,所以可以抽離成過濾器使用

          // 使用
          // 在雙花括號中
          {{ message | capitalize }}
          
          // 在 `v-bind` 中
          <div v-bind:id="rawId | formatId"></div>
          
          // 全局注冊
          Vue.filter('stampToYYMMDD', (value) =>{
            // 處理邏輯
          })
          
          // 局部注冊
          filters: {
            stampToYYMMDD: (value)=> {
              // 處理邏輯
            }
          }
          
          // 多個過濾器全局注冊
          // /src/common/filters.js
          let dateServer = value => value.replace(/(\d{4})(\d{2})(\d{2})/g, '$1-$2-$3') 
          export { dateServer }
          // /src/main.js
          import * as custom from './common/filters/custom'
          Object.keys(custom).forEach(key => Vue.filter(key, custom[key]))
          
          復制代碼

          18.Vue.compile

          場景:在 render 函數中編譯模板字符串。只在獨立構建時有效

          var res = Vue.compile('<div><span>{{ msg }}</span></div>')
          
          new Vue({
            data: {
              msg: 'hello'
            },
            render: res.render,
            staticRenderFns: res.staticRenderFns
          })
          復制代碼

          19.Vue.version

          場景:有些開發插件需要針對不同 vue 版本做兼容,所以就會用到 Vue.version 用法:Vue.version()可以獲取 vue 版本

          var version = Number(Vue.version.split('.')[0])
          
          if (version === 2) {
            // Vue v2.x.x
          } else if (version === 1) {
            // Vue v1.x.x
          } else {
            // Unsupported versions of Vue
          }
          復制代碼

          20.Vue.set()

          場景:當你利用索引直接設置一個數組項時或你修改數組的長度時,由于 Object.defineprototype()方法限制,數據不響應式更新 不過vue.3.x 將利用 proxy 這個問題將得到解決 解決方案:

          // 利用 set
          this.$set(arr,index,item)
          
          // 利用數組 push(),splice()
          復制代碼

          21.Vue.config.keyCodes

          場景:自定義按鍵修飾符別名

          // 將鍵碼為 113 定義為 f2
          Vue.config.keyCodes.f2 = 113;
          <input type="text" @keyup.f2="add"/>
          復制代碼

          22.Vue.config.performance

          場景:監聽性能

          Vue.config.performance = true
          復制代碼

          只適用于開發模式和支持 performance.mark API 的瀏覽器上

          23.Vue.config.errorHandler

          1.場景:指定組件的渲染和觀察期間未捕獲錯誤的處理函數 2.規則: 從 2.2.0 起,這個鉤子也會捕獲組件生命周期鉤子里的錯誤。同樣的,當這個鉤子是 undefined 時,被捕獲的錯誤會通過 console.error 輸出而避免應用崩潰 從 2.4.0 起,這個鉤子也會捕獲 Vue 自定義事件處理函數內部的錯誤了 從 2.6.0 起,這個鉤子也會捕獲 v-on DOM 監聽器內部拋出的錯誤。另外,如果任何被覆蓋的鉤子或處理函數返回一個 Promise 鏈 (例如 async 函數),則來自其 Promise 鏈的錯誤也會被處理 3.使用

          Vue.config.errorHandler = function (err, vm, info) {
            // handle error
            // `info` 是 Vue 特定的錯誤信息,比如錯誤所在的生命周期鉤子
            // 只在 2.2.0+ 可用
          }
          復制代碼

          24.Vue.config.warnHandler

          2.4.0 新增 1.場景:為 Vue 的運行時警告賦予一個自定義處理函數,只會在開發者環境下生效 2.用法:

          Vue.config.warnHandler = function (msg, vm, trace) {
            // `trace` 是組件的繼承關系追蹤
          }
          復制代碼

          25.v-pre

          場景:vue 是響應式系統,但是有些靜態的標簽不需要多次編譯,這樣可以節省性能

          <span v-pre>{{ this will not be compiled }}</span>   顯示的是{{ this will not be compiled }}
          <span v-pre>{{msg}}</span>     即使data里面定義了msg這里仍然是顯示的{{msg}}
          復制代碼

          26.v-cloak

          場景:在網速慢的情況下,在使用vue綁定數據的時候,渲染頁面時會出現變量閃爍 用法:這個指令保持在元素上直到關聯實例結束編譯。和 CSS 規則如 [v-cloak] { display: none } 一起用時,這個指令可以隱藏未編譯的 Mustache 標簽直到實例準備完畢

          // template 中
          <div class="#app" v-cloak>
              <p>{{value.name}}</p>
          </div>
          
          // css 中
          [v-cloak] {
              display: none;
          }
          
          復制代碼

          這樣就可以解決閃爍,但是會出現白屏,這樣可以結合骨架屏使用

          27.v-once

          場景:有些 template 中的靜態 dom 沒有改變,這時就只需要渲染一次,可以降低性能開銷

          <span v-once> 這時只需要加載一次的標簽</span>
          復制代碼

          v-once 和 v-pre 的區別: v-once只渲染一次;v-pre不編譯,原樣輸出

          28.事件修飾符

          .stop:阻止冒泡
          .prevent:阻止默認行為
          .self:僅綁定元素自身觸發
          .once: 2.1.4 新增,只觸發一次
          .passive: 2.3.0 新增,滾動事件的默認行為 (即滾動行為) 將會立即觸發,不能和.prevent 一起使用
          復制代碼

          29.按鍵修飾符和按鍵碼

          場景:有的時候需要監聽鍵盤的行為,如按下 enter 去查詢接口等

          // 對應鍵盤上的關鍵字
          .enter
          .tab
          .delete (捕獲“刪除”和“退格”鍵)
          .esc
          .space
          .up
          .down
          .left
          .right
          復制代碼

          30.Vue-router

          場景:Vue-router 是官方提供的路由插件

          30.1 緩存和動畫

          1.路由是使用官方組件 vue-router,使用方法相信大家非常熟悉;
          2.這里我就敘述下路由的緩存和動畫;
          3.可以用exclude(除了)或者include(包括),2.1.0 新增來坐判斷

          <transition>
            <keep-alive :include="['a', 'b']">
            //或include="a,b" :include="/a|b/",a 和 b 表示組件的 name
            //因為有些頁面,如試試數據統計,要實時刷新,所以就不需要緩存
              <router-view/> //路由標簽
            </keep-alive>
            <router-view exclude="c"/> 
            // c 表示組件的 name值
          </transition>
          復制代碼

          注:匹配首先檢查組件自身的 name 選項,如果 name 選項不可用,則匹配它的局部注冊名稱 (父組件 components 選項的鍵值)。匿名組件不能被匹配
          4.用 v-if 做判斷,組件會重新渲染,但是不用一一列舉組件 name

          30.2 全局路由鉤子

          1.router.beforeEach

          router.beforeEach((to, from, next) => {
            console.log('全局前置守衛:beforeEach -- next需要調用') //一般登錄攔截用這個,也叫導航鉤子守衛
            if (path === '/login') {
              next()
              return
            }
            if (token) {
              next();
            } 
          })
          復制代碼

          2.router.beforeResolve (v 2.5.0+) 和beforeEach類似,區別是在導航被確認之前,同時在所有組件內守衛和異步路由組件被解析之后,解析守衛就被調用 即在 beforeEach之后調用

          3.router.afterEach 全局后置鉤子 在所有路由跳轉結束的時候調用 這些鉤子不會接受 next 函數也不會改變導航本身

          30.3 組件路由鉤子

          1.beforeRouteEnter 在渲染該組件的對應路由被確認前調用,用法和參數與router.beforeEach類似,next需要被主動調用 此時組件實例還未被創建,不能訪問this 可以通過傳一個回調給 next來訪問組件實例。在導航被確認的時候執行回調,并且把組件實例作為回調方法的參數

          beforeRouteEnter (to, from, next) {
            // 這里還無法訪問到組件實例,this === undefined
            next( vm => {
              // 通過 `vm` 訪問組件實例
            })
          }
          復制代碼

          2.beforeRouteUpdate (v 2.2+) 在當前路由改變,并且該組件被復用時調用,可以通過this訪問實例, next需要被主動調用,不能傳回調

          3.beforeRouteLeave 導航離開該組件的對應路由時調用,可以訪問組件實例 this,next需要被主動調用,不能傳回調

          30.4 路由模式

          設置 mode 屬性:hash或 history

          30.5 Vue.$router

          this.$router.push():跳轉到不同的url,但這個方法回向history棧添加一個記錄,點擊后退會返回到上一個頁面
          this.$router.replace():不會有記錄
          this.$router.go(n):n可為正數可為負數。正數前進, 負數后退,類似 window.history.go(n)
          復制代碼

          30.6 Vue.$route

          表示當前跳轉的路由對象,屬性有: name:路由名稱 path:路徑 query:傳參接收值 params:傳參接收值 fullPath:完成解析后的 URL,包含查詢參數和 hash 的完整路徑 matched:路由記錄副本 redirectedFrom:如果存在重定向,即為重定向來源的路由的名字

          this.$route.params.id:獲取通過 params 或/:id傳參的參數
          this.$route.query.id:獲取通過 query 傳參的參數
          復制代碼

          30.7 router-view 的 key

          場景:由于 Vue 會復用相同組件, 即 /page/1 => /page/2 或者 /page?id=1 => /page?id=2 這類鏈接跳轉時, 將不在執行created, mounted之類的鉤子

          <router-view :key="$route.fullPath"></router-view>
          復制代碼

          這樣組件的 created 和 mounted 就都會執行

          31.Object.freeze

          場景:一個長列表數據,一般不會更改,但是vue會做getter和setter的轉換 用法:是ES5新增的特性,可以凍結一個對象,防止對象被修改 支持:vue 1.0.18+對其提供了支持,對于data或vuex里使用freeze凍結了的對象,vue不會做getter和setter的轉換 注意:凍結只是凍結里面的單個屬性,引用地址還是可以更改

          new Vue({
              data: {
                  // vue不會對list里的object做getter、setter綁定
                  list: Object.freeze([
                      { value: 1 },
                      { value: 2 }
                  ])
              },
              mounted () {
                  // 界面不會有響應,因為單個屬性被凍結
                  this.list[0].value = 100;
          
                  // 下面兩種做法,界面都會響應
                  this.list = [
                      { value: 100 },
                      { value: 200 }
                  ];
                  this.list = Object.freeze([
                      { value: 100 },
                      { value: 200 }
                  ]);
              }
          })
          復制代碼

          32.調試 template

          場景:在Vue開發過程中, 經常會遇到template模板渲染時JavaScript變量出錯的問題, 此時也許你會通過console.log來進行調試 這時可以在開發環境掛載一個 log 函數

          // main.js
          Vue.prototype.$log = window.console.log;
          
          // 組件內部
          <div>{{$log(info)}}</div>
          
          復制代碼

          33.vue-loader 小技巧

          33.1 preserveWhitespace

          場景:開發 vue 代碼一般會有空格,這個時候打包壓縮如果不去掉空格會加大包的體積 配置preserveWhitespace可以減小包的體積

          {
            vue: {
              preserveWhitespace: false
            }
          }
          復制代碼

          33.2 transformToRequire

          場景:以前在寫 Vue 的時候經常會寫到這樣的代碼:把圖片提前 require 傳給一個變量再傳給組件

          // page 代碼
          <template>
            <div>
              <avatar :img-src="imgSrc"></avatar>
            </div>
          </template>
          <script>
            export default {
              created () {
                this.imgSrc = require('./assets/default-avatar.png')
              }
            }
          </script>
          復制代碼

          現在:通過配置 transformToRequire 后,就可以直接配置,這樣vue-loader會把對應的屬性自動 require 之后傳給組件

          // vue-cli 2.x在vue-loader.conf.js 默認配置是
          transformToRequire: {
              video: ['src', 'poster'],
              source: 'src',
              img: 'src',
              image: 'xlink:href'
          }
          
          // 配置文件,如果是vue-cli2.x 在vue-loader.conf.js里面修改
            avatar: ['default-src']
          
          // vue-cli 3.x 在vue.config.js
          // vue-cli 3.x 將transformToRequire屬性換為了transformAssetUrls
          module.exports = {
            pages,
            chainWebpack: config => {
              config
                .module
                  .rule('vue')
                  .use('vue-loader')
                  .loader('vue-loader')
                  .tap(options => {
                options.transformAssetUrls = {
                  avatar: 'img-src',
                }
                return options;
                });
            }
          }
          
          // page 代碼可以簡化為
          <template>
            <div>
              <avatar img-src="./assets/default-avatar.png"></avatar>
            </div>
          </template>
          復制代碼

          34.為路徑設置別名

          1.場景:在開發過程中,我們經常需要引入各種文件,如圖片、CSS、JS等,為了避免寫很長的相對路徑(../),我們可以為不同的目錄配置一個別名

          2.vue-cli 2.x 配置

          // 在 webpack.base.config.js中的 resolve 配置項,在其 alias 中增加別名
          resolve: {
              extensions: ['.js', '.vue', '.json'],
              alias: {
                'vue$': 'vue/dist/vue.esm.js',
                '@': resolve('src'),
              }
            },
          復制代碼

          3.vue-cli 3.x 配置

          // 在根目錄下創建vue.config.js
          var path = require('path')
          function resolve (dir) {
            console.log(__dirname)
            return path.join(__dirname, dir)
          }
          module.exports = {
            chainWebpack: config => {
              config.resolve.alias
                .set(key, value) // key,value自行定義,比如.set('@@', resolve('src/components'))
            }
          }
          復制代碼

          35.img 加載失敗

          場景:有些時候后臺返回圖片地址不一定能打開,所以這個時候應該加一張默認圖片

          // page 代碼
          <img :src="imgUrl" @error="handleError" alt="">
          <script>
          export default{
            data(){
              return{
                imgUrl:''
              }
            },
            methods:{
              handleError(e){
                e.target.src=reqiure('圖片路徑') //當然如果項目配置了transformToRequire,參考上面 33.2
              }
            }
          }
          </script>
          復制代碼

          36.css

          36.1 局部樣式

          1.Vue中style標簽的scoped屬性表示它的樣式只作用于當前模塊,是樣式私有化.

          2.渲染的規則/原理: 給HTML的DOM節點添加一個 不重復的data屬性 來表示 唯一性 在對應的 CSS選擇器 末尾添加一個當前組件的 data屬性選擇器來私有化樣式,如:.demo[data-v-2311c06a]{} 如果引入 less 或 sass 只會在最后一個元素上設置

          // 原始代碼
          <template>
            <div class="demo">
              <span class="content">
                Vue.js scoped
              </span>
            </div>
          </template>
          
          <style lang="less" scoped>
            .demo{
              font-size: 16px;
              .content{
                color: red;
              }
            }
          </style>
          
          // 瀏覽器渲染效果
          <div data-v-fed36922>
            Vue.js scoped
          </div>
          <style type="text/css">
          .demo[data-v-039c5b43] {
            font-size: 14px;
          }
          .demo .content[data-v-039c5b43] { //.demo 上并沒有加 data 屬性
            color: red;
          }
          </style>
          復制代碼

          36.2 deep 屬性

          // 上面樣式加一個 /deep/
          <style lang="less" scoped>
            .demo{
              font-size: 14px;
            }
            .demo /deep/ .content{
              color: blue;
            }
          </style>
          
          // 瀏覽器編譯后
          <style type="text/css">
          .demo[data-v-039c5b43] {
            font-size: 14px;
          }
          .demo[data-v-039c5b43] .content {
            color: blue;
          }
          </style>


          作者:火狼1
          鏈接:https://juejin.cn/post/6844903959266590728
          來源:掘金
          著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。


          者:Ahmad

          譯者:飄飄

          https://ishadeed.com/article/image-techniques/


          主站蜘蛛池模板: 久久久精品人妻一区亚美研究所 | 国产伦精品一区二区三区视频猫咪 | 91视频一区二区| 精品国产一区在线观看| 亚洲一区二区三区精品视频| 国产精品久久久久一区二区| 久久er99热精品一区二区| 亚洲av鲁丝一区二区三区| 无码日韩精品一区二区三区免费| 熟妇人妻一区二区三区四区| 亚洲一区二区三区在线观看精品中文| 亚洲国产激情一区二区三区| 精品无码人妻一区二区三区不卡 | 亚洲AV日韩精品一区二区三区| 日韩三级一区二区| 在线观看精品视频一区二区三区| 日韩精品一区二区三区老鸭窝| 精品欧洲av无码一区二区| 欧美激情国产精品视频一区二区| 亚洲午夜一区二区电影院| 熟妇人妻AV无码一区二区三区| 亚洲日韩精品一区二区三区无码| 中文字幕一区二区三区在线播放| 一区二区三区伦理高清| 亚洲成在人天堂一区二区| 亚洲av无码一区二区三区天堂古代| 五月婷婷一区二区| 一区二区三区波多野结衣| 亚洲视频在线观看一区| 无码人妻精品一区二区蜜桃AV| 国产亚洲一区二区三区在线不卡| 一区二区三区高清视频在线观看| 日本精品视频一区二区三区| 精品国产一区二区三区久久久狼| 无码一区二区三区爆白浆| 日韩精品福利视频一区二区三区| 午夜福利一区二区三区在线观看| 精品久久久久一区二区三区| 波多野结衣av高清一区二区三区| 51视频国产精品一区二区| 久久久久成人精品一区二区|