element-ui ScrollBar組件源碼深入分析

element-ui ScrollBar組件源碼深入分析

scrollbar組件根目錄下包括index.js文件和src文件夾谐檀,index.js是用來(lái)注冊(cè)Vue插件的地方斩狱,沒(méi)什么好說(shuō)的柬姚,不了解的童鞋可以看一下Vue官方文檔中的 插件野芒,src目錄下的內(nèi)容才是scrollbar組件的核心代碼宫盔,其入口文件是main.js绰疤。

在開(kāi)始分析源碼之前,我們先來(lái)說(shuō)一下自定義滾動(dòng)條的原理柑肴,方便大家更好的理解霞揉。

scrollbar.png

如圖,黑色wrap為滾動(dòng)的可顯示區(qū)域晰骑,我們的滾動(dòng)內(nèi)容就是在這個(gè)區(qū)域中滾動(dòng)适秩,view是實(shí)際的滾動(dòng)內(nèi)容,超出wrap可顯示區(qū)域的內(nèi)容都將被隱藏硕舆。右側(cè)track是滾動(dòng)條的滾動(dòng)滑塊thumb上下滾動(dòng)的軌跡秽荞。

當(dāng)wrap中的內(nèi)容溢出的時(shí)候,就會(huì)產(chǎn)生各瀏覽器的原生滾動(dòng)條抚官,要實(shí)現(xiàn)自定義滾動(dòng)條扬跋,我們必須將原生滾動(dòng)條消滅掉。假設(shè)我們給wrap外面再包一層div凌节,并且把這個(gè)div的樣式設(shè)為overflow:hidden钦听,同時(shí)我們給wrap的marginRight,marginBottom設(shè)置一個(gè)負(fù)值,值得大小正好等于原生滾動(dòng)條的寬度倍奢,那么這個(gè)時(shí)候由于父容器的overflow:hidden屬性朴上,正好就可以將原生滾動(dòng)條隱藏掉。然后我們?cè)賹⒆远x的滾動(dòng)條絕對(duì)定位到wrap容器的右側(cè)和下側(cè)卒煞,并加上滾動(dòng)痪宰、拖拽事件等滾動(dòng)邏輯,就可以實(shí)現(xiàn)自定義滾動(dòng)條了。

接下來(lái)我們從main.js入口開(kāi)始衣撬,詳細(xì)分析一下element是如何實(shí)現(xiàn)這些邏輯的乖订。

main.js文件中直接導(dǎo)出一個(gè)對(duì)象,這個(gè)對(duì)象采用render函數(shù)的方式渲染scrollbar組件具练,組件對(duì)外暴漏的接口如下:

props: {
  native: Boolean,  // 是否采用原生滾動(dòng)(即只是隱藏掉了原生滾動(dòng)條垢粮,但并沒(méi)有使用自定義的滾動(dòng)條)
  wrapStyle: {},  // 內(nèi)聯(lián)方式 自定義wrap容器的樣式
  wrapClass: {},  // 類(lèi)名方式 自定義wrap容器的樣式
  viewClass: {},  // 內(nèi)聯(lián)方式 自定義view容器的樣式
  viewStyle: {},  // 類(lèi)名方式 自定義view容器的樣式
  noresize: Boolean, // 如果 container 尺寸不會(huì)發(fā)生變化,最好設(shè)置它可以?xún)?yōu)化性能
  tag: {                // view容器用那種標(biāo)簽渲染靠粪,默認(rèn)為div
    type: String,
    default: 'div'
  }
}

可以看到,這就是整個(gè)ScrollBar組件對(duì)外暴露的接口毫蚓,主要包括了自定義wrap,view樣式的接口占键,以及用來(lái)優(yōu)化性能的noresize接口。

然后我們?cè)賮?lái)分析一下render函數(shù):

