React的思想

React的思想

在我看來, React 是較早使用 JavaScript 構(gòu)建大型直焙、快速的 Web 應(yīng)用程序的技術(shù)方案似将。它已經(jīng)被我們廣泛應(yīng)
用于 Facebook 和 Instagram 念搬。
React 眾多優(yōu)秀特征中的其中一部分就是,教會你去重新思考如何構(gòu)建應(yīng)用程序奕扣。 本文中,我將跟你一起使用 React 構(gòu)建一個具備搜索功能的產(chǎn)品列表显押。<br />

從設(shè)計稿(mock或譯作'原型')開始

假設(shè)你已經(jīng)得到了一份JSON API文檔和設(shè)計稿, 設(shè)計稿如下圖:

JSON的API如下:

[
  {category: "Sporting Goods", price: "$49.99", stocked: true, name: "Football"},
  {category: "Sporting Goods", price: "$9.99", stocked: true, name: "Baseball"},
  {category: "Sporting Goods", price: "$29.99", stocked: false, name: "Basketball"},
  {category: "Electronics", price: "$99.99", stocked: true, name: "iPod Touch"},
  {category: "Electronics", price: "$399.99", stocked: false, name: "iPhone 5"},
  {category: "Electronics", price: "$199.99", stocked: true, name: "Nexus 7"}
];

第一步: 將UI分離成組件層次

你要做的第一件事是,為所有組件(及子組件)命名并畫上線框圖。假如你和設(shè)計師一起工作,也許他們已經(jīng)完 成了這項工作,所以趕緊去跟他們溝通!他們的 Photoshop 圖層名也許最終可以直接用于你的 React 組件名待诅。

然而你如何知道哪些才能成為組件?想象一下,當(dāng)你創(chuàng)建一些函數(shù)或?qū)ο髸r,用到一些類似的技術(shù)。其中一項技
術(shù)就是單一指責(zé)原則,指的是,理想狀態(tài)下一個組件應(yīng)該只做一件事,假如它功能逐漸變大就需要被拆分成更小
的子組件熊镣。

由于你經(jīng)常需要將一個JSON數(shù)據(jù)模型展示給用戶,因此你需要檢查這個模型結(jié)構(gòu)是否正確以便你的 UI (在這里 指組件結(jié)構(gòu))是否能夠正確的映射到這個模型上卑雁。這是因為用戶界面和數(shù)據(jù)模型在 信息構(gòu)造 方面都要一致,這 意味著將你可以省下很多將 UI 分割成組件的麻煩事。你需要做的僅僅只是將數(shù)據(jù)模型分隔成一小塊一小塊的組 件,以便它們都能夠表示成組件绪囱。

* FilterableProductTable (orange): contains the entirety of the example <br />
* SearchBar (blue): receives all user input <br />
* ProductTable (green): displays and filters the data collection based on user input <br />
* ProductCategoryRow (turquoise): displays a heading for each category <br />
* ProductRow (red): displays a row for each product <br />

看看ProductTable测蹲,你會看到表頭(包含“name”和“price”標(biāo)簽)不是自己的組件。 這是一個個人偏好的問題鬼吵。 對于這個例子扣甲,我們把它作為ProductTable的一部分,因為它是渲染數(shù)據(jù)收集的一部分齿椅,這是ProductTable的責(zé)任琉挖。
然而,如果這個頭部變得復(fù)雜(如果我們添加用于排序的可用性)媒咳,那么使它自己的ProductTableHeader組件會更好一些粹排。
下面就是結(jié)構(gòu)層次:

* FilterableProductTable
  * SearchBar
  * ProductTable
    * ProductCategoryRow
    * ProductRow

第二步: 用React構(gòu)建一個靜態(tài)版本

var ProductCategoryRow = React.createClass({
  render: function() {
    return (<tr>
        <th colSpan="2">{this.props.category}</th>
    </tr>);
  }
});

