vue 自定義v-model 封裝地址選擇組件累铅,并實現(xiàn)數(shù)據(jù)綁定和表單驗證

vue 自定義v-model 封裝地址選擇組件跃须,并實現(xiàn)數(shù)據(jù)綁定和表單驗證

vue是雙向數(shù)據(jù)綁定的,v-model可以自動搜集數(shù)據(jù)娃兽,這在我們使用過程中可以說是非常方便菇民。但是,在開發(fā)中投储,如果想把代碼寫的更精簡第练,提供更多的復用。那么我們就免不了想自己封裝一個用有v-model屬性的組件轻要。(本人工作中复旬,就迫切有這種需求,因為表單頁面太大冲泥,如果不做封裝精簡驹碍,就算用了element-ui這種已經(jīng)封裝過的框架,頁面依然會很龐大7不小)

關(guān)于v-model

要實現(xiàn)自己的v-model志秃,首先要了解到,v-model實際上是由兩部分組成的嚼酝,即value和input事件浮还,例如下面兩行代碼,是等價的

<input v-model="name">
<input :value="name" @input="name=$event.target.value">

知道了原理闽巩,我們就可以開干了钧舌。
下面以分裝一個三聯(lián)動地址選擇的小組件為例担汤,使用的select基于element-ui
新建vue組件choose-address-form-item.vue
這里封裝一個表單中的地址選擇組件,所以默認認為他的父組件由<el-form>標簽

封裝組件

先上html部分代碼洼冻,代碼使用flex布局崭歧,樣式相關(guān)的類名可忽略。這里說明下 rowStart樣式:

.rowStart {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
}

<el-row>
        <el-form-item :label="title" label-position="top" class="addressFormItemBox" :required="required" :prop="addressProp">
            <div v-if="edit" class="rowStart">
                <!--@change="changeProvince"-->
                <el-select class="addressFormItem" :size="size" :value="address.provinceId" @input="changeProvince"  placeholder="請選擇">
                    <el-option
                            v-for="item in provinceList"
                            :key="item.regionCode"
                            :label="item.regionName"
                            :value="item.regionCode">
                    </el-option>
                </el-select>
                <el-select class="addressFormItem" :size="size" :value="address.cityId" @change="changeCity" placeholder="請選擇">
                    <el-option
                            v-for="item in cityList"
                            :key="item.regionCode"
                            :label="item.regionName"
                            :value="item.regionCode">
                    </el-option>
                </el-select>
                <el-select class="addressFormItem" v-if="isNotTwoLevels" :size="size" :value="address.districtId" @change="changeDistrict" placeholder="請選擇">
                    <el-option
                            v-for="item in districtList"
                            :key="item.regionCode"
                            :label="item.regionName"
                            :value="item.regionCode">
                    </el-option>
                </el-select>
                <el-input class="addressFormInput" v-if="showStreet" :style="{width:streetInputWidth}" :size="size" placeholder="請輸入" :value="address.street" @blur="streetBlur" @input="streetInput"></el-input>
            </div>
            <span v-else>{{fullAddress}}</span>
        </el-form-item>
    </el-row>

這里重點說下el-select和el-input的拆分撞牢。el-select本來的v-model被重新寫為 :value="address.provinceId" @input="changeProvince"

  <el-select class="addressFormItem" :size="size" :value="address.provinceId" @input="changeProvince"  placeholder="請選擇">
                    <el-option
                            v-for="item in provinceList"
                            :key="item.regionCode"
                            :label="item.regionName"
                            :value="item.regionCode">
                    </el-option>
                </el-select>

由于地址里面有三個input標簽率碾,為了方便處理,并且能實現(xiàn)表單驗證屋彪,所以統(tǒng)一用address來接收數(shù)據(jù)
address.provinceId是省所宰,address.cityId是城市,address.districtId是縣
el-form-item上畜挥,:prop="addressProp"仔粥,指定prop用于設置prop屬性,便于表單驗證砰嘁。
isNotTwoLevels 用于判斷是否是直轄市件炉,直轄市只有兩級勘究,隱藏縣級矮湘。

下面看看js部分

