整合營銷服務商

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

          免費咨詢熱線:

          Vue中輕松使模態框支持類窗口操作的增強組件

          Vue中輕松使模態框支持類窗口操作的增強組件

          今天要介紹的是一個Vue的增強組件——vue-directive-window,它讓你的模態框輕而易舉地支持類窗口操作,也就是說不僅僅對話框,還將具備一些窗口化的特性,諸如拖拽、最大化、縮放等增強型功能!




          Github

          https://gitee.com/mirrors/vue-directive-window

          特性

          • 節約成本

          旨在以極少的改造成本,讓一個現有的模態框或任何合適的HTMLElement輕松支持拖拽移動、調整大小、最大化等類視窗操作。

          • 使用便捷

          同時提供Vue自定義指令以及一般js類庫兩種調用方式。

          • 可插拔

          可以隨時為某個系統里已存在的模塊添上/去除類視窗操作的功能,而不會影響該模塊原有的功能。

          快速開始

          • 安裝使用npm

          也可以使用其它包管理工具,如yarn

          npm install vue-directive-window

          vue-directive-window支持Vue自定義指令及一般js類兩種方式來使用。

          • 自定義指令方式
          <template>
            <div v-window="windowParams">
              <!-- 容器內容 -->
            </div>
          </template>
          <script>
          import VueDirectiveWindow from 'vue-directive-window';
          Vue.use(VueDirectiveWindow); // 如果是以靜態文件方式引入的話,則不需要 import,直接使用Vue.use(window['vue-directive-window'])
          export default {
            data() {
              return {
                windowParams: {
                  movable: false,
                  resizable: ['left', 'left-top'],
                },
              };
            },
          }
          </script
          • 一般使用
          <div class="demo-window" v-window="windowParams">
            <!-- 容器內容 -->
          </div>
          import { enhanceWindow } from 'vue-directive-window'; // 如果是以靜態文件方式引入的話,則是const enhanceWindow=window['vue-directive-window'].enhanceWindow;
          
          const windowParams={
            movable: false
            resizable: ['left', 'left-top']
          };
          
          enhanceWindow(document.querySelector('.demo-window'), windowParams);

          vue-directive-window支持IE10以及以后的瀏覽器

          案例

          本文只展示官方的一個案例,其它案例參考官方文檔

          <template>
            <div class="container">
              <div class="window window1" v-show="ifShowWindow" v-window="windowParams">
                <div class="window__header">
                  一般窗口
                  <button class="maximize-btn" type="button">
                    <template v-if="!isMaximize"
                      >點這放大</template
                    >
                    <template v-else
                      >點這縮小</template
                    >
                  </button>
                </div>
                <div class="window__body">
                  <iframe height="100%" width="100%" frameborder="0" src="https://array-huang.github.io/vue-directive-window/">
                </div>
              </div>
          
              <button type="button" @click="ifShowWindow=true" v-if="!ifShowWindow">
                顯示窗口
              </button>
              <button type="button" @click="ifShowWindow=false" v-else>隱藏窗口</button>
            </div>
          </template>
          <script>
            Vue.use(window['vue-directive-window']);
          
            function maximizeCb(isMaximize) {
              this.isMaximize=isMaximize;
            }
          
            export default {
              data() {
                return {
                  windowParams: {
                    minWidth: 10,
                    maxWidth: 800,
                    minHeight: 100,
                    maxHeight: 800,
                    customMaximizeHandler: '.maximize-btn',
                    maximizeCallback: maximizeCb.bind(this),
                  },
                  ifShowWindow: false,
                  isMaximize: false,
                };
              },
            };
          </script>
          <style>
            .container {
              padding: 30px;
            }
            .window1 {
              width: 400px;
              position: fixed;
              top: 60px;
              left: 0;
            }
          </style>

          效果如下

          前的文章講了可視窗口可改變位置大?。ú榭矗?,本文介紹配合react-draggable來實現既可改變大小又可移動位置的模態窗口實現。

          實現后效果:

          <script src="https://lf3-cdn-tos.bytescm.com/obj/cdn-static-resource/tt_player/tt.player.js?v=20160723"></script>

          該實現過程旨在它拖拽改變大小和改變位置抽象出來,所以具體的布局由調用方來處理,后面會有使用示例。

          可拖拽窗口(DragableWindow)

          import React, {createRef, useEffect,useState } from 'react'
          import Drag,{ControlPosition } from 'react-draggable';
          import {Resizable} from 're-resizable';
          import {resizeOnVertical} from './utils'
          import useStyle from './style'
          import {calculatePositionAlwaysShowInView} from './utils'
          interface Point extends ControlPosition{
          }
          interface DragabeWindowProps{
              width:number;
              height:number;
              children?:any;
              dragContorlClassName?:string;
          }
          const DragableWindow : React.FC<DragabeWindowProps>=(props)=>{
              const CONTAINER_MIN_HEIGHT=504;
              const {children}=props;
              const [resizePosition,setResizePosition]=useState<Point>({x:0,y:0});
              const [position,setPosition]=useState<Point|null>(); 
              const [containerHeight,setContainerHeight]=useState<number>(CONTAINER_MIN_HEIGHT);
               /**
          	 * @param e {object} 事件源
          	 * @param direction {string} 拖動方向
          	 * @param ref {dom} 拖動的元素
          	 * @param d {object} 移動偏移量
          	 */
          	const onResize=(e:any, direction:any, ref:any, d:any)=> {
          		/* resize 之前的值 */
          		let originX=resizePosition?resizePosition.x:0;
          		let originY=resizePosition?resizePosition.y:0;
          
          		/* 移動的位移 */
          		let moveW=d.width;
          		let moveH=d.height;
          
          		/* 移動的位移 */
          		let x=null;
          		let y=null;
          
          		/* 處理上邊緣 */
          		if (/left/i.test(direction)) {
          			x=originX - moveW;
          			y=originY;
          			setPosition({ x, y });
          
          			/* 處理左邊緣 */
          		} else if (/top/i.test(direction)) {
          			x=originX;
          			y=originY - moveH;
          			setPosition({ x, y });
          		} else {
          			setPosition(null);
          		}
          
          		if (x || y) {
          			ref.style.transform=`translate(${x}px, ${y}px)`;
          		}
          	}
          
              const onResizeStop=(e:any, direction:any, ref:any, d:any)=> {
          		if (position) {
          			setResizePosition(position);
          		}
                  if (resizeOnVertical(direction)) {
                      //setContainerHeight(containerHeight + d.height);
          		}
          	}
              /**彈出窗口的蒙層樣式 */
              const popContainer: React.CSSProperties={
                  top: 0,
                  left: 0,
                  overflow: 'hidden',
                  position: 'fixed',
                  height: '100%',
                  width: '100%',
                  alignItems:'center',
                  flexDirection: 'column',
                  display:'flex',
                  zIndex: 301,
                  backgroundColor:'rgba(0, 0, 0, 0.5)',
              }
              const {width,height}=props;
              const {dragContorlClassName}=props;
              const [dragStartPosition,setDragStartPosition]=useState<ControlPosition | null>();
              useEffect(()=>{
                  /*初始容器(可拖拽組件對于的dom元素)的高度 */ 
                  if(height > CONTAINER_MIN_HEIGHT){
                      setContainerHeight(height);
                  }
              },[height]);
              const onDragStart=()=> {
          		dragStartPosition !==null && setDragStartPosition(null);
          	}
          
          	const onDragStop=(e:any, draggableData:any)=> {
          		calculatePositionAlwaysShowInView(e, draggableData,(x,y)=>{
                      setDragStartPosition({x,y});
                  });
          	};
              let popoverRef=createRef<HTMLDivElement>();
              const {styles,cx}=useStyle();
              return (
                  <>
                      {/**彈出窗口的蒙層 */}
                      <div style={popContainer}>
                          {/** handler屬性指定拖拽移動生效的樣式類,因彈出窗口還可彈出窗口,其應該具有唯一性,
                           * 這個設計旨把拖拽移動和拖拽改變大小抽象出來,通常拖拽部分由調用方指定,所以這個樣式
                           * 類名是一個組件屬性由外部傳入 */}  
                          <Drag 
                              handle={dragContorlClassName}
                              defaultClassName="js-drag-wrapped"
                              position={dragStartPosition as Point}
                              onStart={onDragStart}
                              onStop={onDragStop}
                              >
                              {/** 下面的div作為拖拽區域的外部容器 */}             
                              <div style={{width:width}}>
                                  <Resizable 
                                      style={{}} 
                                      onResize={onResize}
                                      onResizeStop={onResizeStop}
                                      minWidth={width}
                                      defaultSize={{width: width,height:containerHeight}}
                                      className={cx("js-resize-container popover-shadow",styles.resizeContainerShadow)}
                                      >
                                      {/** 下面的div用作Window的可見樣式,例如圓角 
                                       * 拖拽區域使用tansform圓角不起作用,背景色要透明
                                       * 大小可變區域tansform圓角不起作用,背景色要透明
                                       * 在可變區域增加div,設置圓角樣式,child有顏色,需要設置overflow:hidden
                                       */} 
                                      <div className={cx(styles.winPopover,styles.clearFix)}
                                          ref={popoverRef}
                                          onClick={e=> {
                                              e.stopPropagation();
                                          }}
                                          onDoubleClick={e=> {
                                              e.stopPropagation();
                                          }}
                                      >
                                          {/** 承載外部設計組件
                                           * 該實例只是展示了拖拽改變位置和大小,實際對外接口并不完善,需要根據自己的需求進行擴展
                                           * 原則:外部組件不能直接改變一個組件的狀態,所以組件內公開能做什么事,由外部組件來通知,
                                           * 內部實際做具體的動作。
                                           */}
                                          {children}
                                      </div>
                                  </Resizable>
                              </div>
                          </Drag>
                      </div>
                  </>
              );
          }
          
          export default DragableWindow;

          代碼重點,請參照代碼中的注釋,這樣描述更適合程序員來閱讀。

          這里強調的一下,標簽布局的層次,否則讀起來感覺一頭霧水。如下圖


          布局容器層次

          組件引用樣例

          模擬了一個參照彈出窗口樣例(ReferWindow),見前面的視頻。樣例使用的是antd組件進行布局演示

          import React,{Component} from 'react'
          import DragableWindow from './DragableWindow'
          import {Button} from 'antd'
          import {Flex,Layout} from 'antd'
          import {CloseOutlined,WindowsOutlined} from '@ant-design/icons'
          import {getUniqueString} from './utils'
          const { Header, Sider,Footer }=Layout;
          
          interface ReferWindowProps {
              refType:string;
              container:Element|DocumentFragment;
              title?:string;
              headIcon?:React.ReactNode;
              headContents?:[React.ReactNode];
              headComps?:[];
              visible?:boolean;
              children?:any;
              closeListener?:(v:boolean)=> void;
          }
          interface ReferWindowInnerProps {
              visible?:boolean;
              resizeHeight?:number;
              max:boolean;
              activeKey:number;
              isExpandLeftArea:boolean;
              isDragging:boolean;
          }
          
          class ReferWindow extends Component<ReferWindowProps,ReferWindowInnerProps>{
              constructor(props:ReferWindowProps){
                  super(props);
                  this.state={
                      visible:props.visible===undefined?true:props.visible,
                      max: false,
                      activeKey:0,
                      isExpandLeftArea:false,
                      isDragging:false
                  };
                  this.closeWindow.bind(this);
              }
          
              closeWindow=()=>{
                  const {closeListener}=this.props;
                  closeListener&&closeListener(false);
              }
            
              render(): React.ReactNode {
                  const {title,headIcon}=this.props;
                  let winIcon=headIcon?headIcon:<WindowsOutlined/>;
                  let {visible}=this.props;
                  let uniqueString=getUniqueString();
                  return (
                     visible&&(
                          <DragableWindow height={360} width={600} dragContorlClassName={`.drag-header-${uniqueString}`}>
                              <Layout style={{height:'100%'}}>
                                  <Header className={`drag-header-${uniqueString}`} style={{ cursor:'move', display: 'flex', alignItems: 'center',backgroundColor:'#f1f1f1', height:'50px', lineHeight:'50px',padding:'0px 15px' }}>
                                      <Flex justify="space-between" align={'center'} style={{width:'100%',height:'100%'}}  vertical={false}>
                                          <Flex>{winIcon}<span style={{padding:'5px'}}>{title??title}</span></Flex>
                                          <Flex align={'flex-end'}><CloseOutlined onClick={this.closeWindow} style={{cursor:'pointer'}}/></Flex>
                                      </Flex>
                                  </Header>
                                  <Layout style={{}}>
                                      <Sider width={200}>
                                      
                                      </Sider>
                                  </Layout>
                                  <Footer style={{padding:'10px 10px'}}>
                                      <Flex justify={'flex-end'}>
                                          <span><Button type='primary'>確定</Button></span>
                                          <span style={{padding:'0px 5px'}}><Button  onClick={this.closeWindow}>取消</Button></span>
                                      </Flex>
                                  </Footer>
                              </Layout>
                          </DragableWindow>
                      ))
              };
          }
          
          export default ReferWindow;

          參照

          import React,{Component} from 'react';
          import ReactDOM from 'react-dom';
          import {Input} from 'antd';
          import { BarsOutlined } from '@ant-design/icons';
          import ReferWindow from './referWindow'
          
          interface BaseReferProps {
              refType:string;
              container:Element|DocumentFragment;
              title?:string;
          }
          interface BaseReferInnerProps {
              popoverPanelVisible: boolean;
          }
          class BaseRefer extends Component<BaseReferProps,BaseReferInnerProps> {
              constructor(props:BaseReferProps){
                  super(props);
                  this.state={
                      popoverPanelVisible:false,
                  };
                  this.showPopoverPanel.bind(this)
                  this.onReferWindowCloseClick.bind(this);
              }
              showPopoverPanel=()=> {
                  this.setState({popoverPanelVisible:true});
              }
          
              onReferWindowCloseClick=()=>{
                  this.setState({popoverPanelVisible:false});
              }
          
              render(): React.ReactNode {
                  const {container,refType,title}=this.props;
                  let { popoverPanelVisible }=this.state;
                  return <>
                      <Input addonAfter={<BarsOutlined style={{cursor:'pointer'}} onClick={this.showPopoverPanel.bind(this)}/>}></Input>
                      {ReactDOM.createPortal(
                          <ReferWindow 
                          visible={popoverPanelVisible} 
                          closeListener={this.onReferWindowCloseClick}
                          title={title} 
                          refType={refType} 
                          container={container}>
                          </ReferWindow>,
                      container
                      )}  
                  </>
              }
          }
          
          export default BaseRefer;

          參照使用

          import React from 'react';
          import BaseRefer from './components/container/Refer/baseRefer'
          import {Row,Col} from 'antd'
          import './App.css';
          const App : React.FC=()=>{
            return (
              
                <Row>
                  <Col span={6}><BaseRefer refType='treeGrid' title='門店商品' container={document.body}></BaseRefer></Col>
                  <Col span={18}></Col>
                </Row>
              
            )
          }
          
          export default App;

          效果圖

          有些知識點,比如說Web Components, 自己平時根本用不到,如果不刻意學習和了解,自己的知識體系就會產生盲區,可是每個人的知識盲區那么多,掃的過來嘛。對于這一點,我們要抱有積極的心態,少除一個就少一個??墒且獟叱募夹g盲區那么多,為什么要優先選擇掃除它?這一點看個人偏好,沒有標準答案。但有一個大方向是確定的,如果想在技術的道路上走得更遠,就得不斷清除阻礙自己前行的障礙拓寬自己的技術視野。廢話不多說了,現在我們進入今天的主題。

          Web Components簡介

          Web Components 是一組標準,用于創建可重用的、封裝良好的自定義元素,能夠與標準的 HTML 元素無縫集成。Web Components 使開發者能夠定義自己的 HTML 標簽,這些標簽具有獨立的樣式和行為,從而增強了組件的可復用性和模塊化程度。Web Components 由以下三項技術組成:

          Custom Elements(自定義元素)

          • 允許開發者定義自己的 HTML 元素,并賦予這些元素自定義的行為。
          • 通過 customElements.define 方法注冊自定義元素。
          • 自定義元素具有生命周期回調方法,例如 connectedCallback(掛載)、disconnectedCallback(卸載)、attributeChangedCallback(屬性改變) 等。

          Shadow DOM(影子 DOM)

          • 提供了一種封裝組件內部 DOM 和樣式的方法,使其與外部 DOM 和樣式隔離。
          • 使用 attachShadow 方法創建一個影子 DOM 根節點。
          • 影子 DOM 內部的樣式和結構不會影響外部的 DOM,反之亦然。

          HTML Templates(HTML 模板)

          • 提供了一種定義可重用 HTML 結構的方法,這些結構在頁面加載時不會立即呈現。
          • 使用 <template> 標簽定義模板內容。
          • 模板內容在通過 JavaScript 克隆并插入到 DOM 中。

          Web Components使用場景

          Web Components技術是一組讓開發者能夠創建可重用的、封裝良好的自定義HTML元素的標準。使開發者能夠創建高度復用、獨立、封裝良好的組件,從而提高開發效率和代碼質量。下面是一些典型的場景:

          1. 設計系統和組件庫

          許多公司和團隊使用Web Components來構建設計系統和組件庫。這些系統和庫允許在不同項目中復用一致的UI組件,從而保持設計的一致性和開發的高效性。如Salesforce的Lightning Web Components、Ionic Framework中的Stencil。

          1. 跨框架組件共享

          Web Components可以在不同的前端框架(如React、Angular、Vue)中無縫使用。這使得開發者能夠創建獨立于框架的組件,從而提高組件的復用性。在一個項目中使用React構建大部分頁面,同時使用Web Components構建特定的獨立組件,比如日期選擇器或地圖。

          1. 微前端架構

          在微前端架構中,不同團隊可以獨立開發、部署和維護前端應用的不同部分。Web Components使得這些獨立的部分可以以組件的形式集成到一個整體的應用中,而不會互相干擾。如一個電商網站的不同模塊(如購物車、支付、用戶評論)由不同團隊開發,并以Web Components的形式集成。

          1. Web Widgets和插件

          Web Components非常適合構建可以嵌入到任意網頁中的小部件和插件,比如聊天窗口、表單驗證、廣告模塊等。這些小部件通常需要高度的封裝性和獨立性,以避免與宿主頁面的沖突。如第三方客服聊天窗口、嵌入式視頻播放器。

          1. 數據可視化

          創建數據可視化組件,如圖表、地圖、數據表等,這些組件可以獨立于具體的應用環境,在不同的項目中重用。如使用D3.js或其他圖表庫創建的自定義元素,用于顯示動態數據圖表。

          1. 定制表單控件

          構建復雜且可復用的表單控件,如日期選擇器、顏色選擇器、富文本編輯器等。這些控件可以被封裝為自定義元素,便于在不同表單中復用。如一個自定義的富文本編輯器,可以用于博客系統、內容管理系統等多個場景。

          1. Web應用的組件化開發

          在開發大型Web應用時,使用Web Components可以實現組件化開發,使得應用結構更清晰,組件更易于測試和維護。如在線文檔編輯器中的各種工具欄和編輯器組件,每個都封裝為獨立的Web Component。

          Web Components開發組件示例

          模態對話框是Web應用中常見的UI組件,可以用于顯示重要的消息、表單或確認對話框。我們通過用web components技術創建一個自定義的模態對話框組件,演示一下web components的使用方法。

          1. 定義模板和自定義元素

          將模板和自定義元素的定義放在一個JavaScript文件 my-modal.js中。

          • 創建了一個模板 template,其中包含了模態對話框的結構和樣式。 注意模板有三個插槽,可以讓我們自定義模態框的標題,內容和底部區域。
          • 定義了一個 MyModal 類,繼承自 HTMLElement。
          • 在 constructor 中使用 Shadow DOM 綁定模板內容。
          • 實現了打開和關閉模態對話框的方法,以及處理相關的事件。
          // my-modal.js
          const template=document.createElement('template');
          template.innerHTML=`
            <style>
              :host {
                display: block;
              }
              .modal {
                display: none;
                position: fixed;
                top: 0;
                left: 0;
                width: 100%;
                height: 100%;
                background-color: rgba(0, 0, 0, 0.5);
                justify-content: center;
                align-items: center;
              }
              .modal.open {
                display: flex;
              }
              .modal-content {
                background: white;
                padding: 20px;
                border-radius: 5px;
                max-width: 500px;
                width: 100%;
              }
              .modal-header,
              .modal-footer {
                display: flex;
                justify-content: space-between;
                align-items: center;
              }
              .modal-footer {
                margin-top: 20px;
              }
              .close-button {
                cursor: pointer;
              }
            </style>
            <div class="modal">
              <div class="modal-content">
                <div class="modal-header">
                  <slot name="header">頭部</slot>
                  <span class="close-button">X</span>
                </div>
                <div class="modal-body">
                  <slot name="body">內容區域</slot>
                </div>
                <div class="modal-footer">
                  <slot name="footer">
                    <button id="close-button">關閉</button>
                  </slot>
                </div>
              </div>
            </div>
          `;
          
          class MyModal extends HTMLElement {
            constructor() {
              super();
              this.attachShadow({ mode: 'open' });
              this.shadowRoot.appendChild(template.content.cloneNode(true));
          
              this.modal=this.shadowRoot.querySelector('.modal');
              this.closeButton=this.shadowRoot.querySelector('.close-button');
              this.footerCloseButton=this.shadowRoot.querySelector('#close-button');
          
              this.close=this.close.bind(this);
            }
          
            connectedCallback() {
              if (this.closeButton) {
                this.closeButton.addEventListener('click', this.close);
              }
              if (this.footerCloseButton) {
                this.footerCloseButton.addEventListener('click', this.close);
              }
            }
          
            disconnectedCallback() {
              if (this.closeButton) {
                this.closeButton.removeEventListener('click', this.close);
              }
              if (this.footerCloseButton) {
                this.footerCloseButton.removeEventListener('click', this.close);
              }
            }
          
            open() {
              this.modal.classList.add('open');
            }
          
            close() {
              this.modal.classList.remove('open');
            }
          }
          
          customElements.define('my-modal', MyModal);

          2. 在 index.html 中引入模板和自定義元素

          在HTML文件中通過 <script> 標簽引入上述JavaScript文件,并使用自定義的模態對話框組件的插槽功能定制內容。

          • 使用 <script src="my-modal.js" defer></script> 引入自定義元素的定義文件。
          • 使用 <my-modal> 自定義元素,并通過 slot 插槽填充自定義的內容。
          • 使用JavaScript控制按鈕的點擊事件,調用自定義元素的方法來打開和關閉模態對話框。
          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <meta name="viewport" content="width=device-width, initial-scale=1.0">
              <title>Modal Component Example</title>
              <script src="my-modal.js" defer></script>
          </head>
          <body>
              <button id="open-modal-button">Open Modal</button>
          
              <my-modal id="my-modal">
                  <span slot="header">自定義頭部</span>
                  <p slot="body">自定義內容區域</p>
                  <div slot="footer">
                      <button id="footer-close-button">關閉按鈕</button>
                  </div>
              </my-modal>
          
              <script>
                  document.getElementById('open-modal-button').addEventListener('click', ()=> {
                      document.getElementById('my-modal').open();
                  });
          
                  document.getElementById('footer-close-button').addEventListener('click', ()=> {
                      document.getElementById('my-modal').close();
                  });
              </script>
          </body>
          </html>

          至此,我們實現了一個功能完整的模態對話框組件,并且能夠在不同的頁面中復用。

          最后

          使用web components開發了一個模態框之后,我們發現Web Components的一些不方便之處,比如說template的定義無法單獨寫在一個html文件中,必須用模版字符串包裹起來,不優雅。另外,我們習慣使用框架組件之后,發現Web Component和原生dom開發一樣,不支持響應式數據,api相對繁瑣等。這可能是web components不是特別熱門的原因??墒怯幸环N場景,特別適合用web components。就是一些很復雜的跨開發框架的組件,比如說日歷組件,富文本編輯器,復雜的圖標和表單等??傮w說來,web components還是有用武之地的。有沒有感覺,多了解一項技術,開發的時候就多了一分靈活性,所以說技多不壓身。


          手把手教你用Web Components開發一個跨框架的模態框
          原文鏈接:https://juejin.cn/post/7371319684842340363


          主站蜘蛛池模板: 91一区二区在线观看精品| 无码夜色一区二区三区| 亚洲国产视频一区| 国产乱码精品一区二区三区| 冲田杏梨AV一区二区三区| 久久精品国产一区二区三区日韩| 国产一区二区三区影院| 国产在线无码一区二区三区视频 | 日韩免费视频一区| 无码精品一区二区三区免费视频 | 国产精品揄拍一区二区久久| 国产天堂一区二区综合| 国产视频一区在线播放| 一区二区在线视频| 日本一区二区免费看| а天堂中文最新一区二区三区| 亚洲一区二区三区久久| 寂寞一区在线观看| 国产精华液一区二区区别大吗| 国产伦精品一区二区| 日本一道一区二区免费看| 国产精品高清视亚洲一区二区| 免费无码一区二区三区| 中文字幕精品一区二区三区视频| 亚洲av区一区二区三| 老湿机一区午夜精品免费福利| 国产精品99精品一区二区三区| 日韩一区二区视频在线观看| 人妻无码第一区二区三区| 久久精品视频一区二区三区| 色狠狠一区二区三区香蕉蜜桃| 大伊香蕉精品一区视频在线| 亚洲国产精品一区二区九九| 日本精品一区二区三区在线视频一 | 一区国严二区亚洲三区| 视频在线观看一区二区| jazzjazz国产精品一区二区| 日韩一区二区三区在线观看| 一区二区三区免费在线观看| 亚洲AⅤ视频一区二区三区| 久久精品一区二区影院|