Vue2.x 源碼解析:組件初始化過程概要

作者:lihongxun945

github.com/lihongxun945/myblog/issues/23


這里分析的是當(dāng)前(2018/07/25)最新版 V2.5.16 的源碼懂缕,如果你想一遍看一遍參閱源碼,請務(wù)必記得切換到此版本苦蒿,不然可能存在微小的差異。



大家都知道,我們的應(yīng)用是一個(gè)由Vue組件構(gòu)成的一棵樹,其中每一個(gè)節(jié)點(diǎn)都是一個(gè) Vue 組件。我們的每一個(gè)Vue組件是如何被創(chuàng)建出來的,創(chuàng)建的過程經(jīng)歷了哪些步驟呢迟蜜?把這些都搞清楚刹孔,那么我們對Vue的整個(gè)原理將會(huì)有很深入的理解。


從入口函數(shù)開始娜睛,有比較復(fù)雜的引用關(guān)系髓霞,為了方便大家理解,我畫了一張圖可以直觀地看出他們之間的關(guān)系:



創(chuàng)建Vue實(shí)例的兩步

我們創(chuàng)建一個(gè)Vue實(shí)例畦戒,只需要兩行代碼:


import Vue from ‘vue'

new Vue(options)


而這兩步分別經(jīng)歷了一個(gè)比較復(fù)雜的構(gòu)建過程:


創(chuàng)建類:創(chuàng)建一個(gè) Vue 構(gòu)造函數(shù)方库,以及他的一系列原型方法和類方法

創(chuàng)建實(shí)例:創(chuàng)建一個(gè) Vue 實(shí)例,初始化他的數(shù)據(jù)障斋,事件纵潦,模板等


下面我們分別解析這兩個(gè)階段,其中每個(gè)階段 又分為好多個(gè) 步驟


第一階段:創(chuàng)建Vue類

第一階段是要?jiǎng)?chuàng)建一個(gè)Vue類垃环,因?yàn)槲覀冞@里用的是原型而不是ES6中的class聲明邀层,所以拆成了三步來實(shí)現(xiàn):


創(chuàng)建一個(gè)構(gòu)造函數(shù) Vue

在 Vue.prototype 上創(chuàng)建一系列實(shí)例屬性方法,比如 this.$data 等

在 Vue 上創(chuàng)建一些全局方法遂庄,比如 Vue.use 可以注冊插件


我們導(dǎo)入 Vue 構(gòu)造函數(shù) import Vue from ‘vue’ 的時(shí)候(new Vue(options) 之前)寥院,會(huì)生成一個(gè)Vue的構(gòu)造函數(shù),這個(gè)構(gòu)造函數(shù)本身很簡單涛目,但是他上面會(huì)添加一系列的實(shí)例方法和一些全局方法秸谢,讓我們跟著代碼來依次看看如何一步步構(gòu)造一個(gè) Vue 類的凛澎,我們要明白每一步大致是做什么的,但是這里先不深究估蹄,因?yàn)槲覀儠?huì)在接下來幾章具體講解每一步都做了什么塑煎,這里我們先有一個(gè)大致的概念即可。


我們看代碼先從入口開始元媚,這是我們在瀏覽器環(huán)境最常用的一個(gè)入口轧叽,也就是我們 import Vue 的時(shí)候直接導(dǎo)入的,它很簡單刊棕,直接返回了 從 platforms/web/runtime/index/js 中得到的 Vue 構(gòu)造函數(shù)炭晒,具體代碼如下:


platforms/web/entry-runtime.js


import Vue from './runtime/index'

export default Vue


可以看到,這里不是 Vue 構(gòu)造函數(shù)的定義地方甥角,而是返回了從下面一步得到的Vue構(gòu)造函數(shù)网严,但是做了一些平臺相關(guān)的操作,比如內(nèi)置 directives 注冊等嗤无。這里就會(huì)有人問了震束,為什么不直接定義一個(gè)構(gòu)造函數(shù),而是這樣不停的傳遞呢当犯?因?yàn)?vue 有不同的運(yùn)行環(huán)境垢村,而每一個(gè)環(huán)境又有帶不帶 compiler 等不同版本,所以環(huán)境的不同以及版本的不同都會(huì)導(dǎo)致 Vue 類會(huì)有一些差異嚎卫,那么這里會(huì)通過不同的步驟來處理這些差異嘉栓,而所有的環(huán)境版本都要用到的核心代碼是相同的,因此這些相同的代碼就統(tǒng)一到 core/中了拓诸。


