封裝一個動態(tài)表單吧

經(jīng)常做后臺的小伙伴兒可能經(jīng)常要遭遇各種表單結(jié)構(gòu)非迹,input,select纯趋,時間憎兽、日期插件等等,各種屬性配置到吐吵冒,今天就帶大家來封裝一個可復(fù)用表單纯命。表單參考了網(wǎng)上的一些例子,再結(jié)合自己的需求痹栖,封裝了一個自己的業(yè)務(wù)表單組件亿汞。
先上圖:


QQ截圖20201118163834.png

首先給大家看一下結(jié)構(gòu)布局:
我們現(xiàn)實放了一個form表單。然后利用el-form-item來循環(huán)遍歷揪阿,給每一個el-form-item設(shè)置動態(tài)label疗我,動態(tài)rules(校驗規(guī)則)以及相對應(yīng)的prop。
然后我們給每一種類型的表單元素添加動態(tài)disabled的屬性南捂,控制可編輯狀態(tài)吴裤。
給屬性綁定動態(tài)表單值,并且添加placeholder提示語溺健;
對于select嚼摩,checkbox等多值域綁定的表單元素,配置項中提供options屬性矿瘦。
然后我們的圖片上傳用的是我們之前封裝的圖片上傳組件枕面,傳遞一個綁定值和一個可編輯狀態(tài)即可。
最后我們給每個表單元素添加了一個tooltip缚去,用于提示用戶每一個表單元素要填寫的內(nèi)容或者提示語潮秘。對于每一個label標簽,我們也做了最基本的處理易结,大于四個字我們就給變成4字加省略號枕荞,通過tooltip來查看標簽名稱。

<template>
    <div>
        <el-form :label-position="labelPosition" :inline="inline" :label-width="labelWidth" :model="myForm" ref="customForm">
          <el-form-item v-for="(item,index) in formData" :label="returnLable(item.label)+':'" :rules="item.rules" :key="index" :prop="item.prop">
                <el-tooltip v-if="item.type == 'input'" :effect="effect" :content="'請?zhí)顚?+item.label" placement="top">
                    <!-- prefix-icon 首部圖標--><!-- suffix-icon 尾部圖標-->
                    <el-input 
                        v-model="myForm[item.prop]" clearable :suffix-icon="item.sufIcon" :show-password ="item.password"
                        :prefix-icon="item.preIcon" :placeholder="'選擇'+item.label" :disabled="item.disabled">
                    </el-input>
                </el-tooltip>
                <el-tooltip v-if="item.type == 'select'" :effect="effect" :content="'請選擇'+item.label" placement="top">
                    <el-select v-model="myForm[item.prop]" filterable clearable :multiple="item.multiple" filterable :placeholder="'選擇'+item.label" :disabled="item.disabled">
                        <el-option v-for="o in item.options" :key="o.value" :label="o.label" :value="o.value">
                        </el-option>
                    </el-select>
                </el-tooltip>
                <el-tooltip v-if="item.type == 'radio'" :effect="effect" :content="'請選擇'+item.label" placement="top">
                    <el-radio-group v-model="myForm[item.prop]" :disabled="item.disabled">
                        <el-radio v-for="o in item.options" :label="o.value" :placeholder="'選擇'+item.label">{{o.label}}</el-radio>
                    </el-radio-group>
                </el-tooltip>
                <el-tooltip v-if="item.type == 'checkbox'" :effect="effect" :content="'請選擇'+item.label" placement="top">
                    <el-checkbox-group v-model="myForm[item.prop]" :disabled="item.disabled">
                        <el-checkbox v-for="o in item.options" :label="o.value" :placeholder="'選擇'+item.label">{{o.label}}</el-checkbox>
                    </el-checkbox-group>
                </el-tooltip>
                <el-tooltip v-if="item.type == 'date'" :effect="effect" :content="'請選擇'+item.label" placement="top">
                    <el-date-picker
                        v-model="myForm[item.prop]" type="date" 
                        value-format="yyyy-MM-dd" 
                        :picker-options="pickerOptions" 
                        :placeholder="'選擇'+item.label" 
                        :disabled="item.disabled">
                    </el-date-picker>
                </el-tooltip>
                <el-tooltip v-if="item.type == 'datetime'" :effect="effect" :content="'請選擇'+item.label" placement="top">
                    <el-date-picker
                        v-model="myForm[item.prop]"
                        type="datetime"
                        value-format="yyyy-MM-dd HH:mm:ss"
                        :picker-options="pickerOptions"
                        :placeholder="'選擇'+item.label"
                        default-time="12:00:00"
                        :disabled="item.disabled">
                    </el-date-picker>
                </el-tooltip>
                <el-tooltip v-if="item.type == 'image'" :effect="effect" :content="'請選擇'+item.label" placement="top">
                    <upload-image v-model="myForm[item.prop]" :disabled="item.disabled"></upload-image>
                </el-tooltip>
          </el-form-item>
        </el-form>
        <el-form v-if="isHandle" style="padding-left: 20px;">
            <el-form-item>
              <slot name="handle"></slot>
            </el-form-item>
        </el-form>
    </div>