<script>
    import {mapState} from 'vuex'
    import {reqRegionInfo} from "../api/commonApi"
    import {isNumber} from "../utils/validate";

    export default {
        name: 'addressFormItem',
        props:{
            required:{
                type:Boolean,
                default:true
            },//是否必須
            title:{
                type:String,
                default:'選擇地址'
            },//標題
            showStreet:{
                type:Boolean,
                default:true
            },//是否顯示輸入詳情地址
            defaultAddress:{
                type:Object,
                default:()=>{
                    return {}
                }
            },//默認地址
            edit:{
                type:Boolean,
                default:true
            },//是否可編輯
            size:{
                type:String,
                default:'mini'
            },//尺寸
            inputWidth:{
                type:[Number,String],
                default:'auto'
            },
            addressProp:{
                type:String,
                default:'address'
            }
        },
        data() {
            return {
                address:{},//地址
                isNotTwoLevels:false,//是否直轄市
                cityList:[],//市
                districtList:[],//縣
                fullAddress:'',//地址全部信息
                projectAddress:[],//地址數(shù)組數(shù)據(jù)
                streetInputWidth:'auto',//地址輸入框?qū)挾?                getDefault:false,//是否獲取了默認值
            }
        },

        computed: {
            ...mapState(['provinceList'])
        },
        async mounted() {
            let {inputWidth}=this
            this.streetInputWidth=(typeof inputWidth==='number' || isNumber(inputWidth)) ? (inputWidth+'px') : inputWidth
            this.address=this.defaultAddress
        },
        methods: {
            // 獲取省市區(qū)信息 code 父級code 000000 省份  type類型 (province省份 city城市 district區(qū)域縣  )
            async getRegionInfo(code,type=0){
                let result=await reqRegionInfo(code)
                // //console.log(result)
                this[['provinceList','cityList','districtList'][type]]=result
                ;(type===2) && (this.isNotTwoLevels=!!result.length)
                // //console.log(this.isNotTwoLevels)
            },
            // 點擊切換省份
            changeProvince(val){
                this.$set(this.address,'provinceId',val)
                this.$set(this.address,'cityId','')
                this.$set(this.address,'districtId','')
                this.$set(this.address,'street','')
                this.districtList  = []
                this.cityList  = []
                this.getRegionInfo(val,1)
                let thisProvince=this.provinceList.filter((item,index)=>item.regionCode===val)
                // //console.log(thisProvince)
                this.projectAddress[1]=this.projectAddress[2]=''
                this.projectAddress[0]=[thisProvince[0].regionName]
                this.address.projectAddress= this.projectAddress
                this.$emit('input',this.address)
            },
            // 點擊切換城市
            changeCity(val){
                this.districtList  = []
                this.getRegionInfo(val,2)
                this.$set(this.address,'cityId',val)
                this.$set(this.address,'districtId','')
                // //console.log(this.cityList)
                let thisCity=this.cityList.filter(item=>item.regionCode===val)
                this.projectAddress[2]=''
                this.projectAddress[1]=thisCity[0].regionName
                this.address.projectAddress= this.projectAddress
                this.$emit('input',this.address)
            },
            // 點擊切換區(qū)縣
            async changeDistrict(val){
                let {districtList}=this
                this.$set(this.address,'districtId',val)
                // //console.log(this.address)
                let thisdistrictList=districtList.filter(item=>item.regionCode===val)
                this.projectAddress[2]=thisdistrictList[0].regionName
                this.projectAddress[3] && this.getLonLat(this.projectAddress.join(''))
                this.address.projectAddress= this.projectAddress
                this.address.showStreet= this.showStreet
                this.$emit('input',this.address)

            },
            //獲取經(jīng)緯度
            async getLonLat(data){
                let lngLatArr = await this.$globalMethods.getLngLat(AMap,data)
                // //console.log(lngLatArr)
                let {projectAddress,isNotTwoLevels,showStreet}=this
                this.address={...this.address,projectAddress,isNotTwoLevels,showStreet}
                this.$emit('getLngLatInfo',{
                    longitude:lngLatArr[0].lng,
                    latitude:lngLatArr[0].lat,
                })
                // //console.log(this.address)
                this.$emit('input',this.address)
            },
            //詳細地址改變
            streetBlur(e){
                this.projectAddress[3]=e.target.value
                // //console.log(this.projectAddress.join(''))
                ;((this.isNotTwoLevels && this.projectAddress[1]) || this.projectAddress[2]) && this.getLonLat(this.projectAddress.join(''))
                this.address.projectAddress= this.projectAddress
                let {isNotTwoLevels,showStreet}=this
                this.address={...this.address,projectAddress:this.projectAddress,isNotTwoLevels,showStreet}
                this.$emit('input',this.address)
            },
            //
            streetInput(value){
                this.$set(this.address,'street',value)
                this.$emit('input', this.address)
            }
        },
        watch:{
            defaultAddress:{
                deep:true,
                handler:async function (value) {
                    console.log(value)
                    let {cityId,provinceId,districtId ,street }=value
                    if(this.getDefault) return
                    if(provinceId && cityId){
                        let cityList = await reqRegionInfo(provinceId)
                        this.cityList=cityList
                        let districtList = await reqRegionInfo(cityId)
                        this.districtList=districtList
                        //console.log(districtList)
                        this.isNotTwoLevels=!!districtList.length
                        this.address={...value}
                        this.getDefault=true
                        let province=provinceId ? this.provinceList.filter(item=>item.regionCode===provinceId)[0].regionName : ''
                        let city=cityId ? cityList.filter(item=>item.regionCode===cityId)[0].regionName : ''
                        let district=districtId ? districtList.filter(item=>item.regionCode===districtId)[0].regionName : ''
                        this.fullAddress=`${province} ${city} ${district} ${street}`
                    }
                }
            },
        }

    }