render(){
    let gutter = scrollbarWidth();  // 通過(guò)scrollbarWidth()方法 獲取瀏覽器原生滾動(dòng)條的寬度
  let style = this.wrapStyle;

  if (gutter) {
    const gutterWith = `-${gutter}px`;
    
    // 定義即將應(yīng)用到wrap容器上的marginBottom和marginRight,值為上面求出的瀏覽器滾動(dòng)條寬度的負(fù)值
    const gutterStyle = `margin-bottom: ${gutterWith}; margin-right: ${gutterWith};`;

    // 這一部分主要是根據(jù)接口wrapStyle傳入樣式的數(shù)據(jù)類(lèi)型來(lái)處理style,最終得到的style可能是對(duì)象或者字符串
    if (Array.isArray(this.wrapStyle)) {
      style = toObject(this.wrapStyle);
      style.marginRight = style.marginBottom = gutterWith;
    } else if (typeof this.wrapStyle === 'string') {
      style += gutterStyle;
    } else {
      style = gutterStyle;
    }
  }
  
  ...
}

這一塊代碼中最重要的知識(shí)點(diǎn)就是獲取瀏覽器原生滾動(dòng)條寬度的方式了元潘,為此element專(zhuān)門(mén)定義了一個(gè)方法scrllbarWidth,這個(gè)方法是從外部導(dǎo)入進(jìn)來(lái)的 import scrollbarWidth from 'element-ui/src/utils/scrollbar-width';畔乙,我們一起來(lái)看一下這個(gè)函數(shù):

import Vue from 'vue';

let scrollBarWidth;

export default function() {
  if (Vue.prototype.$isServer) return 0;
  if (scrollBarWidth !== undefined) return scrollBarWidth;

  const outer = document.createElement('div');
  outer.className = 'el-scrollbar__wrap';
  outer.style.visibility = 'hidden';
  outer.style.width = '100px';
  outer.style.position = 'absolute';
  outer.style.top = '-9999px';
  document.body.appendChild(outer);

  const widthNoScroll = outer.offsetWidth;
  outer.style.overflow = 'scroll';

  const inner = document.createElement('div');
  inner.style.width = '100%';
  outer.appendChild(inner);

  const widthWithScroll = inner.offsetWidth;
  outer.parentNode.removeChild(outer);
  scrollBarWidth = widthNoScroll - widthWithScroll;

  return scrollBarWidth;
};

其實(shí)也很簡(jiǎn)單,就是動(dòng)態(tài)創(chuàng)建一個(gè)body的子元素outer翩概,給固定寬度100px牲距,并且將overflow設(shè)置為scroll,這樣wrap就產(chǎn)生滾動(dòng)條了钥庇,這個(gè)時(shí)候再動(dòng)態(tài)創(chuàng)建一個(gè)outer的子元素inner牍鞠,將其寬度設(shè)置為100%。由于outer有滾動(dòng)條存在评姨,inner的寬度必然不可能等于outer的寬度难述,此時(shí)用outer的寬度減去inner的寬度,得出的就是瀏覽器滾動(dòng)條的寬度了吐句。是不是也很簡(jiǎn)單啊胁后,最后記得從body中銷(xiāo)毀動(dòng)態(tài)創(chuàng)建outer元素哦。

回過(guò)頭來(lái)我們接著看render函數(shù)嗦枢,在根據(jù)瀏覽器寬度及wrapStyle動(dòng)態(tài)生成樣式變量style之后攀芯,接下來(lái)就是在render函數(shù)中生成ScrollBar組件的 HTML了。

// 生成view節(jié)點(diǎn)文虏,并且將默認(rèn)slots內(nèi)容插入到view節(jié)點(diǎn)下
const view = h(this.tag, {
  class: ['el-scrollbar__view', this.viewClass],
  style: this.viewStyle,
  ref: 'resize'
}, this.$slots.default);

// 生成wrap節(jié)點(diǎn)侣诺,并且給wrap綁定scroll事件
const wrap = (
  <div
    ref="wrap"
    style={ style }
        onScroll={ this.handleScroll }
        class={ [this.wrapClass, 'el-scrollbar__wrap', gutter ? '' : 'el-scrollbar__wrap--hidden-default'] }>
        { [view] }
    </div>
);