</template>

下面是組件內(nèi)的方法及屬性定義

<script>
    import uploadImage from '@/mycomponents/UploadImage/index.vue'
    export default {
        components:{uploadImage},
        props:{
            //ref命名
            formName:{
                type:String,
                default:'right'
            },
            //操作欄
            isHandle:{
                type:Boolean,
                default:true
            },
            //表單標簽位置
            labelPosition:{
                type:String,
                default:'right'
            },
            //tooltip風(fēng)格是dark還是light
            effect:{
                type:String,
                default:'light'
            },
            //表單元素是并列同行還是獨占一行
            inline:{
                type:Boolean,
                default:true
            },
            //表單標簽寬度
            labelWidth:{
                type:String,
                default:'100px'
            },
            //綁定的表單
            myForm:{
                type:Object,
                default:()=>{}
            },
            //表單配置數(shù)據(jù)
            formData:{
                type:Array,
                default:()=>[]
            }
        },
        data(){
            return {
                pickerOptions : {
                  shortcuts: [{
                    text: '今天',
                    onClick(picker) {
                      picker.$emit('pick', new Date())
                    }
                  }, {
                    text: '昨天',
                    onClick(picker) {
                      const date = new Date()
                      date.setTime(date.getTime() - 3600 * 1000 * 24)
                      picker.$emit('pick', date)
                    }
                  }, {
                    text: '一周前',
                    onClick(picker) {
                      const date = new Date()
                      date.setTime(date.getTime() - 3600 * 1000 * 24 * 7)
                      picker.$emit('pick', date)
                    }
                  }]
                }
            }
        },
        methods:{
            //過濾超長標簽
            returnLable(label){
                if(label.length>4){
                    return label.substring(0,4)+'...'
                }
                return label
            },
            // 表單驗證
            async submitForm(prop) {
                try {
                    return await this.$refs["customForm"].validate();
                } catch (error) {
                    return error;
                }
            },
        }
    }
</script>

我們在頁面里使用時搞动,只需要調(diào)用一下校驗方法躏精,看是否通過校驗即可,這里的表單校驗方法返回的是一個promise鹦肿,所以 這里用async 和 await搭配使用來renturn校驗flag矗烛。
再來看我們的組件應(yīng)用頁面;(這里的具體屬性可根據(jù)element文檔自行查看箩溃。)

<template>
    <div class="pages-container">
        <dynamic-form :myForm="myForm" :formData="formData" ref="dynamic">
            <div slot="handle">
                <el-button type="primary" @click="onSubmit()">{{submitText}}</el-button>
                <el-button type="warning">取消</el-button>
            </div>
        </dynamic-form>
        <div>提交狀態(tài):{{text}}</div>
        <!-- 表單使用說明 -->
        <p>基本使用定義一個myForm(表單綁定字段的對象集合)瞭吃,再定義一個配置項formData(表單需要配置的驗證方法碌嘀、元素類型、元素標簽名稱等)</p>
        <p>label:'用戶名',//表單元素的標簽名稱</p>
        <p>prop:'name',//表單元素需要綁定的字段</p>
        <p>type:'textInput',//表單元素類型歪架,類型在下方會有說明具體是什么元素</p>
        <p>preIcon:'',//input輸入框等元素首部圖標股冗,寫空就是不顯示</p>
        <p>sufIcon:'',//input輸入框等元素尾部圖標,寫空就是不顯示</p>
        <p>password:'',//input輸入框是否為密碼輸入</p>
        <p>disabled:'',//表單元素可編輯狀態(tài)</p>
        <p>rules:Check(true, null, 'blur', '用戶名不能為空'),//校驗規(guī)則和蚪,借鑒的是網(wǎng)上一個大神的封裝方法止状。Check中填寫的四個參數(shù)分別是:是否必填、正則方法名稱攒霹、觸發(fā)動作怯疤、校驗提示語
        </p>
        <p>
            <span>配置項屬性type值釋義:</span>
            <span>input : 普通輸入框</span>
            <span>select : 下拉框</span>
            <span>radio : 單選</span>
            <span>checkbox : 復(fù)選</span>
            <span>date : 日期</span>
            <span>dateTime : 日期時間</span>
            <span>image : 圖片</span>
        </p>
    </div>
