国产秋霞理论久久久电影-婷婷色九月综合激情丁香-欧美在线观看乱妇视频-精品国avA久久久久久久-国产乱码精品一区二区三区亚洲人-欧美熟妇一区二区三区蜜桃视频

【源碼】Vue-i18n: 你知道國際化是怎么實(shí)現(xiàn)的么?

共 25459字,需瀏覽 51分鐘

 ·

2021-06-22 01:24

Vue-i18n 簡單介紹以及使用

大家好,我是 Gopal。目前就職于 Shopee,一家做跨境電商的公司,因?yàn)闃I(yè)務(wù)涉及到多個國家,所以我們各個系統(tǒng)都會涉及到國際化翻譯。Vue I18n 是 Vue.js 的國際化插件,它可以輕松地將一些本地化功能集成到你的 Vue.js 應(yīng)用程序中。

本文的源碼閱讀是基于版本 8.24.4 進(jìn)行

我們來看一個官方的 demo

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>ES modules browser example</title>
    <script src="../../dist/vue-i18n.js"></script>
  </head>
  <body>
    <div id="app">
      <p>{{ $t('message.hello') }}</p>
    </div>
    <script type="module">
      // 如果使用模塊系統(tǒng) (例如通過 vue-cli),則需要導(dǎo)入 Vue 和 VueI18n ,然后調(diào)用 Vue.use(VueI18n)。
      import Vue from 'https://unpkg.com/[email protected]/dist/vue.esm.browser.js'
      Vue.use(VueI18n)

      new Vue({
        // 通過 `i18n` 選項(xiàng)創(chuàng)建 Vue 實(shí)例
        // 通過選項(xiàng)創(chuàng)建 VueI18n 實(shí)例
        i18nnew VueI18n({
          locale'zh'// 設(shè)置地區(qū)
          // 準(zhǔn)備翻譯的語言環(huán)境信息
          // 設(shè)置地區(qū)信息
          messages: {
            en: {
              message: {
                hello'hello, I am Gopal'
              }
            },
            zh: {
              message: {
                hello'你好,我是 Gopal 一號'
              }
            }
          }
        })
      }).$mount('#app')
    
</script>
  </body>
</html>

使用上是比較簡單的,本文我們深入了解 Vue-i18n 的工作原理,探索國際化實(shí)現(xiàn)的奧秘。包括:

  • 整體的 Vue-i18n 的架構(gòu)是怎樣的?
  • 上述 demo 是如何生效的?
  • 我們?yōu)槭裁纯梢灾苯釉谀0逯惺褂?$t?它做了什么?
  • 上述 demo 是如何做到不刷新更新頁面的?
  • 全局組件 <i18n> 和全局自定義指令的實(shí)現(xiàn)?

代碼結(jié)構(gòu)以及入口

我們看一下 Vue-18n 的代碼結(jié)構(gòu)如下

├── components/
│   ├── interpolation.js // <i18n> 組件的實(shí)現(xiàn)
│   └── number.js
├── directive.js // 全局自定義組件的實(shí)現(xiàn)
├── extend.js // 拓展方法
├── format.js // parse 和 compile 的核心實(shí)現(xiàn)
├── index.js // 入口文件
├── install.js // 注冊方法
├── mixin.js // 處理各個生命周期
├── path.js
└── util.js

關(guān)于 Vue-18n 的整體架構(gòu),網(wǎng)上找到了一個比較貼切的圖,如下。其中左側(cè)是 Vue-i18n 提供的一些方法、組件、自定義指令等能力,右側(cè)是 Vue-i18n 對數(shù)據(jù)的管理

入口文件為 index.js,在 VueI18n 類中的 constructor 中先調(diào)用 install 方法注冊

// Auto install if it is not done yet and `window` has `Vue`.
// To allow users to avoid auto-installation in some cases,
// this code should be placed here. See #290
/* istanbul ignore if */
if (!Vue && typeof window !== 'undefined' && window.Vue) {
  install(window.Vue)
}

install 方法中,主要做了幾件事,如下代碼注釋,后面還會提到,這里有一個大致的印象

// 在 Vue 的原型中拓展方法,代碼在 extend.js 里
extend(Vue)
// 在 Vue 中通過 mixin 的方式混入
Vue.mixin(mixin)
// 全局指令
Vue.directive('t', { bind, update, unbind })
// 全局組件
Vue.component(interpolationComponent.name, interpolationComponent)
Vue.component(numberComponent.name, numberComponent)

注冊完成后,會調(diào)用 _initVM,這個主要是創(chuàng)建了一個 Vue 實(shí)例對象,后面很多功能會跟這個 this._ vm 相關(guān)聯(lián)

// VueI18n 其實(shí)不是一個 Vue 對象,但是它在內(nèi)部建立了 Vue 對象 vm,然后很多的功能都是跟這個 vm 關(guān)聯(lián)的
this._initVM({
  locale,
  fallbackLocale,
  messages,
  dateTimeFormats,
  numberFormats
})

_initVM (data: {
         locale: Locale,
         fallbackLocale: FallbackLocale,
         messages: LocaleMessages,
         dateTimeFormats: DateTimeFormats,
         numberFormats: NumberFormats
         }): void {
  // 用來關(guān)閉 Vue 打印消息的
  const silent = Vue.config.silent
  Vue.config.silent = true
  this._vm = new Vue({ data }) // 創(chuàng)建了一個 Vue 實(shí)例對象
  Vue.config.silent = silent
}

全局方法 $t 的實(shí)現(xiàn)

我們來看看 Vue-i18n 的 $t 方法的實(shí)現(xiàn),揭開國際化翻譯的神秘面紗

在 extent.js 中,我們看到在 Vue 的原型中掛載 $t 方法,這是我們?yōu)槭裁茨軌蛑苯釉谀0逯惺褂玫脑颉?/p>