</script>
首先說下props部分

重點的:

 defaultAddress:{
                type:Object,
                default:()=>{
                    return {}
                }
            },//默認地址

考慮到編輯狀態(tài),會從后臺獲取數(shù)據(jù)顯示默認數(shù)據(jù)口糕,用defaultAddress接收缅阳,
對應的需要在watch里面做監(jiān)聽。并把值賦給address

 watch:{
            defaultAddress:{
                deep:true,
                handler:async function (value) {
                    console.log(value)
                    if(!value){
                        //沒有數(shù)據(jù)時景描,清空
                        this.address={}
                        this.cityList=[]
                        this.districtList=[]
                    }
                    let {cityId,provinceId,districtId ,street }=value
                    //有數(shù)據(jù)時只允許更新一次
                    if(this.getDefault) return
                    if(provinceId && cityId){
                        let cityList = await reqRegionInfo(provinceId)
                        this.cityList=cityList
                        let districtList = await reqRegionInfo(cityId)
                        this.districtList=districtList
                        //console.log(districtList)
                        this.isNotTwoLevels=!!districtList.length
                        this.address={...value}
                        this.getDefault=true
                        let province=provinceId ? this.provinceList.filter(item=>item.regionCode===provinceId)[0].regionName : ''
                        let city=cityId ? cityList.filter(item=>item.regionCode===cityId)[0].regionName : ''
                        let district=districtId ? districtList.filter(item=>item.regionCode===districtId)[0].regionName : ''
                        this.fullAddress=`${province} ${city} ${district} ${street}`
                    }
                }
            },
        }
methods部分

看重點:

 // 點擊切換省份
            changeProvince(val){
                this.$set(this.address,'provinceId',val)
                this.$set(this.address,'cityId','')
                this.$set(this.address,'districtId','')
                this.$set(this.address,'street','')
                this.districtList  = []
                this.cityList  = []
                this.getRegionInfo(val,1)
                let thisProvince=this.provinceList.filter((item,index)=>item.regionCode===val)
                // //console.log(thisProvince)
                this.projectAddress[1]=this.projectAddress[2]=''
                this.projectAddress[0]=[thisProvince[0].regionName]
                this.address.projectAddress= this.projectAddress
                this.$emit('input',this.address)
            },
            // 點擊切換城市
            changeCity(val){
                this.districtList  = []
                this.getRegionInfo(val,2)
                this.$set(this.address,'cityId',val)
                this.$set(this.address,'districtId','')
                // //console.log(this.cityList)
                let thisCity=this.cityList.filter(item=>item.regionCode===val)
                this.projectAddress[2]=''
                this.projectAddress[1]=thisCity[0].regionName
                this.address.projectAddress= this.projectAddress
                this.$emit('input',this.address)
            },
            //詳細地址輸入
             streetInput(value){
                this.$set(this.address,'street',value)
                this.$emit('input', this.address)
            }