接著是根據(jù)native來(lái)組裝wrap,view生成整個(gè)HTML節(jié)點(diǎn)數(shù)了。

let nodes;

if (!this.native) {
  nodes = ([
    wrap,
    <Bar
        move={ this.moveX }
            size={ this.sizeWidth }></Bar>,
        <Bar
      vertical
      move={ this.moveY }
      size={ this.sizeHeight }></Bar>
    ]);
} else {
  nodes = ([
    <div
      ref="wrap"
      class={ [this.wrapClass, 'el-scrollbar__wrap'] }
            style={ style }>
             { [view] }
        </div>
    ]);
}
return h('div', { class: 'el-scrollbar' }, nodes);

可以看到如果native為false择葡,則使用自定義的滾動(dòng)條紧武,如果為true,則不使用自定義滾動(dòng)條敏储。簡(jiǎn)化上面的render函數(shù)生成的HTML如下:

<div class="el-scrollbar">
  <div class="el-scrollbar__wrap">
    <div class="el-scrollbar__view">
        this.$slots.default
    </div>
  </div>
  <Bar vertical move={ this.moveY } size={ this.sizeHeight } />
  <Bar move={ this.moveX } size={ this.sizeWidth } />
</div>

最外層的el-scrollbar設(shè)置了overflow:hidden,用來(lái)隱藏wrap中產(chǎn)生的瀏覽器原生滾動(dòng)條阻星。使用ScrollBar組建時(shí),寫(xiě)在ScrollBar組件中的內(nèi)容都將通過(guò)slot分發(fā)到view內(nèi)部。另外這里使用move妥箕,size和vertical三個(gè)接口調(diào)用了Bar組件滥酥,這個(gè)組件就是原理圖上的Track和Thumb了。下面我們來(lái)看一下Bar組件:

props: {
  vertical: Boolean,  // 當(dāng)前Bar組件是否為垂直滾動(dòng)條
  size: String,  // 百分?jǐn)?shù)畦幢,當(dāng)前Bar組件的thumb長(zhǎng)度 / track長(zhǎng)度的百分比 
  move: Number   // 滾動(dòng)條向下/向右發(fā)生transform: translate的值
},

Bar組件的行為都是由這三個(gè)接口來(lái)進(jìn)行控制的坎吻,在前面的分析中,我們可以看到宇葱,在scrollbar中調(diào)用Bar組件時(shí)瘦真,分別傳入了這三個(gè)props。那么父組件是如何初始化以及更新這三個(gè)參數(shù)的值黍瞧,從而達(dá)到更新Bar組件的呢诸尽。首先在mounted鉤子中調(diào)用update方法對(duì)size進(jìn)行初始化:

update() {
  let heightPercentage, widthPercentage;
  const wrap = this.wrap;
  if (!wrap) return;

  heightPercentage = (wrap.clientHeight * 100 / wrap.scrollHeight);
  widthPercentage = (wrap.clientWidth * 100 / wrap.scrollWidth);

  this.sizeHeight = (heightPercentage < 100) ? (heightPercentage + '%') : '';
  this.sizeWidth = (widthPercentage < 100) ? (widthPercentage + '%') : '';
}

可以看到,這里核心的內(nèi)容就是計(jì)算thumb的長(zhǎng)度heightPercentage/widthPercentage印颤。這里使用wrap.clientHeight / wrap.scrollHeight得出了thumb長(zhǎng)度的百分比您机。這是為什么呢?

分析前面我們畫(huà)的那張scrollbar的原理圖年局,thumb在track中上下滾動(dòng)际看,可滾動(dòng)區(qū)域view在可視區(qū)域wrap中上下滾動(dòng),可以將thumb和track的這種相對(duì)關(guān)系看作是wrap和view相對(duì)關(guān)系的一個(gè)微縮模型(微縮反應(yīng))矢否,而滾動(dòng)條的意義就是用來(lái)反映view和wrap的這種相對(duì)運(yùn)動(dòng)關(guān)系的仲闽。從另一個(gè)角度,我們可以將view在wrap中的滾動(dòng)反過(guò)來(lái)看成是wrap在view中的上下滾動(dòng)僵朗,這不就是一個(gè)放大版的滾動(dòng)條嗎蔼囊?