// 在 Vue 的原型中掛載 $t 方法,這是我們?yōu)槭裁茨軌蛑苯釉谀0逯惺褂玫脑?/span>
// 把 VueI18n 對象實(shí)例的方法都注入到 Vue 實(shí)例上
Vue.prototype.$t = function (key: Path, ...values: any): TranslateResult {
  const i18n = this.$i18n
  // 代理模式的使用
  return i18n._t(key, i18n.locale, i18n._getMessages(), this, ...values)
}

看到的是調(diào)用 index.js 中的 $t 的方法

// $t 最后調(diào)用的方法
_t (key: Path, _locale: Locale, messages: LocaleMessages, host: any, ...values: any): any {
  if (!key) { return '' }
  const parsedArgs = parseArgs(...values)
  // 如果 escapeParameterHtml 被配置為 true,那么插值參數(shù)將在轉(zhuǎn)換消息之前被轉(zhuǎn)義。
  if(this._escapeParameterHtml) {
    parsedArgs.params = escapeParams(parsedArgs.params)
  }
  const locale: Locale = parsedArgs.locale || _locale
  // 翻譯
  let ret: any = this._translate(
    messages, locale, this.fallbackLocale, key,
    host, 'string', parsedArgs.params
  )
}

_interpolate

回到主線,當(dāng)調(diào)用 _translate 的時候,接著調(diào)用

this._interpolate(step, messages[step], key, host, interpolateMode, args, [key])

并返回

this._render(ret, interpolateMode, values, key)

_render 方法中,可以調(diào)用自定義方法去處理插值對象,或者是默認(rèn)的方法處理插值對象。

_render (message: string | MessageFunction, interpolateMode: string, values: any, path: string): any {
  // 自定義插值對象
  let ret = this._formatter.interpolate(message, values, path)

  // If the custom formatter refuses to work - apply the default one
  if (!ret) {
    // 默認(rèn)的插值對象
    ret = defaultFormatter.interpolate(message, values, path)
  }

  // if interpolateMode is **not** 'string' ('row'),
  // return the compiled data (e.g. ['foo', VNode, 'bar']) with formatter
  return interpolateMode === 'string' && !isString(ret) ? ret.join('') : ret
}

我們主要來看看默認(rèn)的方法處理,主要是在 format.js 中完成

format.js 中的 parse 和 compile

format.js 實(shí)現(xiàn)了 BaseFormatter 類,這里使用 _caches 實(shí)現(xiàn)了一層緩存優(yōu)化,也是常見的優(yōu)化手段。下面的 沒有插值對象的話,就直接返回 [message],就完成使命了。

export default class BaseFormatter {
  // 實(shí)現(xiàn)緩存效果
  _caches: { [key: string]: Array<Token> }

  constructor () {
    this._caches = Object.create(null)
  }

  interpolate (message: string, values: any): Array<any> {
    // 沒有插值對象的話,就直接返回
    if (!values) {
      return [message]
    }
    // 如果存在 tokens,則組裝值返回
    let tokens: Array<Token> = this._caches[message]
    if (!tokens) {
      // 沒有存在 tokens,則拆分 tokens
      tokens = parse(message)
      this._caches[message] = tokens
    }
    return compile(tokens, values)
  }
}

當(dāng)遇到如下的使用方式的時候

<p>{{ $t('message.sayHi', { name: 'Gopal' })}}</p>

主要涉及兩個方法,我們先來看 parse,代碼比較直觀,可以看到本質(zhì)上是遍歷字符串,然后遇到有 {} 包裹的,把其中的內(nèi)容附上類型拿出來放入到 tokens 里返回。

// 代碼比較直觀,可以看到本質(zhì)上是遍歷字符串,然后遇到有 {} 包裹的,把其中的內(nèi)容附上類型拿出來放入到 tokens 里返回。
export function parse (format: string): Array<Token{
  const tokens: Array<Token> = []
  let position: number = 0

  let text: string = ''
  while (position < format.length) {
    let char: string = format[position++]
    if (char === '{') {
      if (text) {
        tokens.push({ type'text'value: text })
      }

      text = ''
      let sub: string = ''
      char = format[position++]
      while (char !== undefined && char !== '}') {
        sub += char
        char = format[position++]
      }
      const isClosed = char === '}'

      const type = RE_TOKEN_LIST_VALUE.test(sub)
        ? 'list'
        : isClosed && RE_TOKEN_NAMED_VALUE.test(sub)
          ? 'named'
          : 'unknown'
      tokens.push({ value: sub, type })
    } else if (char === '%') {
      // when found rails i18n syntax, skip text capture
      if (format[(position)] !== '{') {
        text += char
      }
    } else {
      text += char
    }
  }

  text && tokens.push({ type'text'value: text })

  return tokens
}

以上的 demo 的返回 tokens 如下:

[
    {
        "type""text",
        "value""hi, I am "
    },
    {
        "value""name",
        "type""named"
    }
]

還有 parse,就是將上述的組裝起來

// 把一切都組裝起來
export function compile (tokens: Array<Token>, values: Object | Array<any>): Array<any{
  const compiled: Array<any> = []
  let index: number = 0

  const mode: string = Array.isArray(values)
    ? 'list'
    : isObject(values)
      ? 'named'
      : 'unknown'
  if (mode === 'unknown') { return compiled }

  while (index < tokens.length) {
    const token: Token = tokens[index]
    switch (token.type) {
      case 'text':
        compiled.push(token.value)
        break
      case 'list':
        compiled.push(values[parseInt(token.value, 10)])
        break
      case 'named':
        if (mode === 'named') {
          compiled.push((values: any)[token.value])
        } else {
          if (process.env.NODE_ENV !== 'production') {
            warn(`Type of token '${token.type}' and format of value '${mode}' don't match!`)
          }
        }
        break
      case 'unknown':
        if (process.env.NODE_ENV !== 'production') {
          warn(`Detect 'unknown' type of token!`)
        }
        break
    }
    index++
  }

  return compiled
}

以上 demo 最后返回 ["hi, I am ", "Gopal"],最后再做一個簡單的拼接就可以了,至此,翻譯就可以成功了