完整代碼和我加的注釋如下:


platforms/web/runtime/index.js


import Vue from 'core/index'

import config from 'core/config'

// 省略


import platformDirectives from './directives/index'

import platformComponents from './components/index'


//這里都是web平臺相關(guān)的一些配置

// install platform specific utils

Vue.config.mustUseProp = mustUseProp

// 省略


// 注冊指令和組件侵佃,這里的 directives 和 components 也是web平臺上的,是內(nèi)置的指令和組件奠支,其實(shí)很少

// install platform runtime directives & components

extend(Vue.options.directives, platformDirectives) // 內(nèi)置的directives只有兩個(gè)馋辈,`v-show` 和 `v-model`

extend(Vue.options.components, platformComponents) // 內(nèi)置的組件也很少,只有`keepAlive`, `transition`和 `transitionGroup`


// 如果不是瀏覽器倍谜,就不進(jìn)行 `patch` 操作了

// install platform patch function

Vue.prototype.__patch__ = inBrowser ? patch : noop


// 如果有 `el` 且在瀏覽器中迈螟,則進(jìn)行 `mount` 操作

// public mount method

Vue.prototype.$mount = function (

??el?: string | Element,

??hydrating?: boolean

): Component {

??el = el && inBrowser ? query(el) : undefined

??return mountComponent(this, el, hydrating)

}


// 省略devtool相關(guān)代碼


export default Vue


上面的代碼終于把平臺和配置相關(guān)的邏輯都處理完了,我們可以進(jìn)入到了 core 目錄井联,這里是Vue組件的核心代碼,我們首先進(jìn)入 core/index文件烙常,發(fā)現(xiàn) Vue 構(gòu)造函數(shù)也不是在這里定義的。不過這里有一點(diǎn)值得注意的就是侦副,這里調(diào)用了一個(gè) initGlobalAPI 函數(shù),這個(gè)函數(shù)是添加一些全局屬性方法到 Vue 上驼鞭,也就是類方法秦驯,而不是實(shí)例方法。具體他是做什么的我們后面再講


core/index.js


import Vue from './instance/index'

import { initGlobalAPI } from './global-api/index'


initGlobalAPI(Vue) // 這個(gè)函數(shù)添加了一些類方法屬性


// 省略一些ssr相關(guān)的內(nèi)容

// 省略


Vue.version = '__VERSION__'


export default Vue


到 core/instance/index.js 這里才是真正的創(chuàng)建了 Vue 構(gòu)造函數(shù)的地方挣棕,雖然代碼也很簡單译隘,就是創(chuàng)建了一個(gè)構(gòu)造函數(shù),然后通過mixin把一堆實(shí)例方法添加上去洛心。


core/instance/index.js 完整代碼如下:


//??省略import語句

function Vue (options) {

??if (process.env.NODE_ENV !== 'production' &&

????!(this instanceof Vue)

??) {

????warn('Vue is a constructor and should be called with the `new` keyword')

??}

??this._init(options)

}


initMixin(Vue)

stateMixin(Vue)

eventsMixin(Vue)

lifecycleMixin(Vue)

renderMixin(Vue)


export default Vue


下面我們分成兩段來講解這些代碼分別干了什么固耘。


function Vue (options) {

??if (process.env.NODE_ENV !== 'production' &&

????!(this instanceof Vue)

??) {

????warn('Vue is a constructor and should be called with the `new` keyword')

??}

??this._init(options) // 構(gòu)造函數(shù)有用的只有這一行代碼,是不是很簡單词身,至于這一行代碼具體做了什么厅目,在第二階段我們詳細(xì)講解。

}


這里才是真正的Vue構(gòu)造函數(shù)法严,注意其實(shí)很簡單损敷,忽略在開發(fā)模式下的警告外,只執(zhí)行了一行代碼 this._init(options)深啤∞致可想而知,Vue初始化必定有很多工作要做溯街,比如數(shù)據(jù)的響應(yīng)化诱桂、事件的綁定等,在第二階段我們會(huì)詳細(xì)講解這個(gè)函數(shù)到底做了什么苫幢。這里我們暫且跳過它访诱。


initMixin(Vue)

stateMixin(Vue)

