使用element-ui + cropper.js自己封裝一個圖片裁剪組件

本文主要使用了element-ui的圖片上傳組件獲取圖片思犁,然后使用cropper.js進(jìn)行圖片裁剪逊笆,在裁剪完以后進(jìn)行格式轉(zhuǎn)換拂苹,然后自行圖片上傳,文中的css使用了stylus編譯矮湘,如果不是請自行更改

裁剪效果如圖

1.插件安裝

npm install cropperjs --save

element-ui的安裝就不予以贅述了斟冕,主要使用了element-ui的圖片上傳以及$message

2.組件編寫

  • 目錄新建

components文件夾下新建upload文件夾口糕,然后在upload文件夾下新建 cropperBox.vue 以及 upCover.vue

  • 編寫cropperBox.vue

cropperBox.vue中寫入以下內(nèi)容,(finishCropImage方法中的blob的數(shù)據(jù)格式請自行選擇以下兩種缅阳,第一種是blob,第二種是普通文件方式。)

<template>
  <div class="cropper-wrap">
    <div class="cropper-alert-mask" :class="{ show: imgHasLoad }"></div>
    <div class="cropper-alert" :class="{ show: imgHasLoad }">
      <div class="cropper">
        <span class="layout-icon-wrap"><i class="el-icon-circle-close" @click="imgHasLoad=false"></i></span>
        <div class="cropper-box">
          <img ref="uploadPreview" style="width:100px;height:auto;">
        </div>
        <div class="cropper-res-wrap">
          <div class="cropper-res" id="cropperRes">
            <img style="width:100px;height:100px;">
          </div>
        </div>
      </div>
      <div class="cropper-btns-wrap">
        <el-progress
          :text-inside="true"
          :stroke-width="30"
          :percentage="uploadProgress">
        </el-progress>
        <button
          type="button"
          class="cropper-btn"
          @click="finishCropImage"
          :disabled="btnTips.disable"
          :class="{'btn-bg': uploading}">
          {{ btnTips.value }}
        </button>
      </div>
    </div>
  </div>
</template>

<script>
import Cropper from 'cropperjs'

export default {
  name: 'cropper-box',
  props: {
    options: {
      default: {
        aspectRatio: 1 / 1,
        preview: '#cropperRes',
        zoomOnWheel: false,
        minCropBoxWidth: 50
      }
    },
    uploadProgress: {
      default: 0
    }
  },
  data () {
    return {
      cropper: null,
      imgHasLoad: false,
      cropperHasInit: false,
      uploading: false,
      rawFile: null
    }
  },
  watch: {
    imgHasLoad (val) {
      if (!val) {
        this.uploading = false
      }
    }
  },
  computed: {
    btnTips () {
      if (this.uploading) {
        return {
          value: '正在上傳十办,請稍等',
          disable: true
        }
      }
      return {
        value: '裁剪完成秀撇,立即上傳',
        disable: false
      }
    }
  },
  methods: {
    show () {
      this.imgHasLoad = true
    },
    close () {
      this.imgHasLoad = false
    },
    loadCropper (rawFile) {
      this.rawFile = rawFile
      const URL = window.URL || window.webkitURL
      const blobURL = URL.createObjectURL(rawFile)
      var image = this.$refs.uploadPreview
      if (!this.cropper) this.cropper = new Cropper(image, this.options)
      this.cropper.reset().replace(blobURL)
    },
    // 完成裁剪,將文件進(jìn)行格式轉(zhuǎn)換向族,發(fā)送給父組件呵燕,請自行選擇普通文件格式還是blob格式,格式轉(zhuǎn)換方法已封裝件相,請看下面的兩個方法
    finishCropImage () {
      this.uploading = true

      const croppedCanvas = this.cropper.getCroppedCanvas()
      const croppedDataUrl = croppedCanvas.toDataURL(this.rawFile.type)
      const blob = this.base64toFile(croppedDataUrl)
      this.$emit('finishCropImage', blob)
    },
    // dataUrl 轉(zhuǎn) blob
    dataURLtoBlob (dataurl) {
      /* eslint-disable */
      var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1];
      var bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
      while(n--){
        u8arr[n] = bstr.charCodeAt(n);
      }
      return new Blob([u8arr], {type:mime});
      /* eslint-enable */
    },
    //base64轉(zhuǎn)為普通文件格式
    base64toFile (dataurl, filename = 'file') {
      let arr = dataurl.split(',')
      let mime = arr[0].match(/:(.*?);/)[1]
      let suffix = mime.split('/')[1]
      let bstr = atob(arr[1])
      let n = bstr.length
      let u8arr = new Uint8Array(n)
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n)
      }
      return new File([u8arr], `${filename}.${suffix}`, {
        type: mime
      })
    },
  }
}
</script>