var ProductRow = React.createClass({
  render: function() {
    var name = this.props.product.stocked ?
      this.props.product.name :
      <span style={{color: 'red'}}>
        {this.props.product.name}
      </span>;
    return (
      <tr>
        <td>{name}</td>
        <td>{this.props.product.price}</td>
      </tr>
    );
  }
});

var ProductTable = React.createClass({
  render: function() {
    var rows = [];
    var lastCategory = null;
    this.props.products.forEach(function(product) {
      if (product.category !== lastCategory) {
        rows.push(<ProductCategoryRow category={product.category} key={product.category} />);
      }
      rows.push(<ProductRow product={product} key={product.name} />);
      lastCategory = product.category;
    });
    return (
      <table>
        <thead>
          <tr>
            <th>Name</th>
            <th>Price</th>
          </tr>
        </thead>
        <tbody>{rows}</tbody>
      </table>
    );
  }
});

var SearchBar = React.createClass({
  render: function() {
    return (
      <form>
        <input type="text" placeholder="Search..." />
        <p>
          <input type="checkbox" />
          {' '}
          Only show products in stock
        </p>
      </form>
    );
  }
});

var FilterableProductTable = React.createClass({
  render: function() {
    return (
      <div>
        <SearchBar />
        <ProductTable products={this.props.products} />
      </div>
    );
  }
});


var PRODUCTS = [
  {category: 'Sporting Goods', price: '$49.99', stocked: true, name: 'Football'},
  {category: 'Sporting Goods', price: '$9.99', stocked: true, name: 'Baseball'},
  {category: 'Sporting Goods', price: '$29.99', stocked: false, name: 'Basketball'},
  {category: 'Electronics', price: '$99.99', stocked: true, name: 'iPod Touch'},
  {category: 'Electronics', price: '$399.99', stocked: false, name: 'iPhone 5'},
  {category: 'Electronics', price: '$199.99', stocked: true, name: 'Nexus 7'}
];
 
ReactDOM.render(
  <FilterableProductTable products={PRODUCTS} />,
  document.getElementById('container')
);
  • 現(xiàn)在已經(jīng)擁有了組件層次結(jié)構(gòu),現(xiàn)在是實現(xiàn)應(yīng)用程序的時候了涩澡。 最簡單的方法是構(gòu)建一個版本顽耳,它接收您的數(shù)據(jù)模型并呈現(xiàn)UI,但沒有交互性妙同。
    最好要解耦這些過程射富,因為構(gòu)建靜態(tài)版本需要大量的typing,沒有thinking粥帚,添加交互性需要很多thinking胰耗,而不是很多typing。 我們看看為什么芒涡。
  • 要構(gòu)建呈現(xiàn)您的數(shù)據(jù)模型的應(yīng)用程序的靜態(tài)版本柴灯,您需要構(gòu)建可復(fù)用其他組件和使用props傳遞數(shù)據(jù)的組件。 props是將數(shù)據(jù)從父級傳遞到子級的一種方式费尽。 如果你熟悉state的概念赠群,不要使用state來構(gòu)建這個靜態(tài)版本。
    因為state僅適用于交互性即隨時間變化的數(shù)據(jù)旱幼。 由于這是一個靜態(tài)版本的應(yīng)用程序查描,所以你不需要state
  • 關(guān)于構(gòu)建順序, 您可以構(gòu)建自頂向下或自下而上。 也就是說冬三,您可以從層次結(jié)構(gòu)中的較高層(即從FilterableProductTable開始)或在其中較低的層(ProductRow)開始構(gòu)建組件匀油。
    在更簡單的例子中,通常應(yīng)該從上到下構(gòu)建勾笆,而在更大的項目中敌蚜,更應(yīng)該從底層向上構(gòu)建應(yīng)用和編寫測試。
  • 在此步驟結(jié)束時匠襟,您將有一個用于呈現(xiàn)您的數(shù)據(jù)模型的可重用組件庫钝侠。 組件將只有render()方法,因為這是一個靜態(tài)版本的應(yīng)用程序酸舍。 層次結(jié)構(gòu)頂部的組件(FilterableProductTable)將把您的數(shù)據(jù)模型作為props帅韧。
    如果對基礎(chǔ)數(shù)據(jù)模型進(jìn)行更改并再次調(diào)用ReactDOM.render(),則UI將更新啃勉。 很容易看到你的UI是如何更新的和更改的地方忽舟,因為沒有什么復(fù)雜的。 React的單向數(shù)據(jù)流(也稱為單向綁定)會保持模塊化和快速化淮阐。