eventsMixin(Vue)

lifecycleMixin(Vue)

renderMixin(Vue)


上面這五個(gè)函數(shù)其實(shí)都是在Vue.prototype上添加了一些屬性方法垫挨,讓我們先找一個(gè)看看具體的代碼韩肝,比如initMixin 就是添加 _init 函數(shù),沒錯(cuò)正是我們構(gòu)造函數(shù)中調(diào)用的那個(gè) this._init(options) 哦九榔,它里面主要是調(diào)用其他的幾個(gè)初始化方法哀峻,因?yàn)楸容^簡單,我們直接看代碼:


core/instance/init.js


export function initMixin (Vue: Class<Component>) {

??// 就是這里哲泊,添加了一個(gè)方法

??Vue.prototype._init = function (options?: Object) {

????// 省略育特,這部分我們會(huì)在第二階段講解

??}

}


另外的幾個(gè)同樣都是在 Vue.prototype 上添加了一些方法缰冤,這里暫時(shí)先不一個(gè)個(gè)貼代碼怀薛,總結(jié)一下如下:


core/instance/state.js枝恋,主要是添加了 $data,$props,$watch,$set,$delete 幾個(gè)屬性和方法

core/instance/events.js焚碌,主要是添加了 $on,$off,$once,$emit 三個(gè)方法

core/instance/lifecycle.js呐能,主要添加了 _update, $forceUpdate, $destroy 三個(gè)方法

core/instance/renderMixin.js,主要添加了 $nextTick 和 _render 兩個(gè)方法以及一大堆renderHelpers


還記得我們跳過的在core/index.js中 添加 globalAPI的代碼嗎偎漫,前面的代碼都是在 Vue.prototype 上添加實(shí)例屬性象踊,讓我們回到 core/index 文件杯矩,這一步需要在 Vue 上添加一些全局屬性方法史隆。前面講到過泌射,是通過 initGlobalAPI 來添加的熔酷,那么我們直接看看這個(gè)函數(shù)的樣子:


export function initGlobalAPI (Vue: GlobalAPI) {

??// config

??const configDef = {}

??configDef.get = () => config

??// 省略


??// 這里添加了一個(gè)`Vue.config` 對象拒秘,至于在哪里會(huì)用到躺酒,后面會(huì)講

??Object.defineProperty(Vue, 'config', configDef)


??// exposed util methods.

??// NOTE: these are not considered part of the public API - avoid relying on

??// them unless you are aware of the risk.

??Vue.util = {

????warn,

????extend,

????mergeOptions,

????defineReactive

??}


??//一般我們用實(shí)例方法而不是這三個(gè)類方法

??Vue.set = set

??Vue.delete = del

??Vue.nextTick = nextTick


??// 注意這里活喊,循環(huán)出來的結(jié)果其實(shí)是三個(gè) `components`,`directives`, `filters`钾菊,這里先創(chuàng)建了空對象作為容器煞烫,后面如果有對應(yīng)的插件就會(huì)放進(jìn)來滞详。

??Vue.options = Object.create(null)

??ASSET_TYPES.forEach(type => {

????Vue.options[type + 's'] = Object.create(null)

??})


??// this is used to identify the "base" constructor to extend all plain-object

??// components with in Weex's multi-instance scenarios.

??Vue.options._base = Vue


??// 內(nèi)置組件只有一個(gè),就是 `keepAlive`

??extend(Vue.options.components, builtInComponents)


??initUse(Vue) // 添加了 Vue.use 方法岸啡,可以注冊插件

??initMixin(Vue) //添加了Vue.mixin 方法

??initExtend(Vue) // 添加了 Vue.extend 方法


??// 這一步是注冊了 `Vue.component` ,`Vue.directive` 和 `Vue.filter` 三個(gè)方法巡蘸,上面不是有 `Vue.options.components` 等空對象嗎悦荒,這三個(gè)方法的作用就是把注冊的組件放入對應(yīng)的容器中搬味。

??initAssetRegisters(Vue)

}


至此身腻,我們就構(gòu)建出了一個(gè) Vue 類,這個(gè)類上的方法都已經(jīng)添加完畢愈诚。這里再次強(qiáng)調(diào)一遍炕柔,這個(gè)階段只是添加方法而不是執(zhí)行他們陵刹,具體執(zhí)行他們是要到第二階段的欢嘿∠壑妫總結(jié)一下狗热,我們創(chuàng)建的Vue類都包含了哪些內(nèi)容:


//構(gòu)造函數(shù)

function Vue () {

??this._init()

}


//全局config對象匿刮,我們幾乎不會(huì)用到

Vue.config = {

??keyCodes,

??_lifecycleHooks: ['beforeCreate', 'created', ...]

}


// 默認(rèn)的options配置僻焚,我們每個(gè)組件都會(huì)繼承這個(gè)配置虑啤。

Vue.options = {

??beforeCreate, // 比如 vue-router 就會(huì)注冊這個(gè)回調(diào)狞山,因此會(huì)每一個(gè)組件繼承

??components, // 前面提到了,默認(rèn)組件有三個(gè) `KeepAlive`,`transition`, `transitionGroup`勘纯,這里注冊的組件就是全局組件驳遵,因?yàn)槿魏我粋€(gè)組件中不用聲明就能用了堤结。所以全局組件的原理就是這么簡單

??directives, // 默認(rèn)只有 `v-show` 和 `v-model`

??filters // 不推薦使用了

}


//一些全局方法

Vue.use // 注冊插件

Vue.component // 注冊組件

Vue.directive // 注冊指令

Vue.nextTick //下一個(gè)tick執(zhí)行函數(shù)

Vue.set/delete // 數(shù)據(jù)的修改操作

Vue.mixin // 混入mixin用的


//Vue.prototype 上有幾種不同作用的方法


//由initMixin 添加的 `_init` 方法唐责,是Vue實(shí)例初始化的入口方法鼠哥,會(huì)調(diào)用其他的功能初始話函數(shù)

Vue.prototype._init


// 由 initState 添加的三個(gè)用來進(jìn)行數(shù)據(jù)操作的方法

Vue.prototype.$data

Vue.prototype.$props

Vue.prototype.$watch


// 由initEvents添加的事件方法

Vue.prototype.$on

Vue.prototype.$off

Vue.prototype.$one

Vue.prototype.$emit


// 由 lifecycle添加的生命周期相關(guān)的方法

Vue.prototype._update

Vue.prototype.$forceUpdate

Vue.prototype.$destroy


//在 platform 中添加的生命周期方法

Vue.prototype.$mount


// 由renderMixin添加的`$nextTick` 和 `_render` 以及一堆renderHelper

Vue.prototype.$nextTick

Vue.prototype._render

Vue.prototype._b

Vue.prototype._e

//...


上述就是我們的 Vue 類的全部了帽衙,有一些特別細(xì)小的點(diǎn)暫時(shí)沒有列出來,如果你在后面看代碼的時(shí)候,發(fā)現(xiàn)有哪個(gè)函數(shù)不知道在哪定義的谴垫,可以參考這里乳怎。那么讓我們進(jìn)入第二個(gè)階段:創(chuàng)建實(shí)例階段


第二階段:創(chuàng)建 Vue 實(shí)例

我們通過 new Vue(options) 來創(chuàng)建一個(gè)實(shí)例前弯,實(shí)例的創(chuàng)建询枚,肯定是從構(gòu)造函數(shù)開始的金蜀,然后會(huì)進(jìn)行一系列的初始化操作,我們依次看一下創(chuàng)建過程都進(jìn)行了什么初始化操作:


core/instance/index.js, 構(gòu)造函數(shù)本身只進(jìn)行了一個(gè)操作护桦,就是調(diào)用 this._init(options) 進(jìn)行初始化嘶炭,這個(gè)在前面也提到過,這里就不貼代碼了睡陪。


core/instance/init.js 中會(huì)進(jìn)行真正的初始化操作,讓我們詳細(xì)看一下這個(gè)函數(shù)具體都做了些什么汁果。


先看看它的完整代碼:


Vue.prototype._init = function (options?: Object) {

??const vm: Component = this

??// a uid

??vm._uid = uid++


??let startTag, endTag

??/* istanbul ignore if */

??if (process.env.NODE_ENV !== 'production' && config.performance && mark) {

????startTag = `vue-perf-start:${vm._uid}`

????endTag = `vue-perf-end:${vm._uid}`

????mark(startTag)

??}


??// a flag to avoid this being observed

??vm._isVue = true

??// merge options

??if (options && options._isComponent) {

????// optimize internal component instantiation

????// since dynamic options merging is pretty slow, and none of the

????// internal component options needs special treatment.

????initInternalComponent(vm, options)

??} else {

????vm.$options = mergeOptions(

??????resolveConstructorOptions(vm.constructor),

??????options || {},

??????vm

????)

??}

??/* istanbul ignore else */

??if (process.env.NODE_ENV !== 'production') {

????initProxy(vm)

??} else {

????vm._renderProxy = vm

??}

??// expose real self

??vm._self = vm

??initLifecycle(vm)

??initEvents(vm)

??initRender(vm)

??callHook(vm, 'beforeCreate')

??initInjections(vm) // resolve injections before data/props

??initState(vm)

??initProvide(vm) // resolve provide after data/props

??callHook(vm, 'created')


??/* istanbul ignore if */

??if (process.env.NODE_ENV !== 'production' && config.performance && mark) {

????vm._name = formatComponentName(vm, false)

????mark(endTag)

????measure(`vue ${vm._name} init`, startTag, endTag)

??}


??if (vm.$options.el) {

????vm.$mount(vm.$options.el)

??}

}


我們來一段一段看看上面的代碼分別作了什么跷车。


const vm: Component = this // vm 就是this的一個(gè)別名而已

????// a uid

????vm._uid = uid++ // 唯一自增ID


????let startTag, endTag

????/* istanbul ignore if */

????if (process.env.NODE_ENV !== 'production' && config.performance && mark) {

??????startTag = `vue-perf-start:${vm._uid}`

??????endTag = `vue-perf-end:${vm._uid}`

??????mark(startTag)

????}


這段代碼首先生成了一個(gè)全局唯一的id善玫。然后如果是非生產(chǎn)環(huán)境并且開啟了 performance,那么會(huì)調(diào)用 mark 進(jìn)行performance標(biāo)記密强,這段代碼就是開發(fā)模式下收集性能數(shù)據(jù)的茅郎,因?yàn)楹蚔ue本身的運(yùn)行原理無關(guān),我們先跳過或渤。


?// a flag to avoid this being observed

????vm._isVue = true

????// merge options

????//

????// TODO

????if (options && options._isComponent) {

??????// optimize internal component instantiation

??????// since dynamic options merging is pretty slow, and none of the

??????// internal component options needs special treatment.

??????initInternalComponent(vm, options)

????} else {

??????// mergeOptions 本身比較簡單只洒,就是做了一個(gè)合并操作

??????vm.$options = mergeOptions(

????????resolveConstructorOptions(vm.constructor),

????????options || {},

????????vm

??????)

????}


上面這段代碼,暫時(shí)先不用管_isComponent劳坑,暫時(shí)只需要知道我們自己開發(fā)的時(shí)候使用的組件毕谴,都不是 _isComponent,所以我們會(huì)進(jìn)入到 else語句中距芬。這里主要是進(jìn)行了 options的合并离斩,最終生成了一個(gè) $options 屬性。下一章我們會(huì)詳細(xì)講解 options 合并的時(shí)候都做了什么,這里我們只需要暫時(shí)知道左腔,他是把構(gòu)造函數(shù)上的options和我們創(chuàng)建組件時(shí)傳入的配置 options 進(jìn)行了一個(gè)合并就可以了蓄愁。正是由于合并了這個(gè)全局的 options 所以我們在可以直接在組件中使用全局的 directives 等


?/* istanbul ignore else */

????if (process.env.NODE_ENV !== 'production') {

??????initProxy(vm)

????} else {

??????vm._renderProxy = vm

????}


這段代碼可能看起來比較奇怪站超,這個(gè) renderProxy 是干嘛的呢,其實(shí)就是定義了在 render 函數(shù)渲染模板的時(shí)候倒彰,訪問屬性的時(shí)候的一個(gè)代理,可以看到生產(chǎn)環(huán)境下就是自己阅酪。


開發(fā)環(huán)境下作了一個(gè)什么操作呢辉词?暫時(shí)不用關(guān)心幢哨,反正知道渲染模板的時(shí)候上下文就是 vm 也就是 this 就行了厂画。如果有興趣可以看看非生產(chǎn)環(huán)境抛人,作了一些友好的報(bào)錯(cuò)提醒等荠商。


這里只需要記住,在生產(chǎn)環(huán)境下,模板渲染的上下文就是 vm就行了。


