記一次基于mpvue的小程序開發(fā)及上線實(shí)戰(zhàn)

服務(wù)端:https://github.com/jrainlau/t...

  • 小程序二維碼:

經(jīng)過為期兩個(gè)晚上下班時(shí)間的努力,終于把我第一個(gè)小程序開發(fā)完成并發(fā)布上線了。整個(gè)過程還算順利考杉,由于使用了mpvue方案進(jìn)行開發(fā),故可以享受和vue一致的流暢開發(fā)體驗(yàn)借跪;后臺(tái)系統(tǒng)使用了python3+flask框架進(jìn)行胚宦,使用最少的代碼完成了小程序的后臺(tái)邏輯益兄。除了開發(fā)之外脊凰,還實(shí)實(shí)在在地體驗(yàn)了一把微信小程序的開發(fā)流程抖棘,包括開發(fā)者工具的使用、體驗(yàn)版的發(fā)布、上線的申請(qǐng)等等切省。這些開發(fā)體驗(yàn)都非常值得被記錄下來最岗,于是便趁熱打鐵,寫下這篇文章朝捆。

一般渡、需求&功能

由于公司里有相當(dāng)多的同事都住在同一個(gè)小區(qū),所以上下班的時(shí)候經(jīng)常會(huì)在公司群里組織拼車芙盘。但是由于完全依賴聊天記錄驯用,且上下班拼車的同事也很多,依賴群聊很容易把消息刷走何陆,而且容易造成信息錯(cuò)亂晨汹。既然如此豹储,那么完全可以開發(fā)一個(gè)小工具把這些問題解決贷盲。

發(fā)起拼車的人把出發(fā)地點(diǎn)、目的地點(diǎn)剥扣、打車信息以卡片的形式分享出來巩剖,參與拼車的人點(diǎn)擊卡片就能選擇參加拼車,并且能看到同車拼友是誰钠怯,拼單的信息等等內(nèi)容佳魔。

交互流程如下:

可以看到,邏輯是非常簡(jiǎn)單的晦炊,我們只需要保證生成拼單鞠鲜、分享拼單、進(jìn)入拼單和退出拼單這四個(gè)功能就好断国。

需求和功能已經(jīng)確定好贤姆,首先按照小程序官網(wǎng)的介紹,注冊(cè)好小程序并拿到appId稳衬,接下來可以開始進(jìn)行后臺(tái)邏輯的開發(fā)霞捡。

二、后臺(tái)邏輯開發(fā)

由于時(shí)間倉(cāng)促薄疚,功能又簡(jiǎn)單碧信,所以并沒有考慮任何高并發(fā)等復(fù)雜場(chǎng)景,僅僅考慮功能的實(shí)現(xiàn)街夭。從需求的邏輯可以知道砰碴,其實(shí)后臺(tái)只需要維護(hù)兩個(gè)列表,分別存儲(chǔ)當(dāng)前所有拼車單以及當(dāng)前所有參與了拼車的用戶即可板丽,其數(shù)據(jù)結(jié)構(gòu)如下:

  • 當(dāng)前所有拼單列表billsList
  • 當(dāng)前所有參與了拼車的用戶列表inBillUsers

當(dāng)用戶確定并分享了一個(gè)拼單之后呈枉,會(huì)直接新建一個(gè)拼單,同時(shí)把該用戶添加到當(dāng)前所有參與了拼車的用戶列表列表里面,并且添加到該拼單的成員列表當(dāng)中:

只要維護(hù)好這兩個(gè)列表碴卧,接下來就是具體的業(yè)務(wù)邏輯了弱卡。

為了快速開發(fā),這里我使用了python3+flask框架的方案住册。不懂python的讀者看到這里也不用緊張婶博,代碼非常簡(jiǎn)單且直白,看看也無妨荧飞。

首先新建一個(gè)BillController類:

class BillController:
    billsList = []
    inBillUsers = []

接下來會(huì)在這個(gè)類的內(nèi)部添加創(chuàng)建拼單凡人、獲取拼單參與拼單叹阔、退出拼單挠轴、判斷用戶是否在某一拼單中圖片上傳的功能耳幢。

1岸晦、獲取拼單getBill()