如果在此步驟需要幫助叮阅,請參閱React文檔

一個簡短的插曲:Props vs State

React中有兩種類型的“模型”數(shù)據(jù):props和state泣特。 重要的是要了解兩者之間的區(qū)別;
如果你不確定有什么區(qū)別, 請參閱state文檔

第三步: 確定 UI state的最泻评选(但完整)表示

要使你的UI交互,你需要能夠觸發(fā)對基礎(chǔ)數(shù)據(jù)模型的更改状您。 React的state讓交互變得簡單勒叠。

為了正確構(gòu)建應(yīng)用,首先需要考慮應(yīng)用需要的最小的可變 state 數(shù)據(jù)模型集合。此處關(guān)鍵點在于精簡:不要存儲重復(fù)的數(shù)據(jù)膏孟。
構(gòu)造出絕對最小的滿足應(yīng)用需要的最小 state 是有必要的,并且計算出其它強(qiáng)烈需要的東西眯分。例如,如果構(gòu)建一個 TODO 列表,僅保存一個 TODO 列表項的數(shù)組,而不要保存另外一個指代數(shù)組長度的 state 變 量。當(dāng)想要渲染 TODO 列表項總數(shù)的時候,簡單地取出 TODO 列表項數(shù)組的長度就可以了柒桑。

示例程序中所有需要的的數(shù)據(jù)如下:

  • 產(chǎn)品的原始列表 (The original list of products)
  • 用戶在搜索框輸入的文字 (The search text the user has entered)
  • 選擇框的值 (The value of the checkbox)
  • 已過濾的產(chǎn)品列表 (The filtered list of products)

讓我們找出哪一個應(yīng)該是用state管理弊决。 只需詢問每個數(shù)據(jù)的三個問題:

  1. 它是繼承而來的props嗎兼贡? 如果是咧栗,它應(yīng)該不是state
  2. 它是一直不變的嗎? 如果是郊丛,它應(yīng)該不是state界逛。
  3. 能通過其他的state或者props計算而來嗎? 如果是昆稿,它應(yīng)該不是state

經(jīng)過分析, 原始的產(chǎn)品列表作為props傳遞仇奶,所以不是state貌嫡。 搜索文本和復(fù)選框似乎是state,因為它們隨時間變化该溯,不能從任何計算岛抄。
最后,過濾的產(chǎn)品列表不是state狈茉,因為它可以通過將原始產(chǎn)品列表與復(fù)選框的搜索文本和值組合來計算夫椭。

綜上, 我們的state只有兩項:

  • 用戶在搜索框輸入的文字
  • 選擇框的值

第四步: 確定state的位置

var ProductCategoryRow = React.createClass({
  render: function() {
    return (<tr>
        <th colSpan="2">{this.props.category}</th>
    </tr>);
  }
});

var ProductRow = React.createClass({
  render: function() {
    var name = this.props.product.stocked ?
      this.props.product.name :
      <span style={{color: 'red'}}>
        {this.props.product.name}
      </span>;
    return (
      <tr>
        <td>{name}</td>
        <td>{this.props.product.price}</td>
      </tr>
    );
  }
});