<style lang="stylus">
  @import "cropperjs/dist/cropper.min.css"

.cropper-wrap
  .cropper-alert-mask
    position: fixed
    top: 0
    left: 0
    right: 0
    bottom: 0
    z-index: 2000
    background-color: rgba(#000000, .5)
    visibility: hidden
    height: 0
    transition: all .3s ease
  .cropper-alert-mask.show
    visibility: visible
    height: 100%
  .cropper-alert
    opacity: 0
    transition: all .3s ease
    visibility: hidden
    padding: 10px
    position: fixed
    z-index: 2000
    top: 50px
    left: 50%
    transform: translateX(-50%) scale(2)
    background-color: #ffffff
    border-radius: 5px
    overflow: hidden
    width: 100%
    height: 100%
    max-width: 600px
    max-height: 530px
    &.show
      opacity: 1
      visibility: visible
      transform: translateX(-50%) scale(1)
    .cropper
      position: relative
      max-width: 600px
      max-height: 460px
      height: 100%
      padding: 10px
      padding-right: 120px
      @media (max-width: 1324px)
        padding-top: 120px
        padding-right: 10px
      background-color: #f9fbfc
      .layout-icon-wrap
        position: absolute
        cursor: pointer
        right: 0px
        top: 0px
        font-size: 20px
      .cropper-box
        position: relative
        width: 100%
        height: 100%
        background-color: #ffffff
      .cropper-res-wrap
        position: absolute
        top: 50%
        transform: translateY(-50%)
        @media (max-width: 1324px)
          top: 0
          left: 50%
          transform: translateX(-50%)
        right: 0
        width: 100px
        height: auto
        padding: 10px
        background-color: #a8a8a8
        box-sizing: content-box
        .cropper-res
          width: 100px
          height: 100px
          overflow: hidden
          background-color: #ffffff
    .cropper-btns-wrap
      position: relative
      margin-top: 20px
      .cropper-btn
        position: absolute
        left: 0
        top: 0
        width: 100%
        height: 30px
        line-height: 1
        background: #ffffff
        border: 1px solid #e1e1e1
        border-radius: 15px
        color: #666666
        cursor: pointer
      .btn-bg
        background: #FF000000
</style>
  • 編寫upCover.vue

upCover.vue中寫入以下內(nèi)容,(finishCropImage方法中請自行補(bǔ)充圖片上傳調(diào)用接口的方法)

<template>
  <div
    class="cover-upload-wrap"
    ref=coverOutWrap
    :style="{
      width: width ? (width + 'px') : '100%',
      height: calcHeight + 'px',
      maxWidth: maxWidth ? (maxWidth + 'px') : '100px',
      maxHeight: maxHeight ? (maxHeight + 'px') : '100px'
    }">
    <el-upload
      ref="upload"
      class="cover-uploader"
      :show-file-list="false"
      :before-upload="beforeVipImageUpload"
      :auto-upload="false"
      :on-change="onFileChange"
      :on-progress="onUploadProgress">
      <div class="img-wrap">
        <img :src="imageUrl" class="cover" v-if="imageUrl">
        <div class="img-mask-default" :class="{'img-mask': imageUrl}">
          <i class="el-icon-upload"></i>
          <div>{{ tip }}</div>
        </div>
      </div>
    </el-upload>
    <cropperBox
      ref="cropperBox"
      :options="options"
      :uploadProgress="uploadProgress"
      @finishCropImage="finishCropImage">
    </cropperBox>
  </div>
</template>
<script>
import uploadImage from "../../mixins/uploadImage";
import cropperBox from './cropperBox'
import {upload} from "../../api/base";