根據(jù)這種相似性,我們可以得出一個(gè)比例關(guān)系: wrap.clientHeight / wrap.scrollHeight = thumb.clientHeight / track.clientHeight衣迷。在這里畏鼓,我們并不需要求出具體的thumb.clientHeight的值,只需要根據(jù)thumb.clientHeight / track.clientHeight的比值壶谒,來(lái)設(shè)置thumb 的css百分比就可以了云矫。

另外還有一個(gè)需要注意的地方,就是當(dāng)這個(gè)比值大于等于100%的時(shí)候汗菜,也就是wrap.clientHeight(容器高度)大于等于 wrap.scrollHeight(滾動(dòng)高度)的時(shí)候让禀,此時(shí)就不需要滾動(dòng)條了,因此將size置為空字符串陨界。

接下來(lái)我們?cè)賮?lái)看一下move巡揍,也就是滾動(dòng)條滾動(dòng)位置的更新。

handleScroll() {
  const wrap = this.wrap;

  this.moveY = ((wrap.scrollTop * 100) / wrap.clientHeight);
  this.moveX = ((wrap.scrollLeft * 100) / wrap.clientWidth);
}

moveX/moveY用來(lái)控制滾動(dòng)條的滾動(dòng)位置菌瘪,當(dāng)這個(gè)值傳給Bar組件時(shí)腮敌,Bar組件render函數(shù)中會(huì)調(diào)用renderThumbStyle方法將它轉(zhuǎn)化為trumb的樣式transform: translateX(${moveX}%) / transform: translateY(${moveY}%)阱当。有之前分析的相似關(guān)系可知,當(dāng)wrap.scrollTop正好等于wrap.clientHeight的時(shí)候糜工,thumb正好應(yīng)該向下滾動(dòng)它自身長(zhǎng)度的距離弊添,也就是transform: translateY(100%),一次可知捌木,當(dāng)wrap滾動(dòng)的時(shí)候油坝,thubm應(yīng)該向下滾動(dòng)的距離正好是 transform: translateY(wrap.scrollTop / wrap.clientHeight )。這就是wrap滾動(dòng)函數(shù)handleScroll中的邏輯所在刨裆。

現(xiàn)在我們已經(jīng)完全弄清楚了scrollbar組件中的所有邏輯澈圈,接下來(lái)我們?cè)倏纯碆ar組件在接收到props之后是如何處理的。

render(h) {
  const { size, move, bar } = this;

  return (
    <div
      class={ ['el-scrollbar__bar', 'is-' + bar.key] }
      onMousedown={ this.clickTrackHandler } >
      <div
        ref="thumb"
        class="el-scrollbar__thumb"
        onMousedown={ this.clickThumbHandler }
        style={ renderThumbStyle({ size, move, bar }) }>
      </div>
    </div>
  );
}

render函數(shù)獲取父組件傳遞的size帆啃,move之后极舔,通過(guò)renderThumbStyle來(lái)生成thumb,并且給track和thumb分別綁定了onMousedown事件。

clickThumbHandler(e) {
  this.startDrag(e);
  // 記錄this.y , this.y = 鼠標(biāo)按下點(diǎn)到thumb底部的距離
  // 記錄this.x , this.x = 鼠標(biāo)按下點(diǎn)到thumb左側(cè)的距離
  this[this.bar.axis] = (e.currentTarget[this.bar.offset] - (e[this.bar.client] - e.currentTarget.getBoundingClientRect()[this.bar.direction]));
},
 