</template>
<script>
    import DynamicForm from '@/mycomponents/Form/dynamic.vue'
    import { Check } from '@/utils/rule.js'
    export default {
        components:{DynamicForm},
        data(){
            const options = [{
          value: '1',
          label: '黃金糕'
        }, {
          value: '2',
          label: '雙皮奶'
        }, {
          value: '3',
          label: '蚵仔煎'
        }, {
          value: '4',
          label: '龍須面'
        }, {
          value: '5',
          label: '北京烤鴨'
        }]
            return {
                text:'',
                submitText:'編輯',
                //表單值綁定
                myForm:{
                    name:'',
                    vscode:'',
                    prodType:'',
                    prodp:'2',
                    commissions:['1','5'],
                    commdate:'',
                    commdatetime:'',
                    images:['https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif?imageView2/1/w/80/h/80'],
                },
                //基本的表單配置項示例、有需要可自行添加其他屬性
                formData:[
                    {
                        label:'用戶名',//標簽名稱
                        prop:'name',//字段值
                        type:'input',//表單元素類型
                        preIcon:'el-icon-search',//首部標簽剔蹋,input元素獨有
                        rules:Check(true, null, 'blur', '用戶名不能為空'),//校驗規(guī)則
                        disabled:true,
                    },
                    {
                        label:'管理員密碼',
                        prop:'vscode',
                        type:'input',
                        sufIcon:'',//尾部標簽,input元素獨有
                        password:true,//input是否是密碼類型
                        rules:Check(true, null, 'blur', '密碼不能為空'),
                        disabled:true,
                    },
                    {
                        label:'產(chǎn)品類型',
                        prop:'prodType',
                        type:'select',
                        rules:Check(true, null, 'change', '請選擇產(chǎn)品類型'),
                        options:options,
                        multiple:false,//select是否可以多選辅髓,多選綁定值要對應(yīng)變?yōu)閿?shù)組
                        disabled:true,
                    },
                    {
                        label:'產(chǎn)品分類',
                        prop:'prodp',
                        type:'radio',
                        rules:Check(true, null, 'change', '請選擇產(chǎn)品分類'),
                        options:options,//屬性選項值
                        disabled:true,
                    },
                    {
                        label:'訂單選擇',
                        prop:'commissions',
                        type:'checkbox',
                        rules:Check(true, null, 'change', '請訂單選擇'),
                        options:options,//屬性選項值
                        disabled:true,
                    },
                    {
                        label:'訂單日期',
                        prop:'commdate',
                        type:'date',
                        rules:Check(true, null, 'change', '請選擇訂單日期'),
                        disabled:true,
                    },
                    {
                        label:'訂單日期時間',
                        prop:'commdatetime',
                        type:'datetime',
                        rules:Check(true, null, 'change', '請選擇訂單日期時間'),
                        disabled:true,
                    },
                    {
                        label:'訂單圖標',
                        prop:'images',
                        type:'image',
                        rules:Check(true, null, 'change', '請選擇訂單圖標'),
                        disabled:true,
                    },
                ]
            }
        },
        mounted() {
            
        },
        methods:{

            //點擊提交泣崩,校驗表單,進行業(yè)務(wù)操作
            async onSubmit(){
                if(this.submitText == '編輯'){
                    this.formData.forEach(item=>{
                        item.disabled = false;
                    })
                    this.submitText = '提交'
                }else{
                    this.formData.forEach(item=>{
                        item.disabled = true;
                        this.submitText = '編輯'
                    })
                    let flag = await this.$refs.dynamic.submitForm();
                    if(flag){
                        this.text = "success submit"
                    }else{
                        this.text = "fail submit"
                    }
                }
                
            },
        }
    }