Vue-i18n 是如何避免 XSS ?

上面 _t 方法中有一個 _escapeParameterHtml 。這里談?wù)?escapeParams,其實(shí)是 Vue-i18n 為了防止 xss 攻擊做的一個處理。如果 escapeParameterHtml 被配置為 true,那么插值參數(shù)將在轉(zhuǎn)換消息之前被轉(zhuǎn)義。

// 如果escapeParameterHtml被配置為true,那么插值參數(shù)將在轉(zhuǎn)換消息之前被轉(zhuǎn)義。
if(this._escapeParameterHtml) {
  parsedArgs.params = escapeParams(parsedArgs.params)
}
/**
 * Sanitizes html special characters from input strings. For mitigating risk of XSS attacks.
 * @param rawText The raw input from the user that should be escaped.
 */

function escapeHtml(rawText: string): string {
  return rawText
    .replace(/</g'&lt;')
    .replace(/>/g'&gt;')
    .replace(/"/g'&quot;')
    .replace(/'/g'&apos;')
}

/**
 * Escapes html tags and special symbols from all provided params which were returned from parseArgs().params.
 * This method performs an in-place operation on the params object.
 *
 * @param {any} params Parameters as provided from `parseArgs().params`.
 *                     May be either an array of strings or a string->any map.
 *
 * @returns The manipulated `params` object.
 */

export function escapeParams(params: any): any {
  if(params != null) {
    Object.keys(params).forEach(key => {
      if(typeof(params[key]) == 'string') {
        // 處理參數(shù),防止 XSS 攻擊
        params[key] = escapeHtml(params[key])
      }
    })
  }
  return params
}

如何做到無刷新更新頁面

我們發(fā)現(xiàn),在 demo 中,我無論是修改了 locale 還是 message 的值,頁面都不會刷新,但頁面也是會更新數(shù)據(jù)。這個功能類似 Vue 的雙向數(shù)據(jù)綁定,它是如何實(shí)現(xiàn)的呢?

new

這里 Vue-i18n 采用了觀察者模式,我們上面提到過的 _initVM 方法中,我們會將翻譯相關(guān)的數(shù)據(jù) data 通過 new Vue 傳遞給 this._vm 實(shí)例?,F(xiàn)在要做的就是去監(jiān)聽這些 data 的變化

Vue-i18n 的這一塊的邏輯主要是在 mixin.js 文件中,在 beforeCreate 中調(diào)用 watchI18nData 方法,這個方法的實(shí)現(xiàn)如下:

// 為了監(jiān)聽翻譯變量的變化
watchI18nData (): Function {
  const self = this
  // 使用 vue 實(shí)例中的 $watch 方法,數(shù)據(jù)變化的時候,強(qiáng)制刷新
  // 組件的 data 選項(xiàng)是一個函數(shù)。Vue 在創(chuàng)建新組件實(shí)例的過程中調(diào)用此函數(shù)。它應(yīng)該返回一個對象,然后 Vue 會通過響應(yīng)性系統(tǒng)將其包裹起來,并以 $data 的形式存儲在組件實(shí)例中
  return this._vm.$watch('$data', () => {
    self._dataListeners.forEach(e => {
      Vue.nextTick(() => {
        e && e.$forceUpdate()
      })
    })
  }, { deeptrue })
}

其中 _dataListeners,我理解是一個個的實(shí)例(但我沒想到具體的場景,在系統(tǒng)中使用 vue-18n new 多個實(shí)例?)。subscribeDataChangingunsubscribeDataChanging 就是用來添加和移除訂閱器的函數(shù)

// 添加訂閱器,添加使用的實(shí)例
subscribeDataChanging (vm: any): void {
  this._dataListeners.add(vm)
}

// 移除訂閱器
unsubscribeDataChanging (vm: any): void {
  remove(this._dataListeners, vm)
}

它們會在 mixin.js 中的 beforeMountbeforeDestroy 中調(diào)用

// 精簡后的代碼  
// 在保證了_i18n 對象生成之后,beforeMount 和 beforeDestroy 里就能增加移除監(jiān)聽了
beforeMount (): void {
  const options: any = this.$options
  options.i18n = options.i18n || (options.__i18n ? {} : null)

  this._i18n.subscribeDataChanging(this)
},


  beforeDestroy (): void {
    if (!this._i18n) { return }
    const self = this
    this.$nextTick(() => {
      if (self._subscribing) {
        // 組件銷毀的時候,去除這個實(shí)例
        self._i18n.unsubscribeDataChanging(self)
        delete self._subscribing
      }
    })
}

總結(jié)一下,在 beforeCreate 會去 watch data 的變化,并在 beforeMount 中添加訂閱器。假如 data 變化,就會強(qiáng)制更新相應(yīng)的實(shí)例更新組件。并在 beforeDestroy 中移除訂閱器,防止內(nèi)存溢出,整體流程如下圖所示

全局自定義指令以及全局組件的實(shí)現(xiàn)

在 extent.js 中,我們提到了注冊全局指令和全局組件,我們來看下如何實(shí)現(xiàn)的

// 全局指令
Vue.directive('t', { bind, update, unbind })
// 全局組件
Vue.component(interpolationComponent.name, interpolationComponent)
Vue.component(numberComponent.name, numberComponent)

全局指令 t

關(guān)于指令 t 的使用方法,詳情參考官方文檔

以下是示例:

<!-- 字符串語法:字面量 -->
<p v-t="'foo.bar'"></p>

<!-- 字符串語法:通過數(shù)據(jù)或計(jì)算屬性綁定 -->
<p v-t="msg"></p>

<!-- 對象語法: 字面量 -->
<p v-t="{ path: 'hi', locale: 'ja', args: { name: 'kazupon' } }"></p>

<!-- 對象語法: 通過數(shù)據(jù)或計(jì)算屬性綁定 -->
<p v-t="{ path: greeting, args: { name: fullName } }"></p>

<!-- `preserve` 修飾符 -->
<p v-t.preserve="'foo.bar'"></p>

directive.js 中,我們看到實(shí)際上是調(diào)用了 t 方法和 tc 方法,并給 textContent 方法賦值。(textContent 屬性表示一個節(jié)點(diǎn)及其后代的文本內(nèi)容。)

// 主要是調(diào)用了 t 方法和 tc 方法
if (choice != null) {
  el._vt = el.textContent = vm.$i18n.tc(path, choice, ...makeParams(locale, args))
else {
  el._vt = el.textContent = vm.$i18n.t(path, ...makeParams(locale, args))
}

在 unbind 的時候會清空 textContent

全局組件 i18n

i18n 函數(shù)式組件 使用如下:

<div id="app">
  <!-- ... -->
  <i18n path="term" tag="label" for="tos">
    <a :href="url" target="_blank">{{ $t('tos') }}</a>
  </i18n>

  <!-- ... -->
</div>

其源碼實(shí)現(xiàn) src/components/interpolation.js,其中 tag 表示外層標(biāo)簽。傳 false, 則表示不需要外層。

export default {
  name'i18n',
  functionaltrue,
  props: {
    // 外層標(biāo)簽。傳 false,則表示不需要外層
    tag: {
      type: [StringBooleanObject],
      default'span'
    },
    path: {
      typeString,
      requiredtrue
    },
    locale: {
      typeString
    },
    places: {
      type: [ArrayObject]
    }
  },
  render (h: Function, { data, parent, props, slots }: Object) {
    const { $i18n } = parent

    const { path, locale, places } = props
    // 通過插槽的方式實(shí)現(xiàn)
    const params = slots()
    // 獲取到子元素 children 列表
    const children = $i18n.i(
      path,
      locale,
      onlyHasDefaultPlace(params) || places
        ? useLegacyPlaces(params.default, places)
        : params
    )

    const tag = (!!props.tag && props.tag !== true) || props.tag === false ? props.tag : 'span'
    // 是否需要外層標(biāo)簽進(jìn)行渲染
    return tag ? h(tag, data, children) : children
  }
}

注意的是:places  語法會在下個版本進(jìn)行廢棄了

function useLegacyPlaces (children, places{
  const params = places ? createParamsFromPlaces(places) : {}

  if (!children) { return params }

  // Filter empty text nodes
  children = children.filter(child => {
    return child.tag || child.text.trim() !== ''
  })

  const everyPlace = children.every(vnodeHasPlaceAttribute)
  if (process.env.NODE_ENV !== 'production' && everyPlace) {
    warn('`place` attribute is deprecated in next major version. Please switch to Vue slots.')
  }

  return children.reduce(
    everyPlace ? assignChildPlace : assignChildIndex,
    params
  )
}

總結(jié)

總體 Vue-i18n 代碼不復(fù)雜,但也花了自己挺多時間,算是一個小挑戰(zhàn)。從 Vue-i18n 中,我學(xué)習(xí)到了

  • 國際化翻譯 Vue-i18n 的架構(gòu)組織和 $t 的原理,當(dāng)遇到插值對象的時候,需要進(jìn)行 parse 和 compile
  • Vue-i18n 通過轉(zhuǎn)義字符避免 XSS
  • 通過觀察者模式對數(shù)據(jù)進(jìn)行監(jiān)聽和更新,做到無刷新更新頁面
  • 全局自定義指令和全局組件的實(shí)現(xiàn)

參考

  • https://zhuanlan.zhihu.com/p/110112552
  • https://hellogithub2014.github.io/2018/07/17/vue-i18n-source-code/


瀏覽 171
點(diǎn)贊
評論
收藏
分享

手機(jī)掃一掃分享

分享
舉報
評論
圖片
表情
推薦
點(diǎn)贊
評論
收藏
分享

手機(jī)掃一掃分享

分享
舉報

感谢您访问我们的网站,您可能还对以下资源感兴趣:

国产秋霞理论久久久电影-婷婷色九月综合激情丁香-欧美在线观看乱妇视频-精品国avA久久久久久久-国产乱码精品一区二区三区亚洲人-欧美熟妇一区二区三区蜜桃视频 91国产视频在线播放| 久久国产热| 69av电影| 亚洲性精| 男人天堂网站| 豆花成人社区,视频| 国产一级婬片A片AAA樱花| 毛片成人网| 91污视频在线观看| 一本一道波多野结衣潮喷视频 | 亚洲男同tv| 在线免费黄色网址| 亚洲va欧美va天堂v国产综合| 国产亚洲AV| 蜜桃av秘无码一区二区三区| 秋霞一区| 人妻二区| 欧美一区二区三区成人片下载| 热久久伊人| 东京热A片| 操逼超碰| 成人做爰100片免费着| 亚洲精品国产成人| 亚洲AV秘一区二区色盗战流出| 男人天堂网站| 免费在线a| 亚洲AV成人无码| 国产精品国产| 国产综合精品久久久久成人AV| 亚洲一级免费视频| Japanese在线观看| 亚洲电影AV| 午夜黄色视频在线观看| 日本熟妇无码一区二区| 国产性爱免费视频| 亚洲无吗视频| 黄色av网站在线观看| 亚洲人一级电影| 成人小视频十八禁免费观看| 人妻中文字幕网| 无码高清在线观看| 欧美精品一区二区三区成人片在线| 日日干夜夜操| 亚洲色五月| 蜜芽av在线| 欧美性爱福利| 日韩精品成人无码免费| 黑人大荫蒂女同互磨| 国产AV久久| 999大香蕉| 尤物精品在线| 黄色在线免费观看网站| 国产成人精品麻豆| 精品乱子伦一区二区三区在线播放| aaa三级片| 成人在线H| 在线黄色视频网站| 男人插女人网站| 人人妻人人操人人干| 国产黄在线| 国产精品美女久久久| 少妇高潮一区二区三区99| 无码三级在线播放| 午夜成人无码视频| 欧美日韩人妻高清中文| 日韩一区二区三区四区久久久精品有吗 | 2025中文在线观看最好看的电影 | 午夜视频在线| 麻豆传媒猫爪| 日本精品久久| 国产一区二区三区成人| 国产潮吹| 综合久久av| 狠狠操狠狠色| www插插| 东京热观看| 在线看一区二区三区| 高清无码高潮| 久久99视频免费观看| 另类老妇奶性生BBwBBw偷拍| 99热99re6国产线播放| 国产女人十八水真多| 精品热99| 新BBWBBWBBWBBW| 樱桃性爱视频| 操日本女人逼| 九九小视频| 男人的天堂免费视频| 麻豆激情视频| 欧美中文字幕在线播放| 黄色综合网| 日本无码免费视频| 99色色网| 国产精品网站在线观看| 影音先锋天堂| 亚洲婷婷在线| 亚洲v| 色就是色欧美| 日韩精品一区二区三区四在线播放 | 龙泽美曦土豪| 一本色道精品久久一区二区三区| 日韩av在线不卡| 91一区二区在线播放精品| 成人三级视频在线| 69成人| 国产精品九九九九九九| 亚洲午夜电影| 狠狠躁日日躁夜夜躁A片小说免费 色综合久久久无码中文字幕999 | 久久er99| 成人在线免费电影| 男女国产网站| 国产亚洲激情| 日韩一级欧美一级| 亚洲在线免费| 阿宾MD0165麻豆沈娜娜| 日韩中文字幕一区二区三区| 久久久久少妇| 超碰97成人| 青青操日日干| 色婷婷在线综合| 午夜69成人做爱视频网站| 久久久久久综合| 玖玖成人电影| 毛片网站在线| 久久久一区二区| 亚洲中文字幕在线观看视频网站| 大香蕉伊人网在线| 毛片小电影| 黄色成人免费视频| 人人看人人爱| 操逼在线播放| 久久久久三级片| 夜夜操夜夜操| 夫妻成人免费看片一区二区 | 亚洲黄色Av| 曰曰摸日日碰| 91人妻人人澡人人爽人人精| 色久在线| 蜜臀久久99精品久久久久久酒店| 国产熟女一区二区视频网站 | 人人天天爽| 麻豆md0049免费| 人人草人人操| 无码人妻一区二区一牛影视| 2018天天操| 久久久久久国产免费A片| 婷婷丁香五月在线| 国产黄片一区二区三区| 大香蕉东京热| 五月丁香婷婷在线| www.51av| 三级片AAA成人免费| 国际精品久久久| 狠狠做深爱婷婷久久综合一区| 亚洲日韩黄色| 久草手机视频在线观看| 一级欧美视频| 成人在线视频观看| 亚洲欧美国产另类| 国产欧美日韩综合在线视频| 国产一a毛一a免费观看| 国产精品欧美精品| 一本大道东京热av无码| 欧美日韩男女淫乱一区二区| 久久私拍视频| 黄色无码在线观看| 亚洲精品久久久蜜桃| 日本免费中文字幕| 亚洲视频一区| 99久久综合国产精品二区 | 18禁激韩| 99青草| 免费岛国av大片| 天天日穴| 久久肏逼| 亚洲欧美激情小说| 欧美日韩成人电影| 日韩精品你懂的| 91蝌蚪在线视频| 中文在线一区| 香蕉操逼视频| 日本高清无码| 亚洲性爱一区二区三区| 91丝袜在线| 色色色亚洲| 日韩在线综合| 国产一级美女操逼视频免费播放| 亚洲中文无码在线观看| 日韩无码视屏| 欧美一级大香蕉| 欧美老妇性猛交| 四虎在线视频观看96| av一区二区在线观看| 91福利视频在线观看| 黄色小视频在线免费观看| 成人精品无码| 国产寡妇亲子伦一区二区三区四区| 中文字幕无码影院| 国产三级在线观看视频| 91视频人妻| 欧美日韩操逼片| 色色五月丁香| 成人小视频18| 99热视| 操操操操一本到| 国产人妻AV| 国产啊啊啊啊| 五月天操逼网| 亚洲激情综合网| a片免费在线观看| 狼友视频免费| 中文字幕第11页| 影音先锋成人资源网| 日韩AAA| 成人一区二区电影| 黄片视频免费播放| 人妻体内射精一区二区| 三级一区二区| 狠狠干2024| 精品国产黄色| 久久久一区二区| 1024香蕉视频| 狠狠躁日日躁夜夜躁A片小说免费 色综合久久久无码中文字幕999 | 九九九中文字幕| 天天看天天干| 高圆圆一区二区三区| 超小超嫩国产合集六部| 成人午夜免费视频| 四色婷婷| 中文字幕乱码中文乱码91| 91免费视频观看| 俺来也官网欧美久久精品| 无码人妻AV一区| 欧美性性生交XXXXX无码| 久久er| 成人国产片| 成人精品一区二区区别解析| 在线观看国产免费视频| 在线亚洲免费观看| 国产精品秘久久久久久| 91在线无码精品秘入口动作 | 国产成人精品视频免费看| 四色影视| 一级成人A片| 无码一区二区北条| 波多野结衣天堂| 日韩精品中文字幕无码| 午夜性爽视频男人的天堂| 国产成人一区二区无码| 人人摸人人色| 中文字幕乱伦性爱| 国产91久久婷婷一区二区| 在线成人免费视频| 色香蕉视频在线观看| 午夜视频网站| AA黄色片| 亚洲午夜精品久久久久久APP| 亚洲黄色免费观看| 陈冠希和张柏芝mv| 中文乱码在线观看| 99看片| 麻豆中文字幕| A片操逼| 日韩欧美国产成人| 亚洲操逼网| 亚洲黄色视频在线观看网站| 97在线观看免费视频| 国精品无码人妻一区二区三区免费 | 亚洲婷婷在线视频| 加勒比无码| 亚洲香蕉av| 久久成人网豆花视频| 精品乱子伦一区二区三区| 99er这里只有精品| 综合久久亚洲| 日韩操比| 综合合一品道| 97一区二区三区| 人人操干| 免费一级大片| 丁香六月婷婷综合| 全国男人的天堂网站| 翔田AV无码秘三区| 大地8免费高清视频观看大全 | 亚洲成人情趣大香蕉| 国产毛片毛片毛片毛片毛片| 日韩小视频| 黄片网站在线免费观看| 蜜臀99久久精品久久久久久软件| 亚洲日韩国产AV| 色妞视频| 亚洲第一成人网站| 亚洲男同Gay一区二区| 北条麻妃二区| 2024av在线| 欧美成人天堂| 成人在线观看无码| 狠狠躁日日躁夜夜躁2022麻豆| 国产精品一二三| 成人午夜啪免费视频在线观看软件 | 天天干视频| 骚骚肥肥一区二区三区| 久久久久久久亚洲| 亚洲人成777| 天天添| 成人做爰免费网站2023| 综合激情AV| 免费黄色AV| 中文无码一区二区三区四区| 成人国产在线| 亚洲日韩精品成人无码专区AV| 2025天天干| 日产久久久久久| 天天射天天射| 天天干天天操综合| 国产精品视频无码| 成人网站在线| 欧美日韩小电影| 亚洲无码免费看| 国产字幕| 亚洲资源站| 九月丁香婷婷| www.久久99| 欧美日韩北条麻妃视频在线观看| 88AV在线| 欧美一级性爱在线观看| 看看AV| 99久久精彩视频| 亚洲视频成人| 麻豆传媒av| 欧美黄色录像| 人人干人| 18禁网站免费| 成人免费A片视频| 蜜桃AV在线播放| 熟女人妻一区二区三区免费看| 麻豆911| 人人操人人爽人人爱| 黄色电影中文字幕| 亚洲都市激情| 波多野结衣av中文字幕| 人妻少妇一区二区| 亚洲激情视频在线观看| 中文字幕资源站| 91老熟女视频| 成人蜜臀AV| 97午夜| 五月天黄色电影网站| 日本免费高清视频| 亚洲秘无码一区二区| 免费一级做a爱片毛片A片小说 | 国产无码久久| 男女拍拍拍拍| 蜜臀久久99精品久久久久久酒店| 亚洲精品久久久久毛片A级绿茶 | 亚洲xxxxxx| 国产一区二区三区免费| 少妇高潮日韩| 日本人妻视频| 男人天堂视频网站| 操碰在线视频| 91av久久| 日韩AV无码网站| 亚洲AV无码乱码国产精品蜜芽| 欧一美一伦一A片| 北条麻妃日B视频| 91网站在线免费观看| 人人摸人人射| 高清无码一级片| 毛片二区| 大香蕉这里只有精品| 亚洲视频日韩在线观看| 性爱视频免费| 久草视频免费在线播放| 久草久| 欧美日韩黄色极品| 日韩A片在线观看| 91麻豆视频在线观看| 色男人天堂| 欧美日韩亚洲中文字幕| 欧美,日韩,中文字幕| 一二区视频| 黄色三级片视频| 麻豆乱码国产一区二区三区| 亚洲无码高清在线视频| 狼友初视频在线观看| 一级黄色片免费| 国产精品无码一区二区三| 国产精品自拍小视频| 久久一级A片| 亚洲欧美久久| 欧美精品性爱视频| www.色在线观看| 97视频在线免费观看| 999久久久精品| 五月丁香色婷婷| HEYZO少婦AV無碼精品| 五月丁香六月情| A毛片| 国产系列第一页| 青青青操| 天天插一插| 波多野结衣Av在线| 无码视频一区| 五月乱伦| 99成人乱码一区二区三区在线 | 国产午夜精品一区二区三区嫩A| 免费一区二区三区四区| 欧美一级婬片AAAAAA片| 亚洲一区色| 人妻av在线| 东方av在线播放| 一本一道vs波多野结衣| 免费黄色视频观看| 欧美偷拍一区| 婷婷五月天在线观看| 波多野结衣久久中文字幕| 中文字幕无码乱伦| 在线你懂| 91精品无码一区二区| 人妻丝袜蕾丝高跟双飞| 国产99re| 日本黄色视频网| 久久亚洲福利视频| 中文在线字幕高清电视剧| 日韩欧美三级在线| 免费观看黄色视频| 小黄片在线看| 亚洲天堂一| 91青青草| 伊人小视频| 久久久91人妻无码精品蜜桃ID| 精品第一页| 亚洲黄片免费在线观看| 婷婷成人综合网| 大香蕉在线视频99| 色色色色五月天| www.俺去啦| 亚洲在线| 国产免费a| 久久久77| 青娱乐黄片| 国产乱国产乱300精品| 91污视频在线观看| 18禁网站网址| 久久美女视频| 午夜资源网| 免费+无码+精品| 亚洲vs无码秘蜜桃少妇| 日韩爱爱网站| 影音先锋久久久久AV综合网成人| 玩弄小怮女在线观看| 嫩草视频网站| 亚洲人人18XXX—20HD| 天天操天天操| 特级西西44www无码| 极品少妇av| 在线观看2区| 首页-91n| 91国产在线播放| 特黄特色免费视频| jizz国产| 成人激情在线观看| 国产操逼大片| 久久国产精品在线| 激情六月婷婷| 国产视频一区二区三区四区五区| 男女一区二区| 欧美成人看片| 色婷婷国产| 成人中文字幕在线观看| 黄色毛片在线播放| 一级黄片免费看| 无码理论片| 色综合婷婷| 中文原创麻豆传媒md0052| 中国女人操逼视频| 97精品人人妻人人| 亚洲在线资源| 国产国产国产在线无码视频| 一区色| 亚洲无码视频一区二区| 岛国AV免费在线| 国产男女av| 国产高清视频在线观看| 久热福利| 亚洲人免费视频| 黄色一级在线| 五月天婷婷影院| 黄色视频在线免费播放| 悠悠久久久| 乱伦91视频| 大香蕉一区二区| 伊人精品视频| 免费无码又爽又黄又刺激网站| 欧美一区二区精品| 大香蕉一级红色片青青河边草| 日韩精品网| 日韩精品一区二区三区黄冈站长 | 国产精品免费一区二区三区四区视频 | www.俺去啦| 玖玖爱av| 在线观看黄色小视频| 国产精品免费观看视频| 亚洲AV一二三区| 黄色香蕉网站| 三级片AAA成人免费| 西西444WWW大胆无视频软件亮点 | 天天澡天天爽日日AV| 人人爽人人澡| 操逼视频网址| 黄色一级片在线| 五月丁香在线播放| 91无码视频| 免费乱伦| 日韩午夜av| 精品777| 伊人久久久影视大全| 脓肿是什么原因引起的,该怎么治疗| 青青成人| 日韩毛片在线播放| 一级免费片| 操逼网123首页| 中文字幕免费看高清| 欧一美一婬一伦一区| 91视频色| 欧美日日干| 日日夜夜精选视频| 91精品国产综合久久久蜜臀图片| 成人性生活A级毛片网站| 日本无码电影| 免费黄片视频在线观看| 亚洲精品秘一区二区三区在线观看 | 免费一级做a爱片毛片A片小说| 欧美成人三级精品| 在线观看18s| 老熟女--91XX| 人妻无码中文久久久久专区| 一级黄色片免费看| 九九热免费视频| 一区二区三区无码高清| 国产欧美日韩视频| 天堂无码高清| 丁香五月天色婷婷| 九色视频在线观看| 国产成人精品一区二区三区在线 | 亚洲自拍无码| 中文字幕在线播放视频| 青青草狠狠干| 无码视频一二三区| 国产精品视频一区二区三区在线观看| 丁香婷婷色五月| 亚洲性爱中文字幕| 国产在线高潮| 国产成人无码AⅤ片免费播放| 亚洲精品国产精品国自产| 国产无码电影网| 波多野结衣网| 强伦轩人妻一区二区三区最新版本更新内容| 精品人妻一区二区| 中文字幕精品亚洲熟女| 日韩AV小电影| 蜜桃传媒视频| 久久九一| 竹菊av一区二区三区四区五区| 中文字幕一区二区三区人妻在线视频| 国产三级在线| 国产XXXX| 国语对白做受欧美| 东京热在线免费观看| 亚洲激情片| 岛国AV片| 在线三级片视频| 91视频在线观看免费大全| 欧美性爱免费在线视频| 免费看AV大片| 牛牛av| jizzjizz国产| av不卡在线| 天天综合精品| 超碰久操| 韩国三级HD久久精品HD| 先锋影音资源AV| 亚洲三级无码在线| 国产第页| 国产精品国产三级国产专区52| 色色丁香五月天| 亚洲AV秘一区二区色盗战流出| 熟女一区| 99热超碰| 亚洲一级av| 免费成人黄片| 亚洲清高毛无码毛片| 国产色色色色| 亚洲春色一区二区三区| 人人干人人干人人干| 韩国三级HD中文字幕的背景音乐| 老太老熟女城中层露脸60| 天天日天天操天天爽| 麻豆天美蜜桃91| 波多野结衣Av在线| wwwxx在线观看| 亚洲综合p| 日韩欧美一区二区三区不卡| 97人人干| 亚洲操| 苍井空无码| 在线一区二区三区四区| 色婷婷国产| 男女操网站| 成人黄片视频| 成人做爰黄AA片免费看三区 | 波多野结衣一区| 成人网站免费在线| 亚洲日韩国产AV无码无码精品 | 操逼视频在线看| 国产精品夜夜爽7777777| 欧美日韩国产中文字幕| 九色PORN视频成人蝌蚪自拍| 超碰成人97| 亚洲成年视频| 免费看毛片网站| 做爰视频毛片下载蜜桃视频| 色天堂在线观看视频| 欧美成人看片黄a免费看| 大香蕉98| 老熟女伦一区二区三区| 99免费热视频在线| 欧美日韩国产成人综合| 亚洲成年人在线| 激情五月天综合网| 高清无码在线免费视频| 免费人成在线观看视频播放| 精品国产一级| 亚洲精品高清视频| 国产av二区| av天堂资源在线| 激情小视频在线观看| 波多野结衣精品无码| 欧美性爱AAA| 男女性爱视频网站| 狠狠狠狠狠狠狠狠狠狠| 91高潮久久久久久久| 黄色免费AV| 69福利| 荫蒂添的高潮免费视频| 国产午夜精品一区二区三区嫩A| 丁香五月天激情网| 丰满人妻一区二区三区四区不卡| 乱伦激情视频| 极品少妇久久久| 91大香蕉伊人| 国产噜噜噜噜久久久久久久久 | 国产色黄视频| 一本久道综合| 中国熟女视频| 亚洲精品另类| 中文字幕第一页亚洲| 熟妇操逼视频| 无码在线播放视频| 大屌在线| 超碰九色| 色色五月天网站| 久久久免费观看视频| 人人干人人上| 中文子幕免费毛片| 东方a在线| 国产精品欧美一区二区三区苍井空| 成人动漫一区二区| 色欲av伊人久久大香线蕉影院| 嫩小槡BBBB槡BBBB槡漫画 | 天天色色综合| 国产精品永久免费| 亚洲秘无码一区二区三区av| 丁香六月激情| 高清无码在线免费观看| 色高清无码免费视频| 天天狠天天干| 国产一区免费视频| 日韩Va| 欧美精品久久久久久久久| 国产色拍| 天天看毛片| 婷婷狠狠操| 婷婷色AV| 精品一区二区三区免费毛片| 日韩高清一区二区| 国产无码久久| 欧美999| 日韩中文性受视频| 日韩无码黄色片| 久热中文在线观看精品视频| 免费在线观看黄色网址| WWW.99热| 人妻熟女在线| 日韩精品一区二区在线观看| 三根一起进菊眼| 特级西西WWW444人体聚色| 99热网站| 中文字幕在线看| 一区性爱| 91久久久久久久久久久| 在线观看中文字幕网站| 99国产免费| 黄片视频免费播放| 18禁激韩| 国产黄色在线免费观看| 外国一级片| 91综合网| 中文字幕高清无码免费视频| 中文字幕精品综合| 人妻熟女在线视频| H网站在线观看| 亚洲精品女人久久久| 性饥渴熟妇乱子伦| 麻豆精品在线| 97成人视频| 夜夜撸| 青青草手机视频在线| 黃色毛片A片AAAA级20| 无码视频中文字幕| 嘉兴少妇按摩69XX| 六月丁香视频| 久久国产精品网站| 午夜黄色| 欧美成人精品a| 免费高清无码在线| 亚洲熟妇AV日韩熟妇在线| 美女乱伦视频| 丁香五月天在线| 老熟女露脸25分钟91秒| 玩弄小怮女在线观看| 一级大毛片| 乱伦91视频| 无码视频中文字幕| 亚洲欧美第一页| 亚洲AV成人无码精品直播在线 | 99黄色视频| 久久精品一区二区三区四区五区| 黑人无码一二三四五区| 97人妻一区二区精品免费视频| 日本在线网站| 国产TS在线| 国产在线观看黄色| 日本中文在线| 青青草免费在线视| 色婷婷中文在线| 天天爆操| 欧美性性生交XXXXX无码| 午夜精品18视频国产17c| 久草视频免费在线观看| 国产乱婬片视频| 久久久久亚洲AV无码成人片| 激情爱爱网| 无码人妻精品一区二区蜜桃91| 日韩一级欧美一级| ⅴA日本成人| 国产一二三区在线| 久久色片| 2022黄片| 亚洲女人被黑人巨大进入| 91亚洲视频| 久久成人一区| 国内精品久久久久久久久久变脸| 天堂资源中文在线| 91夫妻视频| 高清免费无码| 日韩三级一区二区| 丁香六月久久| 中文字幕2025年最好看电视剧| 午夜高清无码| 风情万种AV| jizz免费观看| 精品动漫3D一区二区三区免费版 | 欧美视频在线观看一区| 亚洲区中文字幕| 午夜成人视频| 黄片视频在线观看| 一本色道久久综合狠狠躁| 亚洲精品女人| 亚洲免费观看高清完整版在va线 | 欧美成人午夜无码A片秀色直播| 69AV视频网站| 欧美A级成人婬片免费看| 乱子伦国产精品一区二区| 日韩一级欧美一级| 久久久久久久香蕉视频| 先锋AV资源网| a片视频网站| 欧美v在线| 佳佳女王footjob超级爽| www.蜜桃av| 日本欧美在线播放中文| 国产中文字幕在线视频| 欧美色性乐汇操日本娘们| 一级婬片A片AAAAA毛片| 久久婷婷五月综合伊人| 欧美色图另类| 人人操人人妻| 国产精品高清网站| 91精品在线观看视频| 中文字幕性爱| 精品无码一区二区三区四区久久久软件| 成人做爰100片免费着| 欧美成人在线免费视频| 欧美黄色小视频| 中字一区人妻水多多| 国产成人无码精免费视频| 国产精品免费人成人网站酒店| 日韩一级网站| 午夜福利av在线| 日韩精品无码AV| 成人三级片视频| 亚洲无码在线播放| 日本三级网站| 欧美怡红院视频| 熟女少妇视频| 天堂中文资源在线| 蕉久中文字慕| 免费视频久久久| 国产视频在线播放| 丝瓜视频| 亚洲高清人妻| 色色网站在线观看| 中文字幕2025年最好看电视剧| 成人欧美一区二区三区黑人免费 | 蜜桃AV在线观看| 99九九精品| 亚洲综合日韩在线| 成人黄片在线免费观看| 激情午夜av| 一本色道久久综合无码欧美| 国产黄色大片| av无码不卡| 国产成人性爱| 大香蕉一区二区三区| 无码999| 国产精品福利导航| 人人操人人干人人摸| 久久亚洲福利视频| 伊人成人免费视频| 黄色a片视频| 人人免费操| 无码人妻av黄色一区二区三区| 日本一区二区三| 在线国产激情| 91在线| 国产精品久久| 日韩毛片一区二区| 中文字幕第69页| 人人妻人人澡人人爽| 婷婷五月亚洲精品AAA片在 | 欧美一本在线| av无码观看| 精品无码久久久久久久久app | 久久久91人妻无码精品蜜桃ID | 日韩一级在线视频| 亚洲天堂2016| 免费十无码| 日韩成人无码AV| 中文字幕精品一区久久久久| 色噜噜狠狠一区二区三区牛牛影视| 爱搞搞就搞搞| 中文字幕亚洲中文字幕| 亚洲欧美第一页| 77777免费观看电视剧推荐爱的教育 | 无码东京热国产| av手机在线| 久久一级视频| 狠狠狠久久久| 国产A级片| 国产不卡在线| 操逼操逼操逼操逼操逼操逼| 懂色av懂色av粉嫩av无码| 国产a级毛片| 日韩在线视频第一页| 99视频在线看| 亚洲一区中文字幕成人在线| 天天激情站| 人人插人人干| 亚洲视频综合网| 免费视频久久| 久操免费视频| 国产天堂在线观看| 精品无码在线| 无码不卡视频在线| 日产电影一区二区三区| 亚洲AV成人片无码网站| 久久五月天综合| 亚洲精品娱乐| 亚洲AV三级片| 久久久久久免费毛片精品| 色五月激情五月| 先锋AV资源网| 色呦呦一区二区三区| 免费中文字幕视频| 天天天天天天天干| 黄色三级视频在线观看| 三级片AV在线| 丁香五月天网站|