<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ## 第九步:Footer和Navbar組件 Navbar和Footer都是相對簡單的組件。Footer組件獲取并展示Top5人物角色,Navbar組件獲取并展示所有角色數量,然后還初始化一個Socket.IO事件監聽器,用以跟蹤在線訪客的數量。 > 注意:這一節會比別的小節要稍長些,因為我會在這里談到一些新概念,而其它小節將基于它們進行開發。 ### Footer組件 在components目錄下新建文件*Footer.js*: ~~~ import React from 'react'; import {Link} from 'react-router'; import FooterStore from '../stores/FooterStore' import FooterActions from '../actions/FooterActions'; class Footer extends React.Component { constructor(props) { super(props); this.state = FooterStore.getState(); this.onChange = this.onChange.bind(this); } componentDidMount() { FooterStore.listen(this.onChange); FooterActions.getTopCharacters(); } componentWillUnmount() { FooterStore.unlisten(this.onChange); } onChange(state) { this.setState(state); } render() { let leaderboardCharacters = this.state.characters.map((character) => { return ( <li key={character.characterId}> <Link to={'/characters/' + character.characterId}> <img className='thumb-md' src={'http://image.eveonline.com/Character/' + character.characterId + '_128.jpg'} /> </Link> </li> ) }); return ( <footer> <div className='container'> <div className='row'> <div className='col-sm-5'> <h3 className='lead'><strong>Information</strong> and <strong>Copyright</strong></h3> <p>Powered by <strong>Node.js</strong>, <strong>MongoDB</strong> and <strong>React</strong> with Flux architecture and server-side rendering.</p> <p>You may view the <a href='https://github.com/sahat/newedenfaces-react'>Source Code</a> behind this project on GitHub.</p> <p>? 2015 Sahat Yalkabov.</p> </div> <div className='col-sm-7 hidden-xs'> <h3 className='lead'><strong>Leaderboard</strong> Top 5 Characters</h3> <ul className='list-inline'> {leaderboardCharacters} </ul> </div> </div> </div> </footer> ); } } export default Footer; ~~~ 為防止你還未熟悉ES6語法而暈頭轉向,在這里我將最后一次展示這段代碼用ES5是如何寫的,另外你也可以參看[Using Alt with ES5](http://alt.js.org/guides/es5/)指南來了解創建action和store時語法的不同。 ~~~ var React = require('react'); var Link = require('react-router').Link; var FooterStore = require('../stores/FooterStore'); var FooterActions = require('../actions/FooterActions'); var Footer = React.createClass({ getInitialState: function() { return FooterStore.getState(); } componentDidMount: function() { FooterStore.listen(this.onChange); FooterActions.getTopCharacters(); } componentWillUnmount: function() { FooterStore.unlisten(this.onChange); } onChange: function(state) { this.setState(state); } render() { var leaderboardCharacters = this.state.characters.map(function(character) { return ( <li key={character.characterId}> <Link to={'/characters/' + character.characterId}> <img className='thumb-md' src={'http://image.eveonline.com/Character/' + character.characterId + '_128.jpg'} /> </Link> </li> ); }); return ( <footer> <div className='container'> <div className='row'> <div className='col-sm-5'> <h3 className='lead'><strong>Information</strong> and <strong>Copyright</strong></h3> <p>Powered by <strong>Node.js</strong>, <strong>MongoDB</strong> and <strong>React</strong> with Flux architecture and server-side rendering.</p> <p>You may view the <a href='https://github.com/sahat/newedenfaces-react'>Source Code</a> behind this project on GitHub.</p> <p>? 2015 Sahat Yalkabov.</p> </div> <div className='col-sm-7 hidden-xs'> <h3 className='lead'><strong>Leaderboard</strong> Top 5 Characters</h3> <ul className='list-inline'> {leaderboardCharacters} </ul> </div> </div> </div> </footer> ); } }); module.exports = Footer; ~~~ 如果你還記得Flux架構那一節的內容,這些代碼看上去應該挺熟悉。當組件加載后,將初始組件狀態設置為FooterStore中的值,然后初始化store監聽器。同樣,當組件被卸載(比如導航至另一頁面),store監聽器也被移除。當store更新,`onChange`函數被調用,然后反過來又更新Footer的狀態。 如果你之前用過React,在這里你需要注意的是,當使用ES6 class創建React組件,組件方法不再自動綁定`this`。也就是說,當你調用組件內部方法時,你需要手動綁定`this`,在之前,`React.createClass()`會幫我們自動綁定: > 自動綁定:當在JavaScript中創建回調時,你經常需要手動綁定方法到它的實例以保證this的值正確,使用React,所有方法都自動綁定到組件實例。 以上出自于官方文檔。不過在ES6中我們要這么做: ~~~ this.onChange = this.onChange.bind(this); ~~~ 下面是關于這個問題更詳細的例子: ~~~ class App extends React.Component { constructor(props) { super(props); this.state = AppStore.getState(); this.onChange = this.onChange; // Need to add `.bind(this)`. } onChange(state) { // Object `this` will be undefined without binding it explicitly. this.setState(state); } render() { return null; } } ~~~ 現在你需要了解JavaScript中的`map()`方法,即使你之前用過,也還是可能搞不清楚它在JSX中是怎么用的(React官方教程并沒有很好的解釋它)。 它基本上是一個for-each循環,和Jade和Handlebars中的類似,但在這里你可以將結果分配給一個變量,然后你就可以在JSX里使用它了,就和用其它變量一樣。它在React中很常見,你會經常用到。 > 注意:當渲染[動態子組件](https://facebook.github.io/react/docs/multiple-components.html#dynamic-children)時,如上面的`leaderboardCharacters`,React會要求你使用`key`屬性來指定每一個子組件。 [`Link`](http://rackt.github.io/react-router/#Link)組件當指定合適的*href*屬性時會渲染一個鏈接標簽,它還知道鏈接的目標是否可用,從而給鏈接加上`active`的類。如果你使用React Router,你需要使用Link模塊在應用內部進行導航。 ### Actions 下面,我們將為Footer組件創建action和store,在app/actions目錄新建*FooterActions.js*并添加: ~~~ import alt from '../alt'; class FooterActions { constructor() { this.generateActions( 'getTopCharactersSuccess', 'getTopCharactersFail' ); } getTopCharacters() { $.ajax({ url: '/api/characters/top' }) .done((data) => { this.actions.getTopCharactersSuccess(data) }) .fail((jqXhr) => { this.actions.getTopCharactersFail(jqXhr) }); } } export default alt.createActions(FooterActions); ~~~ 首先,注意我們從第七步創建的alt.js中導入了一個Alt的實例,而不是從我們安裝的Alt模塊中。它是一個Alt的實例,實現了Flux dispatcher并提供創建Alt action和store的方法。你可以把它想象為我們的store和action之間的膠水。 這里我們有3個action,一個使用ajax獲取數據,另外兩個用來通知store獲取數據是成功還是失敗。在這個例子里,知道`getTopCharacters`何時被觸發并沒有什么用,我們真正想知道的是action執行成功(更新store然后重新渲染組件)還是失敗(顯示一個錯誤通知)。 Action可以很復雜,也可以很簡單。有些action我們不關心它們做了什么,我們只關心它們是否被觸發,比如這里的`ajaxInProgress`和`ajaxComplete`被用來通知store,AJAX請求是正在進行還是已經完成。 > 注意:Alt的action能通過`generateActions`方法創建,只要它們直接通向dispatch。具體可參看[官方文檔](http://alt.js.org/docs/createActions/)。 下面的兩種創建action方式是等價的,可依據你的喜好進行選擇: ~~~ getTopCharactersSuccess(payload) { this.dispatch(payload); } getTopCharactersFail(payload) { this.dispatch(payload); } // Equivalent to this... this.generateActions( 'getTopCharactersSuccess', 'getTopCharactersFail' ); ~~~ 最后,我們通過`alt.createActions`將FooterActions封裝并暴露出來,然后我們可以在Footer組件里導入并使用它。 ### Store 下面,在app/stores目錄下新建文件*FooterStore.js*: ~~~ import alt from '../alt'; import FooterActions from '../actions/FooterActions'; class FooterStore { constructor() { this.bindActions(FooterActions); this.characters = []; } onGetTopCharactersSuccess(data) { this.characters = data.slice(0, 5); } onGetTopCharactersFail(jqXhr) { // Handle multiple response formats, fallback to HTTP status code number. toastr.error(jqXhr.responseJSON && jqXhr.responseJSON.message || jqXhr.responseText || jqXhr.statusText); } } export default alt.createStore(FooterStore); ~~~ 在store中創建的變量,比如`this`所賦值的變量,都將成為狀態的一部分。當Footer組件初始化并調用`FooterStore.getState()`,它會獲取在構造函數中指定的當前狀態(在一開始只是一個空數組,而遍歷空數組會返回另一個空數組,所以在Footer組件第一次加載時并沒有渲染任何內容)。 [`bindActions`](http://alt.js.org/docs/createStore/#storemodelbindactions)用于將action綁定到store中定義的相應處理函數。比如,一個命名為`foo`的action會匹配store中叫做`onFoo`或者`foo`的處理函數,不過需要注意它不會同時匹配兩者。因此我們在FooterActions.js中定義的action`getTopCharactersSuccess`和`getTopCharactersFail`會匹配到這里的處理函數`onGetTopCharactersSuccess`和`onGetTopCharactersFail`。 > 注意:如需更精細的控制store監聽的action以及它們綁定的處理函數,可參看文檔中的[`bindListeners`](http://alt.js.org/docs/createStore/#storemodelbindlisteners)方法。 在`onGetTopCharactersSuccess`處理函數中我們更新了store的數據,現在它包含Top 5角色,并且我們在Footer組件中初始化了store監聽器,當FooterStore更新后組件會自動的重新渲染。 我們會使用[Toastr庫](http://codeseven.github.io/toastr/demo.html)來處理通知。也許你會問為什么不使用純React通知組件呢?也許你以前看到過為React設計的通知組件,但我個人認為這是少數不太適合用React的地方(還有一個是tooltips)。我認為要從應用的任何地方顯示一個通知,使用命令方式遠比聲明式要簡單,我以前曾經構建過使用React和Flux的通知組件,但老實說,用來它處理顯隱狀態、動畫以及z-index位置等,非常痛苦。 打開app/components下的*App.js*并導入Footer組件: ~~~ import Footer from './Footer'; ~~~ 然后將`<Footer />`添加到`<RouterHandler / >`組件后面: ~~~ <div> <RouteHandler /> <Footer /> </div> ~~~ 刷新瀏覽器你應該看到新的底部: ![](https://box.kancloud.cn/2015-09-14_55f6433978049.jpg) 我們稍后會實現Express API以及添加人物角色數據庫,不過現在讓我們還是繼續構建Navbar組件。因為之前已經講過了alt action和store,這里將會盡量簡略的說明Navbar組件如何構建。 ### Navbar組件 在app/components目錄新建文件*Navbar.js*: ~~~ import React from 'react'; import {Link} from 'react-router'; import NavbarStore from '../stores/NavbarStore'; import NavbarActions from '../actions/NavbarActions'; class Navbar extends React.Component { constructor(props) { super(props); this.state = NavbarStore.getState(); this.onChange = this.onChange.bind(this); } componentDidMount() { NavbarStore.listen(this.onChange); NavbarActions.getCharacterCount(); let socket = io.connect(); socket.on('onlineUsers', (data) => { NavbarActions.updateOnlineUsers(data); }); $(document).ajaxStart(() => { NavbarActions.updateAjaxAnimation('fadeIn'); }); $(document).ajaxComplete(() => { setTimeout(() => { NavbarActions.updateAjaxAnimation('fadeOut'); }, 750); }); } componentWillUnmount() { NavbarStore.unlisten(this.onChange); } onChange(state) { this.setState(state); } handleSubmit(event) { event.preventDefault(); let searchQuery = this.state.searchQuery.trim(); if (searchQuery) { NavbarActions.findCharacter({ searchQuery: searchQuery, searchForm: this.refs.searchForm.getDOMNode(), router: this.context.router }); } } render() { return ( <nav className='navbar navbar-default navbar-static-top'> <div className='navbar-header'> <button type='button' className='navbar-toggle collapsed' data-toggle='collapse' data-target='#navbar'> <span className='sr-only'>Toggle navigation</span> <span className='icon-bar'></span> <span className='icon-bar'></span> <span className='icon-bar'></span> </button> <Link to='/' className='navbar-brand'> <span ref='triangles' className={'triangles animated ' + this.state.ajaxAnimationClass}> <div className='tri invert'></div> <div className='tri invert'></div> <div className='tri'></div> <div className='tri invert'></div> <div className='tri invert'></div> <div className='tri'></div> <div className='tri invert'></div> <div className='tri'></div> <div className='tri invert'></div> </span> NEF <span className='badge badge-up badge-danger'>{this.state.onlineUsers}</span> </Link> </div> <div id='navbar' className='navbar-collapse collapse'> <form ref='searchForm' className='navbar-form navbar-left animated' onSubmit={this.handleSubmit.bind(this)}> <div className='input-group'> <input type='text' className='form-control' placeholder={this.state.totalCharacters + ' characters'} value={this.state.searchQuery} onChange={NavbarActions.updateSearchQuery} /> <span className='input-group-btn'> <button className='btn btn-default' onClick={this.handleSubmit.bind(this)}><span className='glyphicon glyphicon-search'></span></button> </span> </div> </form> <ul className='nav navbar-nav'> <li><Link to='/'>Home</Link></li> <li><Link to='/stats'>Stats</Link></li> <li className='dropdown'> <a href='#' className='dropdown-toggle' data-toggle='dropdown'>Top 100 <span className='caret'></span></a> <ul className='dropdown-menu'> <li><Link to='/top'>Top Overall</Link></li> <li className='dropdown-submenu'> <Link to='/top/caldari'>Caldari</Link> <ul className='dropdown-menu'> <li><Link to='/top/caldari/achura'>Achura</Link></li> <li><Link to='/top/caldari/civire'>Civire</Link></li> <li><Link to='/top/caldari/deteis'>Deteis</Link></li> </ul> </li> <li className='dropdown-submenu'> <Link to='/top/gallente'>Gallente</Link> <ul className='dropdown-menu'> <li><Link to='/top/gallente/gallente'>Gallente</Link></li> <li><Link to='/top/gallente/intaki'>Intaki</Link></li> <li><Link to='/top/gallente/jin-mei'>Jin-Mei</Link></li> </ul> </li> <li className='dropdown-submenu'> <Link to='/top/minmatar'>Minmatar</Link> <ul className='dropdown-menu'> <li><Link to='/top/minmatar/brutor'>Brutor</Link></li> <li><Link to='/top/minmatar/sebiestor'>Sebiestor</Link></li> <li><Link to='/top/minmatar/vherokior'>Vherokior</Link></li> </ul> </li> <li className='dropdown-submenu'> <Link to='/top/amarr'>Amarr</Link> <ul className='dropdown-menu'> <li><Link to='/top/amarr/amarr'>Amarr</Link></li> <li><Link to='/top/amarr/ni-kunni'>Ni-Kunni</Link></li> <li><Link to='/top/amarr/khanid'>Khanid</Link></li> </ul> </li> <li className='divider'></li> <li><Link to='/shame'>Hall of Shame</Link></li> </ul> </li> <li className='dropdown'> <a href='#' className='dropdown-toggle' data-toggle='dropdown'>Female <span className='caret'></span></a> <ul className='dropdown-menu'> <li><Link to='/female'>All</Link></li> <li className='dropdown-submenu'> <Link to='/female/caldari'>Caldari</Link> <ul className='dropdown-menu'> <li><Link to='/female/caldari/achura'>Achura</Link></li> <li><Link to='/female/caldari/civire/'>Civire</Link></li> <li><Link to='/female/caldari/deteis'>Deteis</Link></li> </ul> </li> <li className='dropdown-submenu'> <Link to='/female/gallente'>Gallente</Link> <ul className='dropdown-menu'> <li><Link to='/female/gallente/gallente'>Gallente</Link></li> <li><Link to='/female/gallente/intaki'>Intaki</Link></li> <li><Link to='/female/gallente/jin-mei'>Jin-Mei</Link></li> </ul> </li> <li className='dropdown-submenu'> <Link to='/female/minmatar'>Minmatar</Link> <ul className='dropdown-menu'> <li><Link to='/female/minmatar/brutor'>Brutor</Link></li> <li><Link to='/female/minmatar/sebiestor'>Sebiestor</Link></li> <li><Link to='/female/minmatar/vherokior'>Vherokior</Link></li> </ul> </li> <li className='dropdown-submenu'> <Link to='/female/amarr'>Amarr</Link> <ul className='dropdown-menu'> <li><Link to='/female/amarr/amarr'>Amarr</Link></li> <li><Link to='/female/amarr/ni-kunni'>Ni-Kunni</Link></li> <li><Link to='/female/amarr/khanid'>Khanid</Link></li> </ul> </li> </ul> </li> <li className='dropdown'> <a href='#' className='dropdown-toggle' data-toggle='dropdown'>Male <span className='caret'></span></a> <ul className='dropdown-menu'> <li><Link to='/male'>All</Link></li> <li className='dropdown-submenu'> <Link to='/male/caldari'>Caldari</Link> <ul className='dropdown-menu'> <li><Link to='/male/caldari/achura'>Achura</Link></li> <li><Link to='/male/caldari/civire'>Civire</Link></li> <li><Link to='/male/caldari/deteis'>Deteis</Link></li> </ul> </li> <li className='dropdown-submenu'> <Link to='/male/gallente'>Gallente</Link> <ul className='dropdown-menu'> <li><Link to='/male/gallente/gallente'>Gallente</Link></li> <li><Link to='/male/gallente/intaki'>Intaki</Link></li> <li><Link to='/male/gallente/jin-mei'>Jin-Mei</Link></li> </ul> </li> <li className='dropdown-submenu'> <Link to='/male/minmatar'>Minmatar</Link> <ul className='dropdown-menu'> <li><Link to='/male/minmatar/brutor'>Brutor</Link></li> <li><Link to='/male/minmatar/sebiestor'>Sebiestor</Link></li> <li><Link to='/male/minmatar/vherokior'>Vherokior</Link></li> </ul> </li> <li className='dropdown-submenu'> <Link to='/male/amarr'>Amarr</Link> <ul className='dropdown-menu'> <li><Link to='/male/amarr/amarr'>Amarr</Link></li> <li><Link to='/male/amarr/ni-kunni'>Ni-Kunni</Link></li> <li><Link to='/male/amarr/khanid'>Khanid</Link></li> </ul> </li> </ul> </li> <li><Link to='/add'>Add</Link></li> </ul> </div> </nav> ); } } Navbar.contextTypes = { router: React.PropTypes.func.isRequired }; export default Navbar; ~~~ 必須承認,這里使用循環的話可以少寫一些代碼,但現在這樣對我來說更直觀。 你可能立刻注意到的一個東西是class變量`contextTypes`。我們需要它來引用router的實例,從而讓我們能訪問當前路徑、請求參數、路由參數以及到其它路由的變換。我們不在Navbar組件里直接使用它,而是將它作為一個參數傳遞給Navbar action,以使它能導航到特定character資料頁面。 ![](https://box.kancloud.cn/2015-09-14_55f64339daa8f.jpg) `componentDidMount`是我們發起與Socket.IO的連接,并初始化`ajaxStart`和`ajaxComplete`時間監聽器地方,我們會在AJAX請求時在NEF logo旁邊顯示加載指示。 `handleSubmit`是用來處理表單提交的程序,在按下Enter鍵或點擊Search圖標時執行。它會做一些輸入清理和驗證工作,然后觸發`findCharacter`?action。另外我們還傳遞了搜索區域的DOM節點給action,以便當搜索結果為0時加載一個震動動畫。 ### Actions 在app/actions目錄下新建文件*NavbarActions.js*: ~~~ import alt from '../alt'; import {assign} from 'underscore'; class NavbarActions { constructor() { this.generateActions( 'updateOnlineUsers', 'updateAjaxAnimation', 'updateSearchQuery', 'getCharacterCountSuccess', 'getCharacterCountFail', 'findCharacterSuccess', 'findCharacterFail' ); } findCharacter(payload) { $.ajax({ url: '/api/characters/search', data: { name: payload.searchQuery } }) .done((data) => { assign(payload, data); this.actions.findCharacterSuccess(payload); }) .fail(() => { this.actions.findCharacterFail(payload); }); } getCharacterCount() { $.ajax({ url: '/api/characters/count' }) .done((data) => { this.actions.getCharacterCountSuccess(data) }) .fail((jqXhr) => { this.actions.getCharacterCountFail(jqXhr) }); } } export default alt.createActions(NavbarActions); ~~~ 我想大多數action的命名應該能夠自我解釋,不過為了更清楚的理解,在下面簡單的描述一下它們是干什么的: | Action | Description | | --- | --- | | `updateOnlineUsers` | 當Socket.IO事件更新時設置在線用戶數 | | `updateAjaxAnimation` | 添加”fadeIn”或”fadeOut”類到加載指示器 | | `updateSearchQuery` | 當使用鍵盤時設置搜索請求 | | `getCharacterCount` | 從服務器獲取總角色數 | | `getCharacterCountSuccess` | 返回角色總數 | | `getCharacterCountFail` | 返回jQuery jqXhr對象 | | `findCharacter` | 根據名稱查找角色 | ### Store 在app/stores目錄下創建*NavbarStore.js*: ~~~ import alt from '../alt'; import NavbarActions from '../actions/NavbarActions'; class NavbarStore { constructor() { this.bindActions(NavbarActions); this.totalCharacters = 0; this.onlineUsers = 0; this.searchQuery = ''; this.ajaxAnimationClass = ''; } onFindCharacterSuccess(payload) { payload.router.transitionTo('/characters/' + payload.characterId); } onFindCharacterFail(payload) { payload.searchForm.classList.add('shake'); setTimeout(() => { payload.searchForm.classList.remove('shake'); }, 1000); } onUpdateOnlineUsers(data) { this.onlineUsers = data.onlineUsers; } onUpdateAjaxAnimation(className) { this.ajaxAnimationClass = className; //fadein or fadeout } onUpdateSearchQuery(event) { this.searchQuery = event.target.value; } onGetCharacterCountSuccess(data) { this.totalCharacters = data.count; } onGetCharacterCountFail(jqXhr) { toastr.error(jqXhr.responseJSON.message); } } export default alt.createStore(NavbarStore); ~~~ 回憶一下我們在Navbar組件中的代碼: ~~~ <input type='text' className='form-control' placeholder={this.state.totalCharacters + ' characters'} value={this.state.searchQuery} onChange={NavbarActions.updateSearchQuery} /> ~~~ 因為[`onChange`](https://facebook.github.io/react/docs/forms.html#interactive-props)方法返回一個event對象,所以這里我們在`onUpdateSearchQuery`使用`event.target.value`來獲取輸入框的值。 再次打開App.js并導入Navbar組件: ~~~ import Navbar from './Navbar'; ~~~ 然后在`<RouterHandler />`添加`<Navbar />`組件: ~~~ <div> <Navbar /> <RouteHandler /> <Footer /> </div> ~~~ ![](https://box.kancloud.cn/2015-09-14_55f6433a5dd94.jpg) 由于我們還沒有設置服務器端的Socke.IO,也沒有實現任何API,所以現在你應該看不到在線訪問人數或總的character數。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看