該方法接收客戶端傳來的拼單ID,然后拿這個(gè)ID去檢索是否存在對(duì)應(yīng)的拼單睛藻。若存在則返回對(duì)應(yīng)的拼單启上,否則報(bào)錯(cuò)給客戶端。

def getBill(self, ctx):
        ctxBody = ctx.form
        billId = ctxBody['billId']
        try: 
            return response([item for item in self.billsList if item['billId'] == billId][0])
        except IndexError:
            return response({
                'errMsg': '拼單不存在店印!',
                'billsList': self.billsList,
            }, 1)

2冈在、創(chuàng)建拼單createBill()

該方法會(huì)接收來自客戶端的用戶信息拼單信息,分別添加到billsListinBillUsers當(dāng)中按摘。

def createBill(self, ctx):
        ctxBody = ctx.form
        user = {
            'userId': ctxBody['userId'],
            'billId': ctxBody['billId'],
            'name': ctxBody['name'],
            'avatar': ctxBody['avatar']
        }
        bill = {
            'billId': ctxBody['billId'],
            'from': ctxBody['from'],
            'to': ctxBody['to'],
            'time': ctxBody['time'],
            'members': [user]
        }

        if ctxBody['userId'] in [item['userId'] for item in self.inBillUsers]:
            return response({
                'errMsg': '用戶已經(jīng)在拼單中包券!'
            }, 1)

        self.billsList.append(bill)
        self.inBillUsers.append(user)
        return response({
            'billsList': self.billsList,
            'inBillUsers': self.inBillUsers
        })

創(chuàng)建完成后,會(huì)返回當(dāng)前的billsListinBillUsers到客戶端炫贤。

3溅固、參與拼單joinBill()

接收客戶端傳來的用戶信息拼單ID,把用戶添加到拼單和inBillUsers列表中照激。

def joinBill(self, ctx):
        ctxBody = ctx.form
        billId = ctxBody['billId']
        user = {
            'userId': ctxBody['userId'],
            'name': ctxBody['name'],
            'avatar': ctxBody['avatar'],
            'billId': ctxBody['billId']
        }
        if ctxBody['userId'] in [item['userId'] for item in self.inBillUsers]:
            return response({
                'errMsg': '用戶已經(jīng)在拼單中发魄!'
            }, 1)
        theBill = [item for item in self.billsList if item['billId'] == billId]
        if not theBill:
            return response({
                'errMsg': '拼單不存在'
            }, 1)
        theBill[0]['members'].append(user)
        self.inBillUsers.append(user)
        return response({
            'billsList': self.billsList,
            'inBillUsers': self.inBillUsers
        })

4、退出拼單leaveBill()

接收客戶端傳來的用戶ID拼單ID俩垃,然后刪除掉兩個(gè)列表里面的該用戶励幼。

這個(gè)函數(shù)還有一個(gè)功能,如果判斷到這個(gè)拼單ID所對(duì)應(yīng)的拼單成員為空口柳,會(huì)認(rèn)為該拼單已經(jīng)作廢苹粟,會(huì)直接刪除掉這個(gè)拼單以及所對(duì)應(yīng)的車輛信息圖片。

def leaveBill(self, ctx):
        ctxBody = ctx.form
        billId = ctxBody['billId']
        userId = ctxBody['userId']
        indexOfUser = [i for i, member in enumerate(self.inBillUsers) if member['userId'] == userId][0]
        indexOfTheBill = [i for i, bill in enumerate(self.billsList) if bill['billId'] == billId][0]
        indexOfUserInBill = [i for i, member in enumerate(self.billsList[indexOfTheBill]['members']) if member['userId'] == userId][0]
        # 刪除拼單里面的該用戶
        self.billsList[indexOfTheBill]['members'].pop(indexOfUserInBill)
        # 刪除用戶列表里面的該用戶
        self.inBillUsers.pop(indexOfUser)
        # 如果拼單里面用戶為空跃闹,則直接刪除這筆拼單
        if len(self.billsList[indexOfTheBill]['members']) == 0:
            imgPath = './imgs/' + self.billsList[indexOfTheBill]['img'].split('/getImg')[1]
            if os.path.exists(imgPath):
                os.remove(imgPath)
            self.billsList.pop(indexOfTheBill)
        return response({
            'billsList': self.billsList,
            'inBillUsers': self.inBillUsers
        })