</script>

我的rules校驗方法是在網(wǎng)上看到的一個大神的校驗方法洛口,了解詳細矫付,拿來即用,給大家看一下第焰。

//Check方法
//校驗規(guī)則列表(可擴展)
const rules = {
  URL(url) {
    const regex = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?"\\+&%$#=~_-]+))*$/
    return valid(url, regex, "URL格式不正確")
  },

  LowerCase(str) {
    const regex = /^[a-z]+$/
    return valid(str, regex, "只能輸入小寫字母")
  },

  UpperCase(str) {
    const regex = /^[A-Z]+$/
    return valid(str, regex, "只能輸入大寫字母")
  },

  Alphabets(str) {
    const regex = /^[A-Za-z]+$/
    return valid(str, regex, "只能輸入字母")
  },

  Email(email) {
    const regex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
    return valid(email, regex, "郵箱地址格式不正確")
  },

  Mobile(mobile) {
    const regex = /^1\d{10}$/
    return valid(mobile, regex, "手機號格式不正確")
  },

  Phone(phone) {
    const regex = /^(0\d{2,3})?-?\d{7,8}$/
    return valid(phone, regex, "電話號碼格式不正確")
  },

  Postcode(postcode) {
    const regex = /^[0-9][0-9]{5}$/
    return valid(postcode, regex, "郵編格式不正確")
  },

  Number(num) {
    const regex = /^\d+$/
    return valid(num, regex, "只能輸入純數(shù)字")
  },

  Fax(fax) {
    const regex = /^(\d{3,4}-)?\d{7,8}$/
    return valid(fax, regex, "傳真格式不正確")
  },

  Int(num) {
    const regex = /^((0)|([1-9]\d*))$/
    return valid(num, regex, "只能輸入非負整數(shù)")
  },

  IntPlus(num){
    const regex = /^[1-9]\d*$/
    return valid(num, regex, "只能輸入正整數(shù)")
  },

  Float1(num){
    const regex = /^-?\d+(\.\d)?$/
    return valid(num, regex, "只能輸入數(shù)字买优,最多一位小數(shù)")
  },

  Float2(num){
    const regex = /^-?\d+(\.\d{1,2})?$/
    return valid(num, regex, "只能輸入數(shù)字,最多兩位小數(shù)")
  },

  Float3(num){
    const regex = /^-?\d+(\.\d{1,3})?$/
    return valid(num, regex, "只能輸入數(shù)字挺举,最多三位小數(shù)")
  },
  
  FloatPlus3(num){
    const regex = /^\d+(\.\d{1,3})?$/
    return valid(num, regex, "只能輸入數(shù)字杀赢,最多三位小數(shù)")
  },

  Encode(code){
    const regex = /^(_|-|[a-zA-Z0-9])+$/
    return valid(code, regex, "編碼只能使用字母、數(shù)字湘纵、下劃線脂崔、中劃線")
  },

  Encode2(code){
    const regex = /^[a-zA-Z0-9]+$/
    return valid(code, regex, "編碼只能使用字母、數(shù)字")
  },

  Encode3(code){
    const regex = /^(_|[a-zA-Z0-9])+$/
    return valid(code, regex, "編碼只能使用字母梧喷、數(shù)字砌左、下劃線")
  },

  IdCard(code){
    const regex = /^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/
    return valid(code, regex, "請輸入正確的身份證號碼")
  },
  
  USCC(code){
    const regex = /^[0-9A-Z]{18}/
    return valid(code, regex, "請輸入正確的社會信用號")
  },
  
  CarNum(code){
    const regex = /^(([京津滬渝冀豫云遼黑湘皖魯新蘇浙贛鄂桂甘晉蒙陜吉閩貴粵青藏川寧瓊使領(lǐng)][A-Z](([0-9]{5}[DF])|([DF]([A-HJ-NP-Z0-9])[0-9]{4})))|([京津滬渝冀豫云遼黑湘皖魯新蘇浙贛鄂桂甘晉蒙陜吉閩貴粵青藏川寧瓊使領(lǐng)][A-Z][A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9掛學(xué)警港澳使領(lǐng)]))$/i
    return valid(code, regex, "請輸入正確的車牌號")
  },
  
  CNandEN(code){
    const regex = /^[a-zA-Z\u4e00-\u9fa5]+$/
    return valid(code, regex, "只能使用中文、英文")
  },
  
  MobileOrPhone(val){
    const result = /^1\d{10}$/.test(val) || /^(0\d{2,3})?-?\d{7,8}$/.test(val)
    return valid(result, null, "手機或電話號格式不正確")
  }
}