var ProductTable = React.createClass({
  render: function() {
    var rows = [];
    var lastCategory = null;
    this.props.products.forEach(function(product) {
      if (product.name.indexOf(this.props.filterText) === -1 || (!product.stocked && this.props.inStockOnly)) {
        return;
      }
      if (product.category !== lastCategory) {
        rows.push(<ProductCategoryRow category={product.category} key={product.category} />);
      }
      rows.push(<ProductRow product={product} key={product.name} />);
      lastCategory = product.category;
    }.bind(this));
    return (
      <table>
        <thead>
          <tr>
            <th>Name</th>
            <th>Price</th>
          </tr>
        </thead>
        <tbody>{rows}</tbody>
      </table>
    );
  }
});

var SearchBar = React.createClass({
  render: function() {
    return (
      <form>
        <input type="text" placeholder="Search..." value={this.props.filterText} />
        <p>
          <input type="checkbox" checked={this.props.inStockOnly} />
          {' '}
          Only show products in stock
        </p>
      </form>
    );
  }
});

var FilterableProductTable = React.createClass({
  getInitialState: function() {
    return {
      filterText: '',
      inStockOnly: false
    };
  },

  render: function() {
    return (
      <div>
        <SearchBar
          filterText={this.state.filterText}
          inStockOnly={this.state.inStockOnly}
        />
        <ProductTable
          products={this.props.products}
          filterText={this.state.filterText}
          inStockOnly={this.state.inStockOnly}
        />
      </div>
    );
  }
});


var PRODUCTS = [
  {category: 'Sporting Goods', price: '$49.99', stocked: true, name: 'Football'},
  {category: 'Sporting Goods', price: '$9.99', stocked: true, name: 'Baseball'},
  {category: 'Sporting Goods', price: '$29.99', stocked: false, name: 'Basketball'},
  {category: 'Electronics', price: '$99.99', stocked: true, name: 'iPod Touch'},
  {category: 'Electronics', price: '$399.99', stocked: false, name: 'iPhone 5'},
  {category: 'Electronics', price: '$199.99', stocked: true, name: 'Nexus 7'}
];

ReactDOM.render(
  <FilterableProductTable products={PRODUCTS} />,
  document.getElementById('container')
);

OK,我們已經(jīng)確定了什么是最小的應(yīng)用state集氯庆。 接下來蹭秋,我們需要確定哪個組件的state會突變, 哪個組件應(yīng)該擁有此state

記椎棠臁:React的所有層次的內(nèi)容都是單向數(shù)據(jù)流傳輸仁讨。 可能不是立即清楚哪個組件應(yīng)該擁有什么state
對于新手來說实昨,這通常是最具挑戰(zhàn)性的部分洞豁,因此請按照以下步驟了解:

對于應(yīng)用中所有的state:

  • 找出每一個基于那個 state 渲染界面的組件。
  • 找出共同的祖先組件(某個單個的組件,在組件樹中位于需要這個 state 的所有組件的上面
  • 要么是共同的祖先組件,要么是另外一個在組件樹中位于更高層級的組件應(yīng)該擁有這個state
  • 如果找不出擁有這個 state 數(shù)據(jù)模型的合適的組件,創(chuàng)建一個新的組件來維護(hù)這個 state ,然后添加到組件樹中,層級位于所有共同擁有者組件的上面荒给。

讓我們根據(jù)上面的策略來確定示例程序的state的位置:

  • ProductTable需要根據(jù)狀態(tài)過濾產(chǎn)品列表丈挟,搜索欄需要顯示搜索文本和選中狀態(tài)。
  • 公共所有者組件是FilterableProductTable
  • 過濾器文本(filter text)和檢查值(checked value)放在FilterableProductTable是可行的.

所以我們決定我們的state放置在FilterableProductTable志电。 首先曙咽,將getInitialState()方法添加到FilterableProductTable,返回{filterText:''挑辆,inStockOnly:false}以反映應(yīng)用程序的初始狀態(tài)例朱。
然后,將filterTextinStockOnly傳遞給ProductTableSearchBar作為props之拨。 最后茉继,使用這些props來過濾ProductTable中的rows,并在SearchBar中設(shè)置表單字段的值蚀乔。

你可以試著修改:將filterText設(shè)置為“ball”并刷新你的應(yīng)用程序烁竭。 您將看到數(shù)據(jù)表已正確更新。

第五步: 添加逆向數(shù)據(jù)流

var ProductCategoryRow = React.createClass({
  render: function() {
    return (<tr><th colSpan="2">{this.props.category}</th></tr>);
  }
});

var ProductRow = React.createClass({
  render: function() {
    var name = this.props.product.stocked ?
      this.props.product.name :
      <span style={{color: 'red'}}>
        {this.props.product.name}
      </span>;
    return (
      <tr>
        <td>{name}</td>
        <td>{this.props.product.price}</td>
      </tr>
    );
  }
});

var ProductTable = React.createClass({
  render: function() {
    var rows = [];
    var lastCategory = null;
    this.props.products.forEach(function(product) {
      if (product.name.indexOf(this.props.filterText) === -1 || (!product.stocked && this.props.inStockOnly)) {
        return;
      }
      if (product.category !== lastCategory) {
        rows.push(<ProductCategoryRow category={product.category} key={product.category} />);
      }
      rows.push(<ProductRow product={product} key={product.name} />);
      lastCategory = product.category;
    }.bind(this));
    return (
      <table>
        <thead>
          <tr>
            <th>Name</th>
            <th>Price</th>
          </tr>
        </thead>
        <tbody>{rows}</tbody>
      </table>
    );
  }
});

var SearchBar = React.createClass({
  handleChange: function() {
    this.props.onUserInput(
      this.refs.filterTextInput.value,
      this.refs.inStockOnlyInput.checked
    );
  },
  render: function() {
    return (
      <form>
        <input
          type="text"
          placeholder="Search..."
          value={this.props.filterText}
          ref="filterTextInput"
          onChange={this.handleChange}
        />
        <p>
          <input
            type="checkbox"
            checked={this.props.inStockOnly}
            ref="inStockOnlyInput"
            onChange={this.handleChange}
          />
          {' '}
          Only show products in stock
        </p>
      </form>
    );
  }
});

var FilterableProductTable = React.createClass({
  getInitialState: function() {
    return {
      filterText: '',
      inStockOnly: false
    };
  },

  handleUserInput: function(filterText, inStockOnly) {
    this.setState({
      filterText: filterText,
      inStockOnly: inStockOnly
    });
  },

  render: function() {
    return (
      <div>
        <SearchBar
          filterText={this.state.filterText}
          inStockOnly={this.state.inStockOnly}
          onUserInput={this.handleUserInput}
        />
        <ProductTable
          products={this.props.products}
          filterText={this.state.filterText}
          inStockOnly={this.state.inStockOnly}
        />
      </div>
    );
  }
});


var PRODUCTS = [
  {category: 'Sporting Goods', price: '$49.99', stocked: true, name: 'Football'},
  {category: 'Sporting Goods', price: '$9.99', stocked: true, name: 'Baseball'},
  {category: 'Sporting Goods', price: '$29.99', stocked: false, name: 'Basketball'},
  {category: 'Electronics', price: '$99.99', stocked: true, name: 'iPod Touch'},
  {category: 'Electronics', price: '$399.99', stocked: false, name: 'iPhone 5'},
  {category: 'Electronics', price: '$199.99', stocked: true, name: 'Nexus 7'}
];

ReactDOM.render(
  <FilterableProductTable products={PRODUCTS} />,
  document.getElementById('container')
);

到目前為止吉挣,我們已經(jīng)構(gòu)建了一個應(yīng)用程序派撕,通過propsstate沿著層次結(jié)構(gòu)向下的函數(shù)正確執(zhí)行。
現(xiàn)在是時候以其他方式支持?jǐn)?shù)據(jù)流:層次結(jié)構(gòu)中深層的表單form組件需要更新FilterableProductTable中的state睬魂。