5嵌削、判斷用戶是否在某一拼單中inBill()

接收客戶端傳來的用戶ID毛好,接下來會(huì)根據(jù)這個(gè)用戶ID去inBillUsers里面去檢索該用戶所對(duì)應(yīng)的拼單,如果能檢索到苛秕,會(huì)返回其所在的拼單肌访。

def inBill(self, ctx):
        ctxBody = ctx.form
        userId = ctxBody['userId']
        if ctxBody['userId'] in [item['userId'] for item in self.inBillUsers]:
            return response({
                'inBill': [item for item in self.inBillUsers if ctxBody['userId'] == item['userId']][0],
                'billsList': self.billsList,
                'inBillUsers': self.inBillUsers
            })
        return response({
            'inBill': False,
            'billsList': self.billsList,
            'inBillUsers': self.inBillUsers
        })

6、圖片上傳uploadImg()

接收客戶端傳來的拼單ID圖片資源艇劫,先存儲(chǔ)圖片吼驶,然后把該圖片的路徑寫入對(duì)應(yīng)拼單ID的拼單當(dāng)中。

def uploadImg(self, ctx):
        billId = ctx.form['billId']
        file = ctx.files['file']
        filename = file.filename
        file.save(os.path.join('./imgs', filename))
        # 把圖片信息掛載到對(duì)應(yīng)的拼單
        indexOfTheBill = [i for i, bill in enumerate(self.billsList) if bill['billId'] == billId][0]
        self.billsList[indexOfTheBill]['img'] = url_for('getImg', filename=filename)
        return response({
            'billsList': self.billsList
        })

完成了業(yè)務(wù)邏輯的功能店煞,接下來就是把它們分發(fā)給不同的路由了:

@app.route('/create', methods = ['POST'])
def create():
    return controller.createBill(request)

@app.route('/join', methods = ['POST'])
def join():
    return controller.joinBill(request)

@app.route('/leave', methods = ['POST'])
def leave():
    return controller.leaveBill(request)

@app.route('/getBill', methods = ['POST'])
def getBill():
    return controller.getBill(request)

@app.route('/inBill', methods = ['POST'])
def inBill():
    return controller.inBill(request)

@app.route('/uploadImg', methods = ['POST'])
def uploadImg():
    return controller.uploadImg(request)

@app.route('/getImg/<filename>')
def getImg(filename):
  return send_from_directory('./imgs', filename)

完整的代碼可以直接到倉(cāng)庫(kù)查看蟹演,這里僅展示關(guān)鍵的內(nèi)容。

三顷蟀、前端業(yè)務(wù)開發(fā)

前端借助vue-cli直接使用了mpvue的mpvue-quickstart來初始化項(xiàng)目酒请,具體過程不再細(xì)述,直接進(jìn)入業(yè)務(wù)開發(fā)部分鸣个。

首先羞反,微信小程序的API都是callback風(fēng)格,為了使用方便毛萌,我把用到的小程序API都包裝成了Promise苟弛,統(tǒng)一放在src/utils/wx.js內(nèi)部喝滞,類似下面這樣:

export const request = obj => new Promise((resolve, reject) => {
  wx.request({
    url: obj.url,
    data: obj.data,
    header: { 'content-type': 'application/x-www-form-urlencoded', ...obj.header },
    method: obj.method,
    success (res) {
      resolve(res.data.data)
    },
    fail (e) {
      console.log(e)
      reject(e)
    }
  })
})

1阁将、注冊(cè)全局Store

由于開發(fā)習(xí)慣,我喜歡把所有接口請(qǐng)求都放在store里面的actions當(dāng)中右遭,所以這個(gè)小程序也是需要用到Vuex做盅。但由于小程序每一個(gè)Page都是一個(gè)新的Vue實(shí)例,所以按照Vue的方式窘哈,用全局Vue.use(Vuex)是不會(huì)把$store注冊(cè)到實(shí)例當(dāng)中的吹榴,這一步要手動(dòng)來。

src/目錄下新建一個(gè)store.js文件滚婉,然后在里面進(jìn)行使用注冊(cè):

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({})

接下來在src/main.js當(dāng)中图筹,手動(dòng)在Vue的原型里注冊(cè)一個(gè)$store