export default {
  name: 'up-cover',
  mixins:[uploadImage],
  components: {
    cropperBox
  },
  props: {
    defaultImg: String,
    ratio: { // 裁剪結(jié)果寬高比
      default: 1
    },
    width: [Number,String],
    height: [Number,String],
    WHRatio: { // 組件寬高比
      default: 1
    },
    cropBoxResizable:Boolean,    //是否可以修改裁剪框的尺寸
    maxWidth: String,
    maxHeight: String,
    tip: {
      default: '上傳圖片'
    },
    maxSize: { // 最大選擇圖片的大小再扭,單位M
      default: 3
    }
  },
  data () {
    return {
      cropper: null,
      newFile: null,
      options: {
        aspectRatio: 2.166,
        preview: '#cropperRes',
        zoomOnWheel: false,
        cropBoxResizable:false,
        minCropBoxWidth: 50,
        viewMode:3
      },
      token: {},
      uploadProgress: 0,
      calcHeight: 0
    }
  },
  created() {
    this.options.aspectRatio = this.ratio;
    this.options.cropBoxResizable = this.cropBoxResizable;
    if (this.height) {
      this.calcHeight = this.height
    }
  },
  computed: {
    imageUrl () {
      return this.defaultImg
    }
  },
  mounted() {
    if (!this.calcHeight) {
      if (this.width) {
        this.calcHeight = this.width / this.WHRatio
      } else {
        this.calcHeight = this.$refs.coverOutWrap.offsetWidth / this.WHRatio
      }
    }
  },
  methods: {
    //截取圖片上傳的事件,有圖片的情況就打開裁剪框夜矗,并且將文件傳入到裁剪框中
    onFileChange (file, fileList) {
      if (file.status === 'ready') {
        this.$refs.cropperBox.show();
        this.$refs.cropperBox.loadCropper(file.raw)
      }
    },
    //文件裁剪泛范,nerFile就是最終拿到的文件,自行調(diào)接口進(jìn)行圖片上傳
    finishCropImage (newFile) {
      this.newFile = newFile;
      //圖片上傳調(diào)接口請自行補(bǔ)充
    },
    //上傳圖片之前的大小檢測紊撕,文件大小通過prop傳遞罢荡,可在組件使用自定義文件大小限制
    beforeVipImageUpload(file){
        const isLt3M = file.size / 1024 / 1024 < this.maxSize;
        if (!isLt3M) {
            this.$message.error('上傳圖片大小不可大于' + this.maxSize + 'M');
        }
        return isLt3M;
        let uploadFile = new window.File([this.newFile], file.name, { type: this.newFile.type });
        uploadFile.uid = this.newFile.uid;
        return Promise.resolve(uploadFile)
    },
    //文件上傳進(jìn)度
    onUploadProgress (event, file, fileList) {
      this.uploadProgress = parseInt(event.percent) - 1
    }
  }
}
</script>
<style lang="stylus">
.cover-upload-wrap
  position: relative
  width: 100%
  max-width: 300px
  height: 150px
  border-radius: 5px
  .cover-uploader
    width: 100%
    height: 100%
    .el-upload
      width: 100%
      height: 100%
      overflow: hidden
      border-radius: 5px
      cursor: pointer
      border: 1px solid #dddddd
      .img-wrap
        position: relative
        width: 100%
        height: 100%
        &:hover
          .img-mask-default
            opacity: 1
            background-color: rgba(0, 0, 0, 0.5)
            color: #ffffff
        .cover
          position: relative
          width: 100%
          height: 100%
          border-radius: 5px
        .img-mask-default
          position: absolute
          left: 0
          top: 0
          width: 100%
          height: 100%
          padding-left: 10px
          padding-right: 10px
          background-color: #ffffff
          color: #555555
          display: flex
          flex-direction: column
          justify-content: center
          font-size: 12px
          transition: all .2s linear
          .el-icon-upload
            font-size: 18px
        .img-mask
          opacity: 0

</style>

使用方法

  • 引入插件
import UP from '@/components/upload/upCover'

export default {
      components:{UP},
}
  • 在頁面中使用

pictureUrl就是圖片上傳成功以后顯示的回調(diào)地址,請自行填寫对扶,maxSize可以限定上傳圖片時候的尺寸大小区赵,width和height限定組件大小,

<UP class="upload-cover"
    :default-img="pictureUrl?pictureUrl:''"
    ratio="2.166"
    :cropBoxResizable="true"
    width="156"
    height="72"
    tip="上傳等級圖標(biāo)"
    maxSize="3"
    @uploadSuccess="uploadSuccess">
</UP>

uploadSuccess方法中可以拿到圖片上傳成功以后的回調(diào)浪南,具體操作自行補(bǔ)充啦

uploadSuccess(res){
    //this.pictureUrl=res.data
},

更多操作

javascript操作

this.myCropper.getCroppedCanvas().toDataURL('image/jpeg') //拿到裁剪后的base64的圖片
this.myCropper.getCropBoxData();    //獲取裁剪框數(shù)據(jù)
this.myCropper.setCropBoxData();    //設(shè)置裁剪框數(shù)據(jù)
this.myCropper.getCanvasData();      //獲取圖片數(shù)據(jù)
this.myCropper.setCanvasData();      //設(shè)置圖片數(shù)據(jù)