//val:String 要校驗的值
//regex:RegExp 校驗正則,不是正則時val作為result的值
//msg:String 校驗不通過的錯誤信息
function valid(val, regex, msg){
  return {result: regex instanceof RegExp? regex.test(val) : !!val, errMsg: msg}
}

//required:Boolean 是否必填項铺敌,選填汇歹,默認"true"
//type:String/Function 校驗類型,選填偿凭,
//     String時必須是上面rules中存在的函數(shù)名产弹,
//     Function時只接收一個參數(shù)(輸入值),返回格式: {result:Boolean, errMsg:String}
//trigger:String 觸發(fā)動作弯囊,選填取视,默認"blur"
//nullMsg:String 未輸入的提示語笤妙,選填诵盼,required=true時有效
export function Check(required=true, type, trigger="blur", nullMsg="該字段為必填項"){
  const rule = { required: !!required, trigger}

  let check = null
  if(typeof type === "function"){
    check = type
  }else{
    check = type ? rules[type+""] : null
  }

  if(check){//存在規(guī)則時添加規(guī)則
    rule.validator = (r, v, c) => {
      const {result, errMsg} = check(v)
      if(required){
        //必填項: null,undefined,"","  " 都算無輸入內(nèi)容
        return (v==null || (v+"").trim()==="") ? c(new Error(nullMsg)) : result ? c() : c(new Error(errMsg))
      }
      //選填項: null,undefined,"" 都算無輸入內(nèi)容,"  "會被校驗
      return (v==null || (v+"")==="" || result) ? c() : c(new Error(errMsg))
    }
  }else{
    rule.message = nullMsg
  }

  return [rule]
}

校驗方法很完美。


QQ截圖20201118170100.png

寫到這里弟塞,我們的一個簡單的form表單封裝就完成了。有需要的小伙伴兒可以添加更多的元素進去叠萍,例如開關(guān)谓着,例如radio-button等等,這里的封裝元素也只添加了最基本的元素锐秦,想要的更多可以自行添加咪奖,示例都在上面。大家覺得對你有幫助的酱床,可以點個贊Q蛘浴!扇谣!謝謝C两荨!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
禁止轉(zhuǎn)載罐寨,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者靡挥。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市鸯绿,隨后出現(xiàn)的幾起案子跋破,更是在濱河造成了極大的恐慌,老刑警劉巖瓶蝴,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件毒返,死亡現(xiàn)場離奇詭異,居然都是意外死亡舷手,警方通過查閱死者的電腦和手機饿悬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來聚霜,“玉大人狡恬,你說我怎么就攤上這事⌒睿” “怎么了弟劲?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長姥芥。 經(jīng)常有香客問我兔乞,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任庸追,我火速辦了婚禮霍骄,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘淡溯。我一直安慰自己读整,他們只是感情好,可當我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布咱娶。 她就那樣靜靜地躺著米间,像睡著了一般。 火紅的嫁衣襯著肌膚如雪膘侮。 梳的紋絲不亂的頭發(fā)上屈糊,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天,我揣著相機與錄音琼了,去河邊找鬼逻锐。 笑死,一個胖子當著我的面吹牛雕薪,可吹牛的內(nèi)容都是我干的昧诱。 我是一名探鬼主播,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼蹦哼,長吁一口氣:“原來是場噩夢啊……” “哼鳄哭!你這毒婦竟也來了要糊?” 一聲冷哼從身側(cè)響起纲熏,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎锄俄,沒想到半個月后局劲,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡奶赠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年鱼填,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片毅戈。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡苹丸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出苇经,到底是詐尸還是另有隱情赘理,我是刑警寧澤,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布扇单,位于F島的核電站商模,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜施流,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一响疚、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧瞪醋,春花似錦忿晕、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蚓土,卻和暖如春宏侍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蜀漆。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工谅河, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人确丢。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓绷耍,卻偏偏與公主長得像,于是被迫代替她去往敵國和親鲜侥。 傳聞我的和親對象是個殘疾皇子褂始,可洞房花燭夜當晚...
    茶點故事閱讀 45,060評論 2 355

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