import Vue from 'vue'
import App from './App'
import Store from './store'

Vue.prototype.$store = Store

這樣,以后在任何的Page里都可以通過this.$store來操作這個(gè)全局Store了让腹。

2远剩、構(gòu)建好請(qǐng)求的API接口

和后臺(tái)系統(tǒng)的邏輯對(duì)應(yīng),前端也要構(gòu)造好各個(gè)請(qǐng)求的API接口骇窍,這樣的做法能夠避免把API邏輯分散到頁(yè)面四處瓜晤,具有清晰、易維護(hù)的優(yōu)勢(shì)腹纳。

/**
     * @param  {} {commit}
     * 獲取用戶公開信息
     */
    async getUserInfo ({ commit }) {
      const { userInfo } = await getUserInfo({
        withCredenitals: false
      })
      userInfo.avatar = userInfo.avatarUrl
      userInfo.name = userInfo.nickName
      userInfo.userId = encodeURIComponent(userInfo.nickName + userInfo.city + userInfo.gender + userInfo.country)
      commit('GET_USER_INFO', userInfo)
      return userInfo
    },
    /**
     * @param  {} {commit}
     * @param  { String } userId 用戶ID
     * 檢查用戶是否已經(jīng)存在于某一拼單中
     */
    async checkInBill ({ commit }, userId) {
      const res = await request({
        method: 'post',
        url: `${apiDomain}/inBill`,
        data: {
          userId
        }
      })
      return res
    },
    /**
     * @param  {} {commit}
     * @param  { String } userId 用戶ID
     * @param  { String } name   用戶昵稱
     * @param  { String } avatar 用戶頭像
     * @param  { String } time   出發(fā)時(shí)間
     * @param  { String } from   出發(fā)地點(diǎn)
     * @param  { String } to     目的地點(diǎn)
     * @param  { String } billId 拼單ID
     * 創(chuàng)建拼單
     */
    async createBill ({ commit }, { userId, name, avatar, time, from, to, billId }) {
      const res = await request({
        method: 'post',
        url: `${apiDomain}/create`,
        data: {
          userId,
          name,
          avatar,
          time,
          from,
          to,
          billId
        }
      })
      commit('GET_BILL_INFO', res)
      return res
    },
    /**
     * @param  {} {commit}
     * @param  { String } billId 拼單ID
     * 獲取拼單信息
     */
    async getBillInfo ({ commit }, billId) {
      const res = await request({
        method: 'post',
        url: `${apiDomain}/getBill`,
        data: {
          billId
        }
      })
      return res
    },
    /**
     * @param  {} {commit}
     * @param  { String } userId 用戶ID
     * @param  { String } name   用戶昵稱
     * @param  { String } avatar 用戶頭像
     * @param  { String } billId 拼單ID
     * 參加拼單
     */
    async joinBill ({ commit }, { userId, name, avatar, billId }) {
      const res = await request({
        method: 'post',
        url: `${apiDomain}/join`,
        data: {
          userId,
          name,
          avatar,
          billId
        }
      })
      return res
    },
    /**
     * @param  {} {commit}
     * @param  { String } userId 用戶ID
     * @param  { String } billId 拼單ID
     * 退出拼單
     */
    async leaveBill ({ commit }, { userId, billId }) {
      const res = await request({
        method: 'post',
        url: `${apiDomain}/leave`,
        data: {
          userId,
          billId
        }
      })
      return res
    },
    /**
     * @param  {} {commit}
     * @param  { String } filePath 圖片路徑
     * @param  { String } billId   拼單ID
     * 參加拼單
     */
    async uploadImg ({ commit }, { filePath, billId }) {
      const res = await uploadFile({
        url: `${apiDomain}/uploadImg`,
        header: {
          'content-type': 'multipart/form-data'
        },
        filePath,
        name: 'file',
        formData: {
          'billId': billId
        }
      })
      return res
    }

3痢掠、填寫拼單并實(shí)現(xiàn)分享功能實(shí)現(xiàn)

新建一個(gè)src/pages/index目錄驱犹,作為小程序的首頁(yè)。