配置對象

  • viewMode 視圖控制
    • 0 無限制
    • 1 限制裁剪框不能超出圖片的范圍
    • 2 限制裁剪框不能超出圖片的范圍 且圖片填充模式為 cover 最長邊填充
    • 3 限制裁剪框不能超出圖片的范圍 且圖片填充模式為 contain 最短邊填充
  • dragMode 拖拽圖片模式
    • crop 形成新的裁剪框
    • move 圖片可移動
    • none 什么也沒有
  • initialAspectRatio 裁剪框?qū)捀弑鹊某跏贾?默認(rèn)與圖片寬高比相同 只有在aspectRatio沒有設(shè)置的情況下可用
  • aspectRatio 設(shè)置裁剪框為固定的寬高比
  • data 之前存儲的裁剪后的數(shù)據(jù) 在初始化時會自動設(shè)置 只有在autoCrop設(shè)置為true時可用
  • preview 預(yù)覽 設(shè)置一個區(qū)域容器預(yù)覽裁剪后的結(jié)果
    • Element, Array (elements), NodeList or String (selector)
  • responsive 在窗口尺寸調(diào)整后 進(jìn)行響應(yīng)式的重渲染 默認(rèn)true
  • restore 在窗口尺寸調(diào)整后 恢復(fù)被裁剪的區(qū)域 默認(rèn)true
  • checkCrossOrigin 檢查圖片是否跨域 默認(rèn)true 如果是 會在被復(fù)制的圖片元素上加上屬性crossOrigin 并且在src上加上一個時間戳 避免重加載圖片時因為瀏覽器緩存而加載錯誤
  • checkOrientation 檢查圖片的方向信息(僅JPEG圖片有)默認(rèn)true 在旋轉(zhuǎn)圖片時會對圖片方向值做一些處理 以解決IOS設(shè)備上的一些問題
  • modal 是否顯示圖片和裁剪框之間的黑色蒙版 默認(rèn)true
  • guides 是否顯示裁剪框的虛線 默認(rèn)true
  • center 是否顯示裁剪框中間的 ‘+’ 指示器 默認(rèn)true
  • highlight 是否顯示裁剪框上面的白色蒙版 (很淡)默認(rèn)true
  • background 是否在容器內(nèi)顯示網(wǎng)格狀的背景 默認(rèn)true
  • autoCrop 允許初始化時自動的裁剪圖片 配合 data 使用 默認(rèn)true
  • autoCropArea 設(shè)置裁剪區(qū)域占圖片的大小 值為 0-1 默認(rèn) 0.8 表示 80%的區(qū)域
  • movable 是否可以移動圖片 默認(rèn)true
  • rotatable 是否可以旋轉(zhuǎn)圖片 默認(rèn)true
  • scalable 是否可以縮放圖片(可以改變長寬) 默認(rèn)true
  • zoomable 是否可以縮放圖片(改變焦距) 默認(rèn)true
  • zoomOnTouch 是否可以通過拖拽觸摸縮放圖片 默認(rèn)true
  • zoomOnWheel 是否可以通過鼠標(biāo)滾輪縮放圖片 默認(rèn)true
  • wheelZoomRatio 設(shè)置鼠標(biāo)滾輪縮放的靈敏度 默認(rèn) 0.1
  • cropBoxMovable 是否可以拖拽裁剪框 默認(rèn)true
  • cropBoxResizable 是否可以改變裁剪框的尺寸 默認(rèn)true
  • toggleDragModeOnDblclick 是否可以通過雙擊切換拖拽圖片模式(move和crop)默認(rèn)true 當(dāng)拖拽圖片模式為none時不可切換 該設(shè)置必須瀏覽器支持雙擊事件
  • minContainerWidth(200)笼才、minContainerHeight(100)、minCanvasWidth(0)络凿、minCanvasHeight(0)患整、minCropBoxWidth(0)、minCropBoxHeight(0) 容器喷众、圖片各谚、裁剪框的 最小寬高 括號內(nèi)為默認(rèn)值 注意 裁剪框的最小高寬是相對與頁面而言的 并非相對圖片