這里的重點在于十办,當下拉框發(fā)生改變,輸入框發(fā)生改變時超棺,要及時把數(shù)據(jù)返給父級組件:
在changeProvince函數(shù)中向族,changeCity函數(shù)中,streetInput中棠绘,均需要執(zhí)行 this.$emit('input',this.address)

組件使用和表單驗證

封裝完了件相,開始使用
在views中新建form.vue,并且引用ChooseAddressFormItem組件:

 import ChooseAddressFormItem from ../components/ChooseAddressFormItem.vue

在form.vue template中使用:

  <ChooseAddressFormItem title="項目地址:" @getLngLatInfo="getLngLatInfo" size="larger" input-width="400px" v-model="projCardForm.address" addressProp=“address"/>

這里重點有三:
第一個是v-model="projCardForm.address"氧苍,這里是數(shù)據(jù)綁定夜矗;
第二是addressProp=“address,指定子組件prop屬性让虐,用于表單驗證紊撕,
第三,表單驗證:下面仔細說下表單驗證
由于要驗證的是一個對象赡突,并且還有存在直轄市等特殊情況对扶,不能依靠element-ui本身的基礎驗證区赵,需要自定義,在表單驗證數(shù)據(jù)rules中

rules: {
              address:[{validator:(rule, value, callback)=>validAddressInfo(rule, value, callback),trigger:['blur', 'change']}],
          },

element-ui提供了自定義驗證方式validator函數(shù)浪南,參數(shù)有rule,value,callback惧笛,這里單獨去定義一個驗證函數(shù)
src下面新建utils文件夾,utils文件夾下面新建validateMethods.js
在validateMethods.js里面定義地址驗證方法
validateMethods.js

//檢查地址是否完善——地址封裝組件
export const validAddressInfo=(rule, value, callback,msg='請完善地址信息')=>{
//如果值不是對象逞泄,肯定不通過患整,調(diào)用  callback(new Error(msg))函數(shù)
   if(!value || !(value instanceof Object)){
       callback(new Error(msg))
       return
   }
   let {districtId,isNotTwoLevels,showStreet,street}=value
   //顯示地址輸入框的時候,如果地址輸入框沒有值喷众,肯定不通過
   if(showStreet){
       if(!street){
           callback(new Error(msg))
           return
       }
   }
   最后的情況各谚,非直轄市情況下,沒有縣id到千,肯定不通過
   if(!districtId && isNotTwoLevels){
       callback(new Error(msg))
   }
}

那么現(xiàn)在在form.vue中引入地址驗證函數(shù)validAddressInfo昌渤,然后賦值給rule中的validator就行

<script>
  import {validAddressInfo} from '../utils/validateMethods.js'
export default{
data(){
return{
rules: {
             address:[{validator:(rule, value, callback)=>validAddressInfo(rule, value, callback),trigger:['blur', 'change']}],
         },
    }
}
}
</script>

到此,組件封裝和使用講完憔四。不僅簡化了代碼膀息,而且數(shù)據(jù)綁定,表單驗證都沒少了赵。
后面附上組件全部代碼
由于本組件地址聯(lián)動數(shù)據(jù)通過服務器請求獲取的潜支,請自動忽略,你只需要找到相關(guān)數(shù)據(jù)對上即可

<!--選擇地址-->
<template>
  <el-row>
      <el-form-item :label="title" label-position="top" class="addressFormItemBox" :required="required" :prop="addressProp">
          <div v-if="edit" class="rowStart">
              <!--@change="changeProvince"-->
              <el-select class="addressFormItem" :size="size" :value="address.provinceId" @input="changeProvince"  placeholder="請選擇">
                  <el-option
                          v-for="item in provinceList"
                          :key="item.regionCode"
                          :label="item.regionName"
                          :value="item.regionCode">
                  </el-option>
              </el-select>
              <el-select class="addressFormItem" :size="size" :value="address.cityId" @change="changeCity" placeholder="請選擇">
                  <el-option
                          v-for="item in cityList"
                          :key="item.regionCode"
                          :label="item.regionName"
                          :value="item.regionCode">
                  </el-option>
              </el-select>
              <el-select class="addressFormItem" v-if="isNotTwoLevels" :size="size" :value="address.districtId" @change="changeDistrict" placeholder="請選擇">
                  <el-option
                          v-for="item in districtList"
                          :key="item.regionCode"
                          :label="item.regionName"
                          :value="item.regionCode">
                  </el-option>
              </el-select>
              <el-input class="addressFormInput" v-if="showStreet" :style="{width:streetInputWidth}" :size="size" placeholder="請輸入" :value="address.street" @blur="streetBlur" @input="streetInput"></el-input>
          </div>
          <span v-else>{{fullAddress}}</span>
      </el-form-item>
  </el-row>