該首頁(yè)的業(yè)務(wù)邏輯如下:

  1. 進(jìn)入首頁(yè)的時(shí)候先獲取用戶信息足画,得到userId
  2. 然后用userId去請(qǐng)求判斷是否已經(jīng)處于拼單
  3. 若是雄驹,則跳轉(zhuǎn)到對(duì)應(yīng)拼單Id的詳情頁(yè)
  4. 若否,才允許新建拼單

onShow的生命周期鉤子中實(shí)現(xiàn)上述邏輯:

async onShow () {
    this.userInfo = await this.$store.dispatch('getUserInfo')
    const inBill = await this.$store.dispatch('checkInBill', this.userInfo.userId)

    if (inBill.inBill) {
      wx.redirectTo(`../join/main?billId=${inBill.inBill.billId}&fromIndex=true`)
    }
  },

當(dāng)用戶填寫完拼單后淹辞,會(huì)點(diǎn)擊一個(gè)帶有open-type="share"屬性的button荠医,然后會(huì)觸發(fā)onShareAppMessage生命周期鉤子的邏輯把拼單構(gòu)造成卡片分享出去。當(dāng)分享成功后會(huì)跳轉(zhuǎn)到對(duì)應(yīng)拼單ID的參加拼單頁(yè)桑涎。

onShareAppMessage (result) {
    let title = '一起拼車'
    let path = '/pages/index'
    if (result.from === 'button') {
      this.billId = 'billId-' + new Date().getTime()
      title = '我發(fā)起了一個(gè)拼車'
      path = `pages/join/main?billId=${this.billId}`
    }
    return {
      title,
      path,
      success: async (res) => {
        await this.$store.dispatch('createBill', { ...this.userInfo, ...this.billInfo })

        // 上傳圖片
        await this.$store.dispatch('uploadImg', {
          filePath: this.imgSrc,
          billId: this.billId
        })

        // 分享成功后彬向,會(huì)帶著billId跳轉(zhuǎn)到參加拼單頁(yè)
        wx.redirectTo(`../join/main?billId=${this.billId}`)
      },
      fail (e) {
        console.log(e)
      }
    }
  },

4、參與拼單&退出拼單功能實(shí)現(xiàn)

新建一個(gè)src/pages/join目錄攻冷,作為小程序的“參加拼單頁(yè)”娃胆。

該頁(yè)面的運(yùn)行邏輯如下:

  1. 首先會(huì)獲取從url里面帶來的billId
  2. 其次會(huì)請(qǐng)求一次userInfo,獲取userId
  3. 然后拿這個(gè)userId去檢查該用戶是否已經(jīng)處于拼單
  4. 如果已經(jīng)處于拼單等曼,那么就會(huì)獲取一個(gè)新的billId代替從url獲取的
  5. 拿當(dāng)前的billId去查詢對(duì)應(yīng)的拼單信息
  6. 如果billId都無效里烦,則redirect到首頁(yè)

由于要獲取url攜帶的內(nèi)容,親測(cè)onShow()是不行的禁谦,只能在onLoad()里面獲刃埠凇:

async onLoad (options) {
    // 1\. 首先會(huì)獲取從url里面帶來的billId
    this.billId = options.billId
    // 2\. 其次會(huì)請(qǐng)求一次userInfo,獲取userId
    this.userInfo = await this.$store.dispatch('getUserInfo')
    // 3\. 然后拿這個(gè)userId去檢查該用戶是否已經(jīng)處于拼單
    const inBill = await this.$store.dispatch('checkInBill', this.userInfo.userId)
    // 4\. 如果已經(jīng)處于拼單州泊,那么就會(huì)有一個(gè)billId
    if (inBill.inBill) {
      this.billId = inBill.inBill.billId
    }
    // 5\. 如果沒有處于拼單丧蘸,那么將請(qǐng)求當(dāng)前billId的拼單
    // 6\. 如果billId都無效,則redirect到首頁(yè)遥皂,否則檢查當(dāng)前用戶是否處于該拼單當(dāng)中
    await this.getBillInfo()
  }

此外力喷,當(dāng)用戶點(diǎn)擊“參與拼車”后,需要重新請(qǐng)求拼單信息演训,以刷新視圖拼車人員列表弟孟;當(dāng)用戶點(diǎn)擊“退出拼車”后,要重定向到首頁(yè)样悟。