// 開(kāi)始拖拽函數(shù)
startDrag(e) {
  e.stopImmediatePropagation();
  // 標(biāo)識(shí)位链瓦, 標(biāo)識(shí)當(dāng)前開(kāi)始拖拽
  this.cursorDown = true;

  // 綁定mousemove和mouseup事件
  on(document, 'mousemove', this.mouseMoveDocumentHandler);
  on(document, 'mouseup', this.mouseUpDocumentHandler);
  
  // 解決拖動(dòng)過(guò)程中頁(yè)面內(nèi)容選中的bug
  document.onselectstart = () => false;
},
  
mouseMoveDocumentHandler(e) {
  // 判斷是否在拖拽過(guò)程中,
  if (this.cursorDown === false) return;
  // 剛剛記錄的this.y(this.x) 的值
  const prevPage = this[this.bar.axis];

  if (!prevPage) return;

  // 鼠標(biāo)按下的位置在track中的偏移量盯桦,即鼠標(biāo)按下點(diǎn)到track頂部(左側(cè))的距離
  const offset = ((this.$el.getBoundingClientRect()[this.bar.direction] - e[this.bar.client]) * -1);
  // 鼠標(biāo)按下點(diǎn)到thumb頂部(左側(cè))的距離
  const thumbClickPosition = (this.$refs.thumb[this.bar.offset] - prevPage);
  // 當(dāng)前thumb頂部(左側(cè))到track頂部(左側(cè))的距離慈俯,即thumb向下(向右)偏移的距離 占track高度(寬度)的百分比
  const thumbPositionPercentage = ((offset - thumbClickPosition) * 100 / this.$el[this.bar.offset]);
    // wrap.scrollHeight / wrap.scrollLeft * thumbPositionPercentage得到wrap.scrollTop / wrap.scrollLeft
  // 當(dāng)wrap.scrollTop(wrap.scrollLeft)發(fā)生變化的時(shí)候,會(huì)觸發(fā)父組件wrap上綁定的onScroll事件拥峦,
  // 從而重新計(jì)算moveX/moveY的值贴膘,這樣thumb的滾動(dòng)位置就會(huì)重新渲染
  this.wrap[this.bar.scroll] = (thumbPositionPercentage * this.wrap[this.bar.scrollSize] / 100);
},

mouseUpDocumentHandler(e) {
  // 當(dāng)拖動(dòng)結(jié)束,將標(biāo)識(shí)位設(shè)為false
  this.cursorDown = false;
  // 將上一次拖動(dòng)記錄的this.y(this.x)的值清空
  this[this.bar.axis] = 0;
  // 取消頁(yè)面綁定的mousemove事件
  off(document, 'mousemove', this.mouseMoveDocumentHandler);
  // 清空onselectstart事件綁定的函數(shù)
  document.onselectstart = null;
}

上面的代碼就是thumb滾動(dòng)條拖拽的所有處理邏輯略号,整體思路就是在拖拽thumb的過(guò)程中刑峡,動(dòng)態(tài)的計(jì)算thumb頂部(左側(cè))到track頂部(左側(cè))的距離占track本身高度(寬度)的百分比,然后利用這個(gè)半分比動(dòng)態(tài)改變wrap.scrollTop的值玄柠,從而觸發(fā)頁(yè)面滾動(dòng)以及滾動(dòng)條位置的重新計(jì)算突梦,實(shí)現(xiàn)滾動(dòng)效果。


微信圖片_20190121160845.jpg

上一個(gè)圖方便大家理解吧( ̄▽?zhuān)?"

track的onMousedown和trumb的邏輯也差不多羽利,有兩點(diǎn)需要注意:

  1. track的onMousedown事件回調(diào)中不會(huì)給頁(yè)面綁定mousemove和mouseup事件宫患,因?yàn)閠rack相當(dāng)于click事件
  2. 在track的onmousedown事件中,我們計(jì)算thumb頂部到track頂部的方式是这弧,用鼠標(biāo)點(diǎn)擊點(diǎn)到track頂部的距離減去thumb的二分之一高度娃闲,這是因?yàn)辄c(diǎn)擊track之后,thumb的中點(diǎn)剛好要在鼠標(biāo)點(diǎn)擊點(diǎn)的位置匾浪。