</template>

<script>
  import {mapState} from 'vuex'
  import {reqRegionInfo} from "../api/commonApi"
  import {isNumber} from "../utils/validate";

  export default {
      name: 'addressFormItem',
      props:{
          required:{
              type:Boolean,
              default:true
          },//是否必須
          title:{
              type:String,
              default:'選擇地址'
          },//標題
          showStreet:{
              type:Boolean,
              default:true
          },//是否顯示輸入詳情地址
          defaultAddress:{
              type:Object,
              default:()=>{
                  return {}
              }
          },//默認地址
          edit:{
              type:Boolean,
              default:true
          },//是否可編輯
          size:{
              type:String,
              default:'mini'
          },//尺寸
          inputWidth:{
              type:[Number,String],
              default:'auto'
          },
          addressProp:{
              type:String,
              default:'address'
          }
      },
      data() {
          return {
              address:{},//地址
              isNotTwoLevels:false,//是否直轄市
              cityList:[],//市
              districtList:[],//縣
              fullAddress:'',//地址全部信息
              projectAddress:[],//地址數(shù)組數(shù)據(jù)
              streetInputWidth:'auto',//地址輸入框?qū)挾?              getDefault:false,//是否獲取了默認值
          }
      },

      computed: {
          ...mapState(['provinceList'])
      },
      async mounted() {
          let {inputWidth}=this
          this.streetInputWidth=(typeof inputWidth==='number' || isNumber(inputWidth)) ? (inputWidth+'px') : inputWidth
          this.address=this.defaultAddress
      },
      methods: {
          // 獲取省市區(qū)信息 code 父級code 000000 省份  type類型 (province省份 city城市 district區(qū)域縣  )
          async getRegionInfo(code,type=0){
              let result=await reqRegionInfo(code)
              // //console.log(result)
              this[['provinceList','cityList','districtList'][type]]=result
              ;(type===2) && (this.isNotTwoLevels=!!result.length)
              // //console.log(this.isNotTwoLevels)
          },
          // 點擊切換省份
          changeProvince(val){
              this.$set(this.address,'provinceId',val)
              this.$set(this.address,'cityId','')
              this.$set(this.address,'districtId','')
              this.$set(this.address,'street','')
              this.districtList  = []
              this.cityList  = []
              this.getRegionInfo(val,1)
              let thisProvince=this.provinceList.filter((item,index)=>item.regionCode===val)
              // //console.log(thisProvince)
              this.projectAddress[1]=this.projectAddress[2]=''
              this.projectAddress[0]=[thisProvince[0].regionName]
              this.address.projectAddress= this.projectAddress
              this.$emit('input',this.address)
          },
          // 點擊切換城市
          changeCity(val){
              this.districtList  = []
              this.getRegionInfo(val,2)
              this.$set(this.address,'cityId',val)
              this.$set(this.address,'districtId','')
              // //console.log(this.cityList)
              let thisCity=this.cityList.filter(item=>item.regionCode===val)
              this.projectAddress[2]=''
              this.projectAddress[1]=thisCity[0].regionName
              this.address.projectAddress= this.projectAddress
              this.$emit('input',this.address)
          },
          // 點擊切換區(qū)縣
          async changeDistrict(val){
              let {districtList}=this
              this.$set(this.address,'districtId',val)
              // //console.log(this.address)
              let thisdistrictList=districtList.filter(item=>item.regionCode===val)
              this.projectAddress[2]=thisdistrictList[0].regionName
              this.projectAddress[3] && this.getLonLat(this.projectAddress.join(''))
              this.address.projectAddress= this.projectAddress
              this.address.showStreet= this.showStreet
              this.$emit('input',this.address)

          },
          //獲取經(jīng)緯度
          async getLonLat(data){
              let lngLatArr = await this.$globalMethods.getLngLat(AMap,data)
              // //console.log(lngLatArr)
              let {projectAddress,isNotTwoLevels,showStreet}=this
              this.address={...this.address,projectAddress,isNotTwoLevels,showStreet}
              this.$emit('getLngLatInfo',{
                  longitude:lngLatArr[0].lng,
                  latitude:lngLatArr[0].lat,
              })
              // //console.log(this.address)
              this.$emit('input',this.address)
          },
          //詳細地址改變
          streetBlur(e){
              this.projectAddress[3]=e.target.value
              // //console.log(this.projectAddress.join(''))
              ;((this.isNotTwoLevels && this.projectAddress[1]) || this.projectAddress[2]) && this.getLonLat(this.projectAddress.join(''))
              this.address.projectAddress= this.projectAddress
              let {isNotTwoLevels,showStreet}=this
              this.address={...this.address,projectAddress:this.projectAddress,isNotTwoLevels,showStreet}
              this.$emit('input',this.address)
          },
          //
          streetInput(value){
              this.$set(this.address,'street',value)
              this.$emit('input', this.address)
          }
      },
      watch:{
          defaultAddress:{
              deep:true,
              handler:async function (value) {
                  console.log(value)
                  if(!value){
                      //沒有數(shù)據(jù)時柿汛,清空
                      this.address={}
                      this.cityList=[]
                      this.districtList=[]
                  }
                  let {cityId,provinceId,districtId ,street }=value
                  //有數(shù)據(jù)時只允許更新一次
                  if(this.getDefault) return
                  if(provinceId && cityId){
                      let cityList = await reqRegionInfo(provinceId)
                      this.cityList=cityList
                      let districtList = await reqRegionInfo(cityId)
                      this.districtList=districtList
                      //console.log(districtList)
                      this.isNotTwoLevels=!!districtList.length
                      this.address={...value}
                      this.getDefault=true
                      let province=provinceId ? this.provinceList.filter(item=>item.regionCode===provinceId)[0].regionName : ''
                      let city=cityId ? cityList.filter(item=>item.regionCode===cityId)[0].regionName : ''
                      let district=districtId ? districtList.filter(item=>item.regionCode===districtId)[0].regionName : ''
                      this.fullAddress=`${province} ${city} ${district} ${street}`
                  }
              }
          },
      }

  }