React 讓這種數(shù)據(jù)流動非常明確,從而很容易理解應(yīng)用是如何工作的,但是相對于傳統(tǒng)的雙向數(shù)據(jù)綁定,確實需 要輸入更多的東西终吼。
React 提供了一個叫做 ReactLink 的插件來使其和雙向數(shù)據(jù)綁定一樣方便,但是考慮到這篇文章的目的,我們將會保持所有東西都直截了當(dāng)。

如果嘗試在當(dāng)前實例中鍵入或選中該框氯哮,您將看到React忽略您的輸入际跪。 這是有意的,因為我們已將輸入的值prop設(shè)置為始終等于從FilterableProductTable傳遞的狀態(tài)。

我們要確保每當(dāng)用戶更改表單時姆打,我們更新狀態(tài)以反映用戶輸入良姆。 因為組件只應(yīng)該更新自己的state狀態(tài),FilterableProductTable將傳遞一個回調(diào)到SearchBar幔戏,每當(dāng)狀態(tài)應(yīng)該更新時觸發(fā)玛追。
我們可以使用onChange事件對輸入進(jìn)行通知。 并且FilterableProductTable傳遞的回調(diào)將調(diào)用setState()闲延,并且應(yīng)用程序?qū)⒈桓?/p>

雖然聽起來比較復(fù)雜痊剖,但是幾行代碼就能實現(xiàn)。而且他能讓我們更加明晰React的數(shù)據(jù)流通方式垒玲。

后記

希望以上內(nèi)容讓你明白了如何思考用 React 去構(gòu)造組件和應(yīng)用陆馁。雖然可能比你之前要輸入更多的代碼,記住,讀代碼的時間遠(yuǎn)比寫代碼的時間多,并且閱讀這種模塊化的清晰的代碼是相當(dāng)容易的。
當(dāng)你開始構(gòu)建大型的組件庫 的時候,你將會非常感激這種清晰性和模塊化,并且隨著代碼的復(fù)用,整個項目代碼量就開始變少了

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末合愈,一起剝皮案震驚了整個濱河市氮惯,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌想暗,老刑警劉巖妇汗,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異说莫,居然都是意外死亡杨箭,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進(jìn)店門储狭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來互婿,“玉大人,你說我怎么就攤上這事辽狈〈炔危” “怎么了?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵刮萌,是天一觀的道長驮配。 經(jīng)常有香客問我,道長着茸,這世上最難降的妖魔是什么壮锻? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮涮阔,結(jié)果婚禮上猜绣,老公的妹妹穿的比我還像新娘。我一直安慰自己敬特,他們只是感情好掰邢,可當(dāng)我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布牺陶。 她就那樣靜靜地躺著,像睡著了一般辣之。 火紅的嫁衣襯著肌膚如雪义图。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天召烂,我揣著相機(jī)與錄音,去河邊找鬼娃承。 笑死奏夫,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的历筝。 我是一名探鬼主播酗昼,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼梳猪!你這毒婦竟也來了麻削?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤春弥,失蹤者是張志新(化名)和其女友劉穎呛哟,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體匿沛,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡扫责,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了逃呼。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鳖孤。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖抡笼,靈堂內(nèi)的尸體忽然破棺而出苏揣,到底是詐尸還是另有隱情,我是刑警寧澤推姻,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布平匈,位于F島的核電站,受9級特大地震影響藏古,放射性物質(zhì)發(fā)生泄漏吐葱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一校翔、第九天 我趴在偏房一處隱蔽的房頂上張望弟跑。 院中可真熱鬧,春花似錦防症、人聲如沸孟辑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽饲嗽。三九已至炭玫,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間貌虾,已是汗流浹背吞加。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留尽狠,地道東北人衔憨。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像袄膏,于是被迫代替她去往敵國和親践图。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,843評論 2 354

推薦閱讀更多精彩內(nèi)容