至此皇帮,整個(gè)scrollbar源碼的就分析結(jié)束了,回過(guò)頭來(lái)看看蛋辈,其實(shí)scrollbar的實(shí)現(xiàn)并不難属拾,主要還是要理清各種滾動(dòng)關(guān)系、thumb的長(zhǎng)度以及滾動(dòng)位置怎么通過(guò)wrap,view之間的關(guān)系來(lái)確定捌年。這一部分可能比較繞瓢娜,沒(méi)搞懂的同學(xué)建議自己手動(dòng)畫(huà)畫(huà)圖研究一下,只要搞懂這個(gè)滾動(dòng)原理礼预,實(shí)現(xiàn)起來(lái)就很簡(jiǎn)單了眠砾。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市托酸,隨后出現(xiàn)的幾起案子褒颈,更是在濱河造成了極大的恐慌,老刑警劉巖励堡,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谷丸,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡应结,警方通過(guò)查閱死者的電腦和手機(jī)刨疼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)鹅龄,“玉大人揩慕,你說(shuō)我怎么就攤上這事“缧荩” “怎么了迎卤?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)玷坠。 經(jīng)常有香客問(wèn)我蜗搔,道長(zhǎng),這世上最難降的妖魔是什么八堡? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任樟凄,我火速辦了婚禮,結(jié)果婚禮上兄渺,老公的妹妹穿的比我還像新娘不同。我一直安慰自己,他們只是感情好溶耘,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布二拐。 她就那樣靜靜地躺著,像睡著了一般凳兵。 火紅的嫁衣襯著肌膚如雪百新。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,166評(píng)論 1 284
  • 那天庐扫,我揣著相機(jī)與錄音饭望,去河邊找鬼仗哨。 笑死,一個(gè)胖子當(dāng)著我的面吹牛铅辞,可吹牛的內(nèi)容都是我干的厌漂。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼斟珊,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼苇倡!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起囤踩,我...
    開(kāi)封第一講書(shū)人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤旨椒,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后堵漱,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體综慎,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年勤庐,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了示惊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡愉镰,死狀恐怖米罚,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情岛杀,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布崭孤,位于F島的核電站类嗤,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏辨宠。R本人自食惡果不足惜遗锣,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望嗤形。 院中可真熱鬧精偿,春花似錦、人聲如沸赋兵。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)霹期。三九已至叶组,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間历造,已是汗流浹背甩十。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工船庇, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人侣监。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓鸭轮,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親橄霉。 傳聞我的和親對(duì)象是個(gè)殘疾皇子窃爷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

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

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件酪劫、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,033評(píng)論 4 62
  • 組件要求 1 .直接引入就可以使用吞鸭,新傳入的值可以和原來(lái)的值復(fù)用2 .默認(rèn)顯示全屏,然后自適應(yīng)高度 layout ...
    skoll閱讀 657評(píng)論 0 0
  • 2015年4月9日雨天覆糟,看后感刻剥。 月島雯是個(gè)很努力的女孩子,她很愛(ài)看書(shū)滩字,一次偶然的機(jī)會(huì)她看到了借書(shū)證上天澤圣司的名...
    王伯弦閱讀 576評(píng)論 0 4
  • 1.感恩志超早起為顧客做售后造虏,謝謝謝謝謝謝 2.感恩減肥的顧客們積極的配合。謝謝謝謝謝謝 3.感恩積極配合的經(jīng)銷(xiāo)商...
    陽(yáng)光之旅001閱讀 167評(píng)論 0 1
  • 文/十月云 1. 每個(gè)人來(lái)到這個(gè)世界上都有自己的專(zhuān)屬使命麦箍,我們要做的是: 找到它漓藕,完成它。 2. 有趣的事情都有意...
    十月云閱讀 486評(píng)論 2 49