經(jīng)過上面幾個(gè)步驟拂募,客戶端的邏輯已經(jīng)完成,可以進(jìn)行預(yù)發(fā)布了窟她。

四陈症、預(yù)發(fā)布&申請(qǐng)上線

如果要發(fā)布預(yù)發(fā)布版本,需要運(yùn)行npm run build命令礁苗,打包出一個(gè)生產(chǎn)版本的包爬凑,然后通過小程序開發(fā)者工具的上傳按鈕上傳代碼,并填寫測(cè)試版本號(hào):

接下來可以在小程序管理后臺(tái)→開發(fā)管理→開發(fā)版本當(dāng)中看到體驗(yàn)版小程序的信息试伙,然后選擇發(fā)布體驗(yàn)版即可:


當(dāng)確定預(yù)發(fā)布測(cè)試無誤之后嘁信,就可以點(diǎn)擊“提交審核”于样,正式把小程序提交給微信團(tuán)隊(duì)進(jìn)行審核。審核的時(shí)間非撑司福快穿剖,在3小時(shí)內(nèi)基本都能夠有答復(fù)。

值得注意的是卦溢,小程序所有請(qǐng)求的API糊余,都必須經(jīng)過域名備案使用https證書,同時(shí)要在設(shè)置→開發(fā)設(shè)置→服務(wù)器域名里面把API添加到白名單才可以正常使用单寂。

五贬芥、后記

這個(gè)小程序現(xiàn)在已經(jīng)發(fā)布上線了,算是完整體驗(yàn)了一把小程序的開發(fā)樂趣宣决。小程序得到了微信團(tuán)隊(duì)的大力支持蘸劈,以后的生態(tài)只會(huì)越來越繁榮。當(dāng)初小程序上線的時(shí)候我也對(duì)它有一些抵觸尊沸,但后來想了想威沫,這只不過是前端工程師所需面對(duì)的又一個(gè)“端“而已,沒有必要為它戴上有色眼鏡洼专,多掌握一些總是好的棒掠。

“一起打車吧”微信小程序依然是一個(gè)玩具般的存在,僅供自己學(xué)習(xí)和探索屁商,當(dāng)然也歡迎各位讀者能夠貢獻(xiàn)代碼烟很,參與開發(fā)~

作者: jrainlau
鏈接:人類身份驗(yàn)證 - SegmentFault
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán)棒假,非商業(yè)轉(zhuǎn)載請(qǐng)注明出處溯职。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市帽哑,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌叹俏,老刑警劉巖妻枕,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異粘驰,居然都是意外死亡屡谐,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門蝌数,熙熙樓的掌柜王于貴愁眉苦臉地迎上來愕掏,“玉大人,你說我怎么就攤上這事顶伞《牛” “怎么了剑梳?”我有些...
    開封第一講書人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)滑潘。 經(jīng)常有香客問我垢乙,道長(zhǎng),這世上最難降的妖魔是什么语卤? 我笑而不...
    開封第一講書人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任追逮,我火速辦了婚禮,結(jié)果婚禮上粹舵,老公的妹妹穿的比我還像新娘钮孵。我一直安慰自己,他們只是感情好眼滤,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開白布油猫。 她就那樣靜靜地躺著,像睡著了一般柠偶。 火紅的嫁衣襯著肌膚如雪情妖。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,764評(píng)論 1 290
  • 那天诱担,我揣著相機(jī)與錄音毡证,去河邊找鬼。 笑死蔫仙,一個(gè)胖子當(dāng)著我的面吹牛料睛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播摇邦,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼恤煞,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了施籍?” 一聲冷哼從身側(cè)響起居扒,我...
    開封第一講書人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎丑慎,沒想到半個(gè)月后喜喂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡竿裂,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年玉吁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片腻异。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡进副,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出悔常,到底是詐尸還是另有隱情影斑,我是刑警寧澤给赞,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站鸥昏,受9級(jí)特大地震影響塞俱,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜吏垮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一障涯、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧膳汪,春花似錦唯蝶、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至痹换,卻和暖如春征字,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背娇豫。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來泰國(guó)打工匙姜, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人冯痢。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓氮昧,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親浦楣。 傳聞我的和親對(duì)象是個(gè)殘疾皇子袖肥,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

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