?// expose real self

????vm._self = vm


????initLifecycle(vm) // 做了一些生命周期的初始化工作豪筝,初始化了很多變量聪富,最主要是設(shè)置了父子組件的引用關(guān)系涮雷,也就是設(shè)置了 `$parent` 和 `$children`的值

????initEvents(vm) // 注冊事件储藐,注意這里注冊的不是自己的浮梢,而是父組件的。因?yàn)楹苊黠@父組件的監(jiān)聽器才會(huì)注冊到孩子身上远豺。

????initRender(vm) // 做一些 render 的準(zhǔn)備工作裁蚁,比如處理父子繼承關(guān)系等,并沒有真的開始 render

????callHook(vm, 'beforeCreate') // 準(zhǔn)備工作完成,接下來進(jìn)入 `create` 階段

????initInjections(vm) // resolve injections before data/props

????initState(vm) // `data`, `props`, `computed` 等都是在這里初始化的,常見的面試考點(diǎn)比如`Vue是如何實(shí)現(xiàn)數(shù)據(jù)響應(yīng)化的` 答案就在這個(gè)函數(shù)中尋找

????initProvide(vm) // resolve provide after data/props

????callHook(vm, 'created') // 至此 `create` 階段完成


這一段代碼承擔(dān)了組件初始化的大部分工作诀黍。我直接把每一步的作用寫在注釋里面了。 把這幾個(gè)函數(shù)都弄懂仗处,那么我們也就差不多弄懂了Vue的整個(gè)工作原理眯勾,而我們接下來的幾篇文章,其實(shí)都是從這幾個(gè)函數(shù)中的某一個(gè)開始的婆誓。


?if (vm.$options.el) {

??????vm.$mount(vm.$options.el)

????}

??}

}


開始mount吃环,注意這里如果是我們的options中指定了 el 才會(huì)在這里進(jìn)行 $mount,而一般情況下洋幻,我們是不設(shè)置 el 而是通過直接調(diào)用 $mount("#app") 來觸發(fā)的郁轻。比如一般我們都是這樣的:


new Vue({

??router,

??store,

??i18n,

??render: h => h(App)

}).$mount('#app')


以上就是Vue實(shí)例的初始化過程。

感興趣的小伙伴鞋屈,可以關(guān)注公眾號【grain先森】范咨,回復(fù)關(guān)鍵詞 “vue”,獲取更多資料厂庇,更多關(guān)鍵詞玩法期待你的探索~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末渠啊,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子权旷,更是在濱河造成了極大的恐慌替蛉,老刑警劉巖贯溅,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異躲查,居然都是意外死亡它浅,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門镣煮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來姐霍,“玉大人,你說我怎么就攤上這事典唇∧髡郏” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵介衔,是天一觀的道長恨胚。 經(jīng)常有香客問我,道長炎咖,這世上最難降的妖魔是什么赃泡? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮乘盼,結(jié)果婚禮上升熊,老公的妹妹穿的比我還像新娘。我一直安慰自己蹦肴,他們只是感情好僚碎,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布猴娩。 她就那樣靜靜地躺著阴幌,像睡著了一般。 火紅的嫁衣襯著肌膚如雪卷中。 梳的紋絲不亂的頭發(fā)上矛双,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機(jī)與錄音蟆豫,去河邊找鬼议忽。 笑死,一個(gè)胖子當(dāng)著我的面吹牛十减,可吹牛的內(nèi)容都是我干的栈幸。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼帮辟,長吁一口氣:“原來是場噩夢啊……” “哼速址!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起由驹,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤芍锚,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體并炮,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡默刚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了逃魄。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片荤西。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖伍俘,靈堂內(nèi)的尸體忽然破棺而出皂冰,到底是詐尸還是另有隱情,我是刑警寧澤养篓,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布秃流,位于F島的核電站,受9級特大地震影響柳弄,放射性物質(zhì)發(fā)生泄漏舶胀。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一碧注、第九天 我趴在偏房一處隱蔽的房頂上張望嚣伐。 院中可真熱鬧,春花似錦萍丐、人聲如沸轩端。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽基茵。三九已至,卻和暖如春壳影,著一層夾襖步出監(jiān)牢的瞬間拱层,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工宴咧, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留根灯,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓掺栅,卻偏偏與公主長得像烙肺,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子氧卧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

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