1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        你是如何設(shè)計(jì)一個(gè)可擴(kuò)展、通用的、健壯性組件!

        共 21951字,需瀏覽 44分鐘

         ·

        2021-08-13 16:12

        點(diǎn)擊上方 前端瓶子君,關(guān)注公眾號(hào)

        回復(fù)算法,加入前端編程面試算法每日一題群

        前言

        組件是頁面不可或缺的部分,而設(shè)計(jì)組件就成為了前端同學(xué)每日工作。

        所以

        一位程序員的職業(yè)生涯大約十年,只有人壽命的十分之一。前端項(xiàng)目只是你生活工作的一部分,而你卻是它的全部,你是他的靈魂。請(qǐng)放下長時(shí)間的游戲、工作時(shí)的摸魚。多學(xué)習(xí)來以最完美的狀態(tài)好好陪你項(xiàng)目!

        正文

        這篇文章將會(huì)以本人所認(rèn)知的角度去對(duì)組件的封裝設(shè)計(jì)展開思考。如果你對(duì)我的觀點(diǎn),方式,又或者你有更好的方式,更優(yōu)的設(shè)計(jì)模式,不妨在評(píng)論區(qū)一起討論 思考, 交流是進(jìn)步的必經(jīng)之路。

        知識(shí)點(diǎn)

        • 組件是如何分類的
        • Vue 和 React 封裝組件模式
        • 怎樣才是一個(gè)好的可擴(kuò)展、通用的、健壯性組件
        • 思考討論,提出問題

        組件是如何分類的

        • 業(yè)務(wù)組件
        • 通用組件(非業(yè)務(wù)組件)
          • UI組件
        1627627583874_8398E85B-D83D-430B-AF41-D4D3F8CF04C0.png

        無論是 業(yè)務(wù)組件 或者 通用組件都具備組件本質(zhì)所包含的三個(gè)性質(zhì)擴(kuò)展、通用健壯

        • 擴(kuò)展性:在原有組件基礎(chǔ)上可 二次封裝 擴(kuò)展成新的組件符合設(shè)計(jì)的開閉原則

        • 通用性:根據(jù)組件接受的參數(shù)組件中與業(yè)務(wù)的解耦比來衡量組件的通用性,并不是通用性占比100%的組件就是最好的組件,需要根據(jù) 不同的場景 分析

        • 健壯性:避免組件中參數(shù)處理函數(shù)執(zhí)行過程可能出現(xiàn)的奔潰和錯(cuò)誤導(dǎo)致程序的直接掛斷,單測以對(duì)組件內(nèi)部 做好邊界處理,異常錯(cuò)誤的捕獲來衡量這一標(biāo)準(zhǔn)

        業(yè)務(wù)組件

        服務(wù)與業(yè)務(wù)的組件稱為業(yè)務(wù)組件,項(xiàng)目中組件的劃分是分頁面級(jí)組件、全局級(jí)別組件

            --- componentes
            --- pages
        復(fù)制代碼

        而結(jié)構(gòu)一般是這樣

        componentes 中存放的組件往往 具有當(dāng)前項(xiàng)目 中的多個(gè) 場景 復(fù)用 才會(huì)進(jìn)行設(shè)計(jì)與封裝

        Vue中的組件

        <template>
            ....
        </template>
        <script>
        export default {
          props: {
            ...
          },
          data () {
            ....
          },
          methods: {
            ....
          }
        }
        </
        script>
        復(fù)制代碼

        React中的組件

        import React, { Component } from 'react';
        export default class Demo extends Component {
            state = {
            };

            componentDidMount() {
              ...
            }

            render() {
              const { .... } = this.props;
              return (
                <div>
                  ....
                </div>

              );
            }
        }
        復(fù)制代碼

        這是目前兩個(gè) 兩個(gè)框架最基本的組件封裝 模板

        而你在封裝組件的時(shí)候是否考慮過一些問題

        • 組件的可維護(hù)性?
        • 組件的可讀性?
        • 擴(kuò)展性、健壯性、通用性?
        • 這個(gè)組件是否需要封裝抽離?
        • 組件是否和業(yè)務(wù)強(qiáng)關(guān)聯(lián)?

        這些問題在組件封裝開始編碼之前你是否都考慮過了

        凡是組件不斷擴(kuò)展,使其通用性提升,必然就會(huì)降低組件的 易用性質(zhì)

        而不斷豐富一個(gè)組件,也會(huì)導(dǎo)致其組件代碼過長,組件使命不單一,不易讀,不易維護(hù)

        像Vue 和 React 推薦 一個(gè)組件代碼長度在 200 - 500 行最佳

        業(yè)務(wù)中的組件往往區(qū)分

        1627627666905_1E9DC37D-8E0E-45C7-814A-63CA34D3936C.png
        • 容器組件負(fù)責(zé)處理業(yè)務(wù)相關(guān)邏輯,注冊業(yè)務(wù)相關(guān)鉤子,傳入相應(yīng)的熟悉和插槽等
        • 視圖組件則負(fù)責(zé)數(shù)據(jù)的呈現(xiàn),交互的實(shí)現(xiàn)
        1627634474901_9F20476A-9B8A-4360-A907-C79218F72E55.png

        容器組件往往不可復(fù)用

        視圖組件則根據(jù)組件的樣式交互 判斷組件在項(xiàng)目中的 頻率 來抉擇是否封裝

        視圖數(shù)據(jù) 解耦 又能搭配 可以很好的提升組件的 可讀,易維護(hù)性

        這個(gè)組件是否需要封裝抽離?

        這可能是新前端同學(xué)容易遇到的問題

        不是所以 DOM 結(jié)構(gòu) 都需要 抽離

        你需要對(duì)你所負(fù)責(zé)的項(xiàng)目 UI走向 有著全局的洞察力,如果不確認(rèn)的是否需要封裝,建議不封裝

        下次業(yè)務(wù)中存在與原來視圖 UI 相同的需求 再進(jìn)行封裝設(shè)計(jì),而不是快速 Copy

        組件是否和業(yè)務(wù)強(qiáng)關(guān)聯(lián)?

        通常情況,組件中的大量數(shù)據(jù)來源 當(dāng)前組件的接口請(qǐng)求。沒有依賴或者幾乎不依賴外部傳入的props等,稱為業(yè)務(wù)強(qiáng)關(guān)聯(lián)組件,放棄組件封裝的想法。

        怎樣才是一個(gè)好的可擴(kuò)展、通用的、健壯性組件?

        我們可以參考一下star高的 Ant designElement 來學(xué)習(xí)

        Ant design 中 rc-switch

        import * as React from 'react';
        import classNames from 'classnames';
        import useMergedState from 'rc-util/lib/hooks/useMergedState';
        import KeyCode from 'rc-util/lib/KeyCode';

        const Switch = React.forwardRef(
          (
            {
              prefixCls = 'rc-switch',
              className,
              checked,
              defaultChecked,
              disabled,
              loadingIcon,
              checkedChildren,
              unCheckedChildren,
              onClick,
              onChange,
              onKeyDown,
              ...restProps
            },
            ref,
          ) => {
            const [innerChecked, setInnerChecked] = useMergedState<boolean>(false, {
              value: checked,
              defaultValue: defaultChecked,
            });

            function triggerChange(
              newChecked: boolean,
              event: React.MouseEvent<HTMLButtonElement> | React.KeyboardEvent<HTMLButtonElement>,
            
        {
              let mergedChecked = innerChecked;

              if (!disabled) {
                mergedChecked = newChecked;
                setInnerChecked(mergedChecked);
                onChange?.(mergedChecked, event);
              }

              return mergedChecked;
            }

            function onInternalKeyDown(e{
              if (e.which === KeyCode.LEFT) {
                triggerChange(false, e);
              } else if (e.which === KeyCode.RIGHT) {
                triggerChange(true, e);
              }
              onKeyDown?.(e);
            }

            function onInternalClick(e{
              const ret = triggerChange(!innerChecked, e);
              // [Legacy] trigger onClick with value
              onClick?.(ret, e);
            }

            const switchClassName = classNames(prefixCls, className, {
              [`${prefixCls}-checked`]: innerChecked,
              [`${prefixCls}-disabled`]: disabled,
            });

            return (
              <button
                {...restProps}
                type="button"
                role="switch"
                aria-checked={innerChecked}
                disabled={disabled}
                className={switchClassName}
                ref={ref}
                onKeyDown={onInternalKeyDown}
                onClick={onInternalClick}
              >

                {loadingIcon}
                <span className={`${prefixCls}-inner`}>
                  {innerChecked ? checkedChildren : unCheckedChildren}
                </span>
              </button>

            );
          },
        );

        Switch.displayName = 'Switch';

        export default Switch;
        復(fù)制代碼
        • 直接脫離 UI
        • 接受參數(shù),處理鉤子

        Ant design 則是對(duì)API 和 UI 的二次封裝

        進(jìn)而體現(xiàn)了 React Components[1] 的組件的 可擴(kuò)展性

        再看看

        Element UI 的 Switch

        <template>
          <div
            class="el-switch"
            :class="{ 'is-disabled': switchDisabled, 'is-checked': checked }"
            role="switch"
            :aria-checked="checked"
            :aria-disabled="switchDisabled"
            @click.prevent="switchValue"
          >

            <input
              class="el-switch__input"
              type="checkbox"
              @change="handleChange"
              ref="input"
              :id="id"
              :name="name"
              :true-value="activeValue"
              :false-value="inactiveValue"
              :disabled="switchDisabled"
              @keydown.enter="switchValue"
            >

            <span
              :class="['el-switch__label', 'el-switch__label--left', !checked ? 'is-active' : '']"
              v-if="inactiveIconClass || inactiveText">

              <i :class="[inactiveIconClass]" v-if="inactiveIconClass"></i>
              <span v-if="!inactiveIconClass && inactiveText" :aria-hidden="checked">{{ inactiveText }}</span>
            </span>
            <span class="el-switch__core" ref="core" :style="{ 'width': coreWidth + 'px' }">
            </span>
            <span
              :class="['el-switch__label', 'el-switch__label--right', checked ? 'is-active' : '']"
              v-if="activeIconClass || activeText">

              <i :class="[activeIconClass]" v-if="activeIconClass"></i>
              <span v-if="!activeIconClass && activeText" :aria-hidden="!checked">{{ activeText }}</span>
            </span>
          </div>
        </template>

        <script>
          import emitter from 'element-ui/src/mixins/emitter';
          import Focus from 'element-ui/src/mixins/focus';
          import Migrating from 'element-ui/src/mixins/migrating';
          export default {
            name'ElSwitch',
            mixins: [Focus('input'), Migrating, emitter],
            inject: {
              elForm: {
                default''
              }
            },
            props: {
              value: {
                type: [BooleanStringNumber],
                defaultfalse
              },
              disabled: {
                typeBoolean,
                defaultfalse
              },
              width: {
                typeNumber,
                default40
              },
              activeIconClass: {
                typeString,
                default''
              },
              inactiveIconClass: {
                typeString,
                default''
              },
              activeTextString,
              inactiveTextString,
              activeColor: {
                typeString,
                default''
              },
              inactiveColor: {
                typeString,
                default''
              },
              activeValue: {
                type: [BooleanStringNumber],
                defaulttrue
              },
              inactiveValue: {
                type: [BooleanStringNumber],
                defaultfalse
              },
              name: {
                typeString,
                default''
              },
              validateEvent: {
                typeBoolean,
                defaulttrue
              },
              idString
            },
            data() {
              return {
                coreWidththis.width
              };
            },
            created() {
              if (!~[this.activeValue, this.inactiveValue].indexOf(this.value)) {
                this.$emit('input'this.inactiveValue);
              }
            },
            computed: {
              checked() {
                return this.value === this.activeValue;
              },
              switchDisabled() {
                return this.disabled || (this.elForm || {}).disabled;
              }
            },
            watch: {
              checked() {
                this.$refs.input.checked = this.checked;
                if (this.activeColor || this.inactiveColor) {
                  this.setBackgroundColor();
                }
                if (this.validateEvent) {
                  this.dispatch('ElFormItem''el.form.change', [this.value]);
                }
              }
            },
            methods: {
              handleChange(event) {
                const val = this.checked ? this.inactiveValue : this.activeValue;
                this.$emit('input', val);
                this.$emit('change', val);
                this.$nextTick(() => {
                  // set input's checked property
                  // in case parent refuses to change component's value
                  this.$refs.input.checked = this.checked;
                });
              },
              setBackgroundColor() {
                let newColor = this.checked ? this.activeColor : this.inactiveColor;
                this.$refs.core.style.borderColor = newColor;
                this.$refs.core.style.backgroundColor = newColor;
              },
              switchValue() {
                !this.switchDisabled && this.handleChange();
              },
              getMigratingConfig() {
                return {
                  props: {
                    'on-color''on-color is renamed to active-color.',
                    'off-color''off-color is renamed to inactive-color.',
                    'on-text''on-text is renamed to active-text.',
                    'off-text''off-text is renamed to inactive-text.',
                    'on-value''on-value is renamed to active-value.',
                    'off-value''off-value is renamed to inactive-value.',
                    'on-icon-class''on-icon-class is renamed to active-icon-class.',
                    'off-icon-class''off-icon-class is renamed to inactive-icon-class.'
                  }
                };
              }
            },
            mounted() {
              /* istanbul ignore if */
              this.coreWidth = this.width || 40;
              if (this.activeColor || this.inactiveColor) {
                this.setBackgroundColor();
              }
              this.$refs.input.checked = this.checked;
            }
          };
        </script>

        復(fù)制代碼

        很直觀的看出, 除了語法 方面 封裝設(shè)計(jì)組件UI的最佳方式

        • 零業(yè)務(wù)代碼
        • 優(yōu)秀的UIAPI設(shè)計(jì)
        • 易學(xué)易用

        我們再看看另外一種封裝組件的方式

        1627634757928_22274B24-4A7F-4B1B-8307-3A565B77A956.png

        React For Menu

        carbon (1).png

        這是 React 配套組件的封裝 的一種思路

        • 創(chuàng)建 context 管理 組件組 的數(shù)據(jù)流
        • 父組件中存在判斷 子組件的類型 增加健壯性
        • index 掛載 分別導(dǎo)出組件

        Vue For Menu

        <template>
            <div
            class="menu"
            // 事件綁定
            >

              // menuItem
              <slot></slot>
            </div>

        </template>

        <script>
        export default {
            mixins: [...],
            name: 'Menu',
            componentName: 'Menu',
            inject: {
              menu: {
                default: ''
              },
            },
            provide() {
              return {
                'menu': this
              };
          }
        }
        </
        script>
        復(fù)制代碼

        Vue \- UI 組件的設(shè)計(jì)封裝中 , 經(jīng)常使用 provide,inject來組件通信.

        Vue 除了使用 slot 還可以使用 jsx & function component 來實(shí)現(xiàn)如此效果,其設(shè)計(jì)思想和 React 大同小異

        Vue3Ant design for Vue 中大量使用 jsx 來 封裝 組件

        下面簡單總結(jié)一下

        • 組件中的 UI數(shù)據(jù) 業(yè)務(wù)盡量 分離
        • UI視圖 組件中 不該包含 業(yè)務(wù)代碼
        • 組件設(shè)計(jì)之初考慮通用、易用、擴(kuò)展、健壯穩(wěn)定 以及 良好的代碼結(jié)構(gòu)、Api設(shè)計(jì)使用

        思考討論,提出問題

        • 你有不同的或者更好的設(shè)計(jì)封裝組件的技巧Demo
        • 你是如何判斷組件是否封裝的?如何設(shè)計(jì)組件的?
        • 回想一下你設(shè)計(jì)的組件 代碼、Api、命名 是否給其他同學(xué)帶來不便
        • 等等.....

        根據(jù)以上的問題思考 或者 你有不同的想法 不妨在評(píng)論區(qū)中我們一起探討,學(xué)習(xí)!


        關(guān)于本文

        來源:遇見同學(xué)

        https://juejin.cn/post/6991261103141421092


        最后

        歡迎關(guān)注【前端瓶子君】??ヽ(°▽°)ノ?
        回復(fù)「算法」,加入前端編程源碼算法群,每日一道面試題(工作日),第二天瓶子君都會(huì)很認(rèn)真的解答喲!
        回復(fù)「交流」,吹吹水、聊聊技術(shù)、吐吐槽!
        回復(fù)「閱讀」,每日刷刷高質(zhì)量好文!
        如果這篇文章對(duì)你有幫助,在看」是最大的支持
         》》面試官也在看的算法資料《《
        “在看和轉(zhuǎn)發(fā)”就是最大的支持


        瀏覽 37
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            免费在线看黄色| 一区二区经典| 蜜桃视频91| 国产高清av| 亚洲精品午夜福利| 俺也去在线视频| 中文√在线天堂8| 精品无码一区二区三区四区久久久软件| 嫩草在线精品| 在线观看黄网| 日本亲子乱婬一级A片| 欧美va亚洲va| 国产—级a毛—a毛免费视频| 一道本无码免费视频| 九九久久国产精品| 欧美激情四射老司机| 五月丁香在线| 国产熟妇| 国产免费视频| 久久综合99| 在线视频一区二区三区| 婷婷久久久久| 操大爷影院| 日本三级中文字幕| 成人av中文字幕| 91探花秘在线播放偷拍| av青青草原| 成人在线毛片| 麻豆传媒一区二区| 亚洲无码资源| 亚洲天堂视频在线播放| 国产精品秘ThePorn| 欧美成人免费在线| 亚洲AV成人片色在线观看高潮| 亚洲三级黄片| 欧美久久性爱视频| 淫色AV| 日韩无码黄色电影| 蜜桃视频成人版网站| 成人国产精品秘欧美高清| 国产无遮挡又黄又爽在线观看| 性爱AV在线观看| 色人阁人妻中文字幕| 久久午夜无码鲁丝片午夜精品偷窥| 久久大香蕉视频| 一级免费毛片| 91视频网| 91香蕉视频在线| 久操网站| 精品乱子伦一区二区三区,亚洲国产成| 9久热| 黄色免费网站| 国产精品国产精品国产| 一级黄色毛片| 亚洲日本黄色网址| 国产欧美精品成人在线观看| 白浆四溢av| 亚色网址| 无码日韩AV| 成人网一区二区| 韩国午夜福利视频| 久久黄色视频免费看| 久久久久人| 欧美XXXXBBBB| 影音先锋女人aV鲁色资源网站| 成人性生交大片免费看小芳| 日日夜夜超碰| 成人黄色一级A片| 高清在线无码视频| 走光无码一区二区三区| 国产99久久| 老司机精品| 国产视频h| 色网站操逼| 欧美在线免费视频| 欧美亚洲成人网| 国产小视频在线播放| 亚洲小说欧美激情另类A片小说 | 久久yzy| 五月婷婷AV| 欧美操逼网| 中文字幕av高清片,中文在线观看 www一个人免费观看视频www | 黄片网址在线观看| 国产又粗又大又爽| 高清无码视频免费看| 狠狠干2024| 一区二区三区四区五区| 青青在线免费视频| 亚洲熟妇视频| 中文有码在线| 黄色成人网站在线| 国产三级自拍视频| 无码A片| 中文字幕不卡| 韩国午夜电影| 天天综合字幕一区二区| 午夜无码免费| 波多野结衣视频无码| 国产三级一区二区| 成人精品秘免费波多野结衣| 在线视频一区二区三区四区| 各国熟女HD合集| 91网站免费看| 一级理论片| 激情视频网址| 99热这里有精品| A片观看视频| 翔田千里无码视频| 亚洲秘无码一区二区| 精品三级网站| 国产乱人伦无码视频| 肏逼网址| 亚欧成人| 无码专区视频| 国产精品视频免费| 中文午夜福利| 夫妻无码| 精品国产一二三区| 黑人一区二区三区四区| 成人免费精品视频| 开心五月激情婷婷| 亚洲天堂色| 日本爱爱网站| 超碰人人在线| 成人国产片女人爽到高潮| 狠狠干老司机| 日韩欧美三级在线| www俺来也com| 久久精品91| 亚洲成人av在线观看| 激情欧美| 浪潮在线观看完整版| 亚洲欧美手机在线| 老司机午夜免费精品视频| 人与禽一级A片一区二区三区| 成人爱爱免费视频| 91蜜桃精品| 亚洲视频综合| 久久青青| 国产91综合一区在线观看| 婷婷综合av| www.199麻豆在线观看网站| 毛片成人网| JiZZjiZZ亚洲成熟熟妇| 伊人久久影院| 欧美日逼超碰| 开心色播五月天| 18禁网站免费观看| www.丁香五月| 色五月中文字幕| 成人毛片18女人毛片| 亚洲看片| 国产黄色a片| TheAV精尽人亡av| 欧美在线无码| 亚洲AV成人精品一区二区三区 | 激情无码五月天| 婷婷丁香五月网| 黑人精品| 学生妹一级片| 日韩激情| 99精品六月婷婷综合在线| 吴梦梦无码| 丰满熟妇人妻无码视频| 手机在线看A片| 91人妻人人澡人人爽人人| 五月丁香六月| 国产国产国产在线无码视频| 国产精品秘国产精品88| 国产亚洲天堂| 亚洲久草| 欧美日韩国产高清| 影音先锋无码AV| 亚洲第一成人久久网站| 国产免费观看视频| 一区二区无码精品| 91香蕉麻豆| 欧美伊人网| 奇米影视av| chinese高潮老女人| 成年人在线播放| 国产AⅤ爽aV久久久久成人| 日韩欧美一级片| 天天爽天天爽夜夜爽| 免费看黄色AV| 先锋影音av资源站| 亚洲影院在线观看| 中文字幕无码视频| 国产精品久久77777| 91人妻人人爽人人澡| 国产AV黄片| 日韩高清无码一区二区| S牛牛AV| 先锋影音资源一区| 在线观看av网站| 婷婷成人电影| 国产成人秘在线观看免费网站| 在线视频三区| 亚洲午夜激情电影| 久久嫩草国产成人一区| 成人无码网站| chip少妇性| 国产一区二区不卡视频| 亚洲中文字墓| 手机看片日韩| 亚洲激情| 五月天啪啪视频| 激情婷婷综合| 亚洲专区视频| 日韩AAA在线| 国产在线拍揄自揄拍无码男男| 亚洲乱伦图片| 伊人99热| 成人伦理聚合| 夜夜爽7777精品国产三级| 牛牛免费视频| 超碰免费在线观看| AAA级片| 一区二区经典| 日韩在线视频免费| 中文字幕在线免费| 黄色成人网站大全| 我要操影院| 日本黄色一级视频| 北条麻妃久久网站| 91精品视频在线免费观看| jizz麻豆| 有码中文字幕| 欧美三级在线观看视频| 亚洲色欲av| 国产毛片在线看| 91视频爱爱| 亚洲日逼网| 青青草原成人| 黄片免费观看| 欧美性爱AAA| 亚洲免费观看高清完整版在线| 嫩草av| 伊人在线综合| 激情六月丁香| 免费a在线观看| 97精品人妻麻豆一区二区| 亚洲少妇熟女| 91超碰在线免费观看| 丁香五月激情中文字幕| 欧美成人性爱在线| 久久九九国产| 香蕉日逼| 午夜亚洲无码| 最近2019中文字幕mv第三季歌词| 亚洲在线观看视频| 欧美一级生活片| 国产成人免费做爰视频| 久热超碰| 在线免费观看av片| 国产va在线| 日韩天堂| 乱伦小说五月天| 另类老太婆性BBWBBw| 成人精品18| 高清不卡一区二区| 无码偷拍| 香蕉日逼| 成年人视频免费| 国产成人无码免费看片| 久久久久久久久久久久久自慰小片 | 东北女人毛多又黑A片| 久久成人三级片| 欧美三级片视频| 老熟女网站| 天天综合7799| 黑人无码| 精品91在线视频| 蜜桃视频一区二区| 久操无码视频| 亚洲天堂大香蕉| 久久99热这里只频精品6学生| 综合插插| 日本成人电影在线观看| 午夜熟睡乱子伦视频| 精品吃奶一区二区三区视频 | 不卡无线在一区| 麻豆国产91在线播放| 国产精品毛片VA一区二区三区| 亚洲成人色色| 91av视频| 亚洲色图1| 国产精品久久久久久久久久两年半| 麻豆黄网| 囯产精品久久久久久久久免费无码 | 中文字幕一区二区无码成人| 黄色视频大全在线观看| 中文无码一区| 无码日韩AV| 亚洲欧美成人在线视频| 九色91| 中文字幕在线播放第一页| 国产无遮挡A片又黄又爽小直播| 开心四房播播第四婷婷| 中文字幕免费观看视频|