方法

  • crop() 手動顯示裁剪框
  • reset() 重置圖片和裁剪框為初始狀態(tài)
  • replace(url[, hasSameSize]) 替換圖片路徑并且重建裁剪框
    • url 新路徑
    • hasSameSize 默認(rèn)值false 設(shè)置為true表示新老圖片尺寸一樣 只需要更換路徑無需重建裁剪框
  • enable() 解凍 裁剪框
  • disable() 凍結(jié) 裁剪框
  • destroy() 摧毀裁剪框并且移除cropper實例
  • move(offsetX[, offsetY]) 移動圖片指定距離 一個參數(shù)代表橫縱向移動距離一樣
  • moveTo(x[, y]) 移動圖片到一個指定的點(diǎn) 一個參數(shù)代表橫縱向移動距離一樣
  • zoom(ratio) 縮放 ratio大于零是放大 小于零縮小
  • zoomTo(ratio[, pivot]) 縮放并設(shè)置中心點(diǎn)的位置
  • rotate(degree) 旋轉(zhuǎn) 類似css
  • rotateTo(degree) 旋轉(zhuǎn)到絕對角度
  • scale(scaleX[, scaleY])、scaleX(scaleX)到千、scaleY(scaleY) 縮放 一個參數(shù)代表橫縱向縮放值一樣
  • getData([rounded]) 返回裁剪區(qū)域基于原圖片!原尺寸!的位置和尺寸 rounded默認(rèn)為false 表示是否顯示四舍五入后的數(shù)據(jù) 有了這些數(shù)據(jù)可以直接在原圖上進(jìn)行裁剪顯示
  • setData(data) 改變裁剪區(qū)域基于原圖的位置和尺寸 僅當(dāng)viewMode 不為0時有效
  • getContainerData()昌渤、getImageData()、getCanvasData()憔四、setCanvasData(data)膀息、getCropBoxData()、setCropBoxData(data) 容器了赵、圖片容器(畫布)潜支、圖片、裁剪區(qū)域相對容器的數(shù)據(jù)設(shè)置和獲取
  • getCroppedCanvas([options]) 得到被裁剪圖片的一個canvas對象 options設(shè)置這個canvas的一些數(shù)據(jù)
    • width柿汛、height冗酿、minWidth、minHeight、maxWidth裁替、maxHeight项玛、fillColor、imageSmoothingEnabled (圖片是否是光滑的 默認(rèn)true)弱判、imageSmoothingQuality(圖片的質(zhì)量 默認(rèn)low 還有medium襟沮、high)
  • setAspectRatio(aspectRatio) 改變裁剪區(qū)域的寬高比
  • setDragMode([mode]) 設(shè)置拖拽圖片模式

事件

  • ready 渲染前(圖片已經(jīng)被加載、cropper實例已經(jīng)準(zhǔn)備完畢)的準(zhǔn)備工作事件
  • cropstart昌腰、cropmove开伏、cropend、crop 開始畫裁剪框(或畫布)遭商、畫裁剪框(或畫布)的中途硅则、裁剪框(或畫布)畫完、進(jìn)行裁剪事件 event.detail.originalEvent株婴、event.detail.action
    • 當(dāng)autoCrop為true crop事件會在ready之前觸發(fā)
  • zoom 裁剪框縮放事件

本文參考于https://www.cnblogs.com/eightFlying/p/cropper-demo.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末怎虫,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子困介,更是在濱河造成了極大的恐慌大审,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件座哩,死亡現(xiàn)場離奇詭異徒扶,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)根穷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門姜骡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人屿良,你說我怎么就攤上這事圈澈。” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長述吸。 經(jīng)常有香客問我,道長啥么,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任贰逾,我火速辦了婚禮悬荣,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘疙剑。我一直安慰自己氯迂,他們只是感情好践叠,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著囚戚,像睡著了一般。 火紅的嫁衣襯著肌膚如雪轧简。 梳的紋絲不亂的頭發(fā)上驰坊,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天,我揣著相機(jī)與錄音哮独,去河邊找鬼拳芙。 笑死,一個胖子當(dāng)著我的面吹牛皮璧,可吹牛的內(nèi)容都是我干的舟扎。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼悴务,長吁一口氣:“原來是場噩夢啊……” “哼睹限!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起讯檐,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤羡疗,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后别洪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體叨恨,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年挖垛,在試婚紗的時候發(fā)現(xiàn)自己被綠了痒钝。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡痢毒,死狀恐怖送矩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情哪替,我是刑警寧澤益愈,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站夷家,受9級特大地震影響蒸其,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜库快,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一摸袁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧义屏,春花似錦靠汁、人聲如沸蜂大。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽奶浦。三九已至,卻和暖如春踢星,著一層夾襖步出監(jiān)牢的瞬間澳叉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工沐悦, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留成洗,地道東北人。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓藏否,卻偏偏與公主長得像瓶殃,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子副签,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評論 2 344