</script>

<style scoped lang="scss">
  .addressFormItemBox{
      .addressFormItem{
          margin-right:10px;
      }
      .addressFormInput{
          /*flex:1;*/
      }
  }
</style>

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末冗酿,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子络断,更是在濱河造成了極大的恐慌裁替,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件貌笨,死亡現(xiàn)場離奇詭異弱判,居然都是意外死亡,警方通過查閱死者的電腦和手機锥惋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門昌腰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人净刮,你說我怎么就攤上這事剥哑。” “怎么了淹父?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵株婴,是天一觀的道長。 經(jīng)常有香客問我,道長困介,這世上最難降的妖魔是什么大审? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮座哩,結(jié)果婚禮上徒扶,老公的妹妹穿的比我還像新娘。我一直安慰自己根穷,他們只是感情好姜骡,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著屿良,像睡著了一般圈澈。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上尘惧,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天康栈,我揣著相機與錄音,去河邊找鬼喷橙。 笑死啥么,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的贰逾。 我是一名探鬼主播悬荣,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼似踱!你這毒婦竟也來了隅熙?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤核芽,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后酵熙,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體轧简,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年匾二,在試婚紗的時候發(fā)現(xiàn)自己被綠了哮独。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡察藐,死狀恐怖皮璧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情分飞,我是刑警寧澤悴务,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響讯檐,放射性物質(zhì)發(fā)生泄漏羡疗。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一别洪、第九天 我趴在偏房一處隱蔽的房頂上張望叨恨。 院中可真熱鬧,春花似錦挖垛、人聲如沸痒钝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽午乓。三九已至,卻和暖如春闸准,著一層夾襖步出監(jiān)牢的瞬間益愈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工夷家, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蒸其,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓库快,卻偏偏與公主長得像摸袁,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子义屏,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355