Vue.js源碼解析-Vue初始化流程

2. 初始化相關(guān)代碼分析

2.1 initGlobalAPI(Vue) 初始化Vue的全局靜態(tài)API

平時開發(fā)通過 new Vue({...}) 去創(chuàng)建了根實例疆偿,當然在此之前形病,Vue已經(jīng)做了一些前期的準備工作辰狡。Vue 的核心代碼都在 src/core 目錄中,我們先來看看 core/index.js 這個入口文件伏恐,這部分代碼邏輯很簡單哮针。

import Vue from './instance/index'

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

import { isServerRendering } from 'core/util/env'

import { FunctionalRenderContext } from 'core/vdom/create-functional-component'

// 初始化全局API

initGlobalAPI(Vue)

// 下面代碼是服務端ssr渲染使用,web端可以忽略

Object.defineProperty(Vue.prototype, '$isServer', {

? get: isServerRendering

})

Object.defineProperty(Vue.prototype, '$ssrContext', {

? get () {

? ? /* istanbul ignore next */

? ? return this.$vnode && this.$vnode.ssrContext

? }

})

// expose FunctionalRenderContext for ssr runtime helper installation

Object.defineProperty(Vue, 'FunctionalRenderContext', {

? value: FunctionalRenderContext

})

// 添加 vue 版本號這個靜態(tài)變量

Vue.version = '__VERSION__'

export default Vue

我們主要關(guān)注的 initGlobalAPI(Vue) 這個函數(shù)演怎,它定義在 core/global-api/index.js 文件中,主要給構(gòu)造函數(shù)避乏,添加諸如 Vue.set/delete/use/mixin/extend/component/directive/filter 這些靜態(tài)方法爷耀。

/* @flow */

import config from '../config'

import { initUse } from './use'

import { initMixin } from './mixin'

import { initExtend } from './extend'

import { initAssetRegisters } from './assets'

import { set, del } from '../observer/index'

import { ASSET_TYPES } from 'shared/constants'

import builtInComponents from '../components/index'

import { observe } from 'core/observer/index'

import {

? warn,

? extend,

? nextTick,

? mergeOptions,

? defineReactive

} from '../util/index'

export function initGlobalAPI (Vue: GlobalAPI) {

? // config

? // 這個是給 Vue 設置的 config 屬性,不要手動的去替換這個對象拍皮,

? // 如果替換歹叮,vue 會給 warn 提示

? const configDef = {}

? configDef.get = () => config

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

? ? configDef.set = () => {

? ? ? warn(

? ? ? ? 'Do not replace the Vue.config object, set individual fields instead.'

? ? ? )

? ? }

? }

? 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

? }

? // Vue的靜態(tài)方法: Vue.set/delete/nextTick

? Vue.set = set

? Vue.delete = del

? Vue.nextTick = nextTick

? // 2.6 explicit observable API

? Vue.observable = <T>(obj: T): T => {

? ? observe(obj)

? ? return obj

? }


? Vue.options = Object.create(null)

? ASSET_TYPES.forEach(type => {

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

? })

? // 用于標識 Weex 多實例場景中,通過“base”標識普通對象組件的構(gòu)造函數(shù)铆帽。

? // 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


? extend(Vue.options.components, builtInComponents)

? // Vue的靜態(tài)方法: Vue.use/mixin/extend

? initUse(Vue)

? initMixin(Vue)

? initExtend(Vue)

? // Vue的靜態(tài)屬性方法:Vue.component/directive/filter

? initAssetRegisters(Vue)

}

其中 initAssetRegisters(Vue)盗胀,通過靜態(tài)變量數(shù)組 [ 'component', 'directive','filter'] 遍歷創(chuàng)建了Vue.component/directive/filter 這三個靜態(tài)屬性方法。 靜態(tài)變量配置在 src/shared/constants.js 文件中锄贼,方法定義在 core/global-api/assets.js 文件中票灰。

export const SSR_ATTR = 'data-server-rendered'

// 注冊全局API時候使用

export const ASSET_TYPES = [

? 'component',

? 'directive',

? 'filter'

]

// 生命周期函數(shù)使用

export const LIFECYCLE_HOOKS = [

? 'beforeCreate',

? 'created',

? 'beforeMount',

? 'mounted',

? 'beforeUpdate',

? 'updated',

? 'beforeDestroy',

? 'destroyed',

? 'activated',

? 'deactivated',

? 'errorCaptured',

? 'serverPrefetch'

]

/* @flow */

import { ASSET_TYPES } from 'shared/constants'

import { isPlainObject, validateComponentName } from '../util/index'

export function initAssetRegisters (Vue: GlobalAPI) {

? /**

? * Create asset registration methods.

? */

? ASSET_TYPES.forEach(type => {

? ? // Vue.comoponent/directive/filter 靜態(tài)方法的綁定

? ? Vue[type] = function (

? ? ? id: string,

? ? ? definition: Function | Object

? ? ): Function | Object | void {

? ? ? if (!definition) {

? ? ? ? return this.options[type + 's'][id]

? ? ? } else {

? ? ? ? /* istanbul ignore if */

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

? ? ? ? ? validateComponentName(id)

? ? ? ? }

? ? ? ? if (type === 'component' && isPlainObject(definition)) {

? ? ? ? ? definition.name = definition.name || id

? ? ? ? ? definition = this.options._base.extend(definition)

? ? ? ? }

? ? ? ? if (type === 'directive' && typeof definition === 'function') {

? ? ? ? ? definition = { bind: definition, update: definition }

? ? ? ? }

? ? ? ? this.options[type + 's'][id] = definition

? ? ? ? return definition

? ? ? }

? ? }

? })

}

2.2 定義Vue構(gòu)造函數(shù)、實例方法

Vue 這個構(gòu)造函數(shù)宅荤,定義在 core/instance/index.js 文件中屑迂。從代碼中可以看到,用工廠模式冯键,執(zhí)行不同的混入函數(shù)惹盼,對 Vue.prototype 原型進行加工,給實例添加對應的屬性方法惫确。

import { initMixin } from './init'

import { stateMixin } from './state'

import { renderMixin } from './render'

import { eventsMixin } from './events'

import { lifecycleMixin } from './lifecycle'

import { warn } from '../util/index'

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')

? }

? // 構(gòu)造函數(shù)中執(zhí)行 Vue.prototype._init 方法

? this._init(options)?

}

// 實例初始化方法: Vue.prototype._init

initMixin(Vue)

// 實例數(shù)據(jù)狀態(tài)相關(guān)方法: Vue.prototype.$data/$props/$set/$delete,$watch

stateMixin(Vue)

// 實例事件相關(guān)方法: Vue.prototype.$on/$once/$off/$emit

eventsMixin(Vue)

// 實例生命周期相關(guān)方法:Vue.prototype._update/$forceUpdate/$destory

lifecycleMixin(Vue)

// 實例渲染相關(guān)方法:Vue.prototype.$nextTick/_render

renderMixin(Vue)

export default Vue

2.3 new Vue(options)

執(zhí)行 new Vue() 創(chuàng)建組件實例手报,同時 this._init(options) 初始化方法被執(zhí)行,合并用戶配置改化、初始化周期掩蛤、事件、數(shù)據(jù)陈肛、屬性等揍鸟。

new Vue({

? ? data: {...},

? ? props: {...},

? ? methods: {...},

? ? computed: {...}

? ? ...

})

這部分處理邏輯在 core/instance/indexjs 文件中,與 _init() 相關(guān)的主要看 initMixin 這個函數(shù)句旱。

/* @flow */

import config from '../config'

import { initProxy } from './proxy'

import { initState } from './state'

import { initRender } from './render'

import { initEvents } from './events'

import { mark, measure } from '../util/perf'

import { initLifecycle, callHook } from './lifecycle'

import { initProvide, initInjections } from './inject'

import { extend, mergeOptions, formatComponentName } from '../util/index'

let uid = 0

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

? 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? // 拋出vue實例本身

? ? vm._self = vm


? ? // 初始化屬性:vm.$parent/$root/$children/$refs

? ? initLifecycle(vm)


? ? // 初始化父組件傳入的 _parentListeners 事件阳藻。

? ? initEvents(vm)


? ? // 初始化render相關(guān):vm.$slot/scopedSlots/_c/$createElement

? ? initRender(vm)


? ? // 調(diào)用生命鉤子 beforeCreate

? ? callHook(vm, 'beforeCreate')


? ? // 在data/props之前解析注入

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


? ? // 初始化相關(guān)用戶配置的數(shù)據(jù)響應式:vm._props/_data, 以及computed、watch谈撒、methods

? ? initState(vm)


? ? // 在 data/props 之后提供數(shù)據(jù)

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


? ? // 調(diào)用生命鉤子 created

? ? 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)

? ? }

? }

}

......

2.4 執(zhí)行 $mount 進行掛載

執(zhí)行 mount執(zhí)行掛載腥泥,目錄是為了生成vnode,進而轉(zhuǎn)換為真實DOM執(zhí)行更新啃匿。mount 方法在 web 端相關(guān)兩個 src/platform/web/entry-runtime-with-compiler.js蛔外、src/platform/web/runtime/index.js 構(gòu)建文件中都有定義蛆楞。我們這里分析 entry-runtime-with-compiler.js 帶 compiler 版本的入口文件。關(guān)于 Vue scripts 腳本構(gòu)建相關(guān)的內(nèi)容冒萄,大家可以參考我之前寫的 這篇文章 的第2章節(jié)臊岸。

entry-runtime-with-compiler.js 版本,是在 src/platform/web/runtime/index.js 版本的基礎上尊流,加 compiler 相關(guān)的功能邏輯帅戒。它首先保存 runtime 版本的 mount = Vue.prototype.mount方法。再重寫Vue.prototype.mount 方法崖技。如果用戶傳入 template 模板逻住,就通過編譯,轉(zhuǎn)換成 render 函數(shù)迎献。最后通過先前保存的 mount 方法進行掛載瞎访。下面我們在再來復習一下這個 $mount 實現(xiàn)邏輯。

......

// 1. 保存 runtime 版本 Vue.prototype 上的 $mount 方法

const mount = Vue.prototype.$mount

// 2. 重寫 Vue.prototype 上的 $mount(加上 compiler 相關(guān)功能邏輯)

Vue.prototype.$mount = function (

? el?: string | Element,

? hydrating?: boolean

): Component {

? el = el && query(el)

? /* istanbul ignore if */

? if (el === document.body || el === document.documentElement) {

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

? ? ? `Do not mount Vue to <html> or <body> - mount to normal elements instead.`

? ? )

? ? return this

? }

? // 處理 options 配置

? const options = this.$options

? // resolve template/el and convert to render function

? if (!options.render) {

? ? let template = options.template

? ? if (template) {

? ? ? if (typeof template === 'string') {

? ? ? ? if (template.charAt(0) === '#') {

? ? ? ? ? template = idToTemplate(template)

? ? ? ? ? /* istanbul ignore if */

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

? ? ? ? ? ? warn(

? ? ? ? ? ? ? `Template element not found or is empty: ${options.template}`,

? ? ? ? ? ? ? this

? ? ? ? ? ? )

? ? ? ? ? }

? ? ? ? }

? ? ? } else if (template.nodeType) {

? ? ? ? template = template.innerHTML

? ? ? } else {

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

? ? ? ? ? warn('invalid template option:' + template, this)

? ? ? ? }

? ? ? ? return this

? ? ? }

? ? } else if (el) {

? ? ? template = getOuterHTML(el)

? ? }

? ? // 3. 存在 template 選項內(nèi)容吁恍,就進行編譯扒秸。

? ? if (template) {

? ? ? /* istanbul ignore if */

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

? ? ? ? mark('compile')

? ? ? }

? ? ? // 編譯獲取 render 函數(shù)

? ? ? const { render, staticRenderFns } = compileToFunctions(template, {

? ? ? ? outputSourceRange: process.env.NODE_ENV !== 'production',

? ? ? ? shouldDecodeNewlines,

? ? ? ? shouldDecodeNewlinesForHref,

? ? ? ? delimiters: options.delimiters,

? ? ? ? comments: options.comments

? ? ? }, this)

? ? ? options.render = render

? ? ? options.staticRenderFns = staticRenderFns

? ? ? /* istanbul ignore if */

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

? ? ? ? mark('compile end')

? ? ? ? measure(`vue ${this._name} compile`, 'compile', 'compile end')

? ? ? }

? ? }

? }


? // 4. 編譯結(jié)束,調(diào)用 runtime 版本的 $mount 方法進行掛載

? return mount.call(this, el, hydrating)

}

......

最后冀瓦,代碼執(zhí)行 mount.call(this, el, hydrating)伴奥。實際上復用了 runtime/index.js 中的定義的 $mount 公共方法,代碼注釋如下翼闽。

/* @flow */

import Vue from 'core/index'

import config from 'core/config'

import { extend, noop } from 'shared/util'

import { mountComponent } from 'core/instance/lifecycle'

import { devtools, inBrowser } from 'core/util/index'

import {

? query,

? mustUseProp,

? isReservedTag,

? isReservedAttr,

? getTagNamespace,

? isUnknownElement

} from 'web/util/index'

import { patch } from './patch'

import platformDirectives from './directives/index'

import platformComponents from './components/index'

// install platform specific utils

Vue.config.mustUseProp = mustUseProp

Vue.config.isReservedTag = isReservedTag

Vue.config.isReservedAttr = isReservedAttr

Vue.config.getTagNamespace = getTagNamespace

Vue.config.isUnknownElement = isUnknownElement

// install platform runtime directives & components

extend(Vue.options.directives, platformDirectives)

extend(Vue.options.components, platformComponents)

// install platform patch function

Vue.prototype.__patch__ = inBrowser ? patch : noop

// 定義了公共的 $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)

}

// devtools global hook

/* istanbul ignore next */

....

export default Vue

公共 $mount 方法實際上調(diào)用了 mountComponent 函數(shù)拾徙,它 core/instance/lifecycle.js 文件中定義,在mountComponent 函數(shù)中感局,實例化一個渲染W(wǎng)atcher尼啡,此時 Watcher 內(nèi)部邏輯中調(diào)用定義的 updateComponent 函數(shù)。updateComponent 被調(diào)用询微, vm._render 執(zhí)行生成 vnode崖瞭,最終調(diào)用 _update 將 vnode 更新成 DOM,代碼注釋如下拓提。

...

export function mountComponent (

? vm: Component,

? el: ?Element,

? hydrating?: boolean

): Component {

? vm.$el = el

? if (!vm.$options.render) {

? ? vm.$options.render = createEmptyVNode

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

? ? ? /* istanbul ignore if */

? ? ? if ((vm.$options.template && vm.$options.template.charAt(0) !== '#') ||

? ? ? ? vm.$options.el || el) {

? ? ? ? warn(

? ? ? ? ? 'You are using the runtime-only build of Vue where the template ' +

? ? ? ? ? 'compiler is not available. Either pre-compile the templates into ' +

? ? ? ? ? 'render functions, or use the compiler-included build.',

? ? ? ? ? vm

? ? ? ? )

? ? ? } else {

? ? ? ? warn(

? ? ? ? ? 'Failed to mount component: template or render function not defined.',

? ? ? ? ? vm

? ? ? ? )

? ? ? }

? ? }

? }

? // 調(diào)用 beforeMount 鉤子

? callHook(vm, 'beforeMount')

? let updateComponent

? /* istanbul ignore if */? // web端可以忽略

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

? ? updateComponent = () => {

? ? ? const name = vm._name

? ? ? const id = vm._uid

? ? ? const startTag = `vue-perf-start:${id}`

? ? ? const endTag = `vue-perf-end:${id}`

? ? ? mark(startTag)

? ? ? const vnode = vm._render()

? ? ? mark(endTag)

? ? ? measure(`vue ${name} render`, startTag, endTag)

? ? ? mark(startTag)

? ? ? vm._update(vnode, hydrating)

? ? ? mark(endTag)

? ? ? measure(`vue ${name} patch`, startTag, endTag)

? ? }

? } else {

? ? // 定義updateComponent方法读恃,渲染 watcher 內(nèi)部會調(diào)用。

? ? // 如果 updateComponent 被調(diào)用代态,render 方法先執(zhí)行,生成 vnode疹吃。

? ? // 最后執(zhí)行 _update 方法蹦疑,進行DOM更新,new Vue() 走的是創(chuàng)建DOM邏輯萨驶。

? ? updateComponent = () => {

? ? ? vm._update(vm._render(), hydrating)

? ? }

? }

? // 初始化渲染 watcher歉摧,內(nèi)部邏輯會調(diào)用 updateComponent。

? // we set this to vm._watcher inside the watcher's constructor

? // since the watcher's initial patch may call $forceUpdate (e.g. inside child

? // component's mounted hook), which relies on vm._watcher being already defined

? new Watcher(vm, updateComponent, noop, {

? ? before () {

? ? ? if (vm._isMounted && !vm._isDestroyed) {

? ? ? ? callHook(vm, 'beforeUpdate')

? ? ? }

? ? }

? }, true /* isRenderWatcher */)

? hydrating = false


? // 如果 vm.$vnode === null 當前 vm 的父 vnode 為null。

? // 即判斷 vm 當前實例為 Vue 的根實例.

? // vm.$vnode 在上面的 updateChildComponent 方法中有的定義 vm.$vnode = parentVnode

? // manually mounted instance, call mounted on self

? // mounted is called for render-created child components in its inserted hook

? if (vm.$vnode == null) {

? ? vm._isMounted = true? // 標記該Vue根實例掛載結(jié)束

? ? callHook(vm, 'mounted')? // 執(zhí)行鉤子 mounted叁温。

? }

? return vm

}

...

2.5 執(zhí)行 _render 生成 vnode

vm._render 方法在之前的內(nèi)容中有提到再悼,它定義 instance/index.js 文件中,它是在 Vue 構(gòu)造函數(shù)定義的時候膝但,給Vue添加的實例方法冲九。

具體邏輯在 src/core/instance/render.js 文件中。其他代碼邏輯可以先不關(guān)注跟束,主要關(guān)注莺奸,vnode = render.call(vm._renderProxy, vm.$createElement) 這部分調(diào)用。

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

? // install runtime convenience helpers

? installRenderHelpers(Vue.prototype)

? Vue.prototype.$nextTick = function (fn: Function) {

? ? return nextTick(fn, this)

? }

? // 給實例初始化render方法

? Vue.prototype._render = function (): VNode {

? ? ...?

? ? try {

? ? ? // There's no need to maintain a stack because all render fns are called

? ? ? // separately from one another. Nested component's render fns are called

? ? ? // when parent component is patched.

? ? ? currentRenderingInstance = vm

? ? ? // 調(diào)用用戶定義 render 函數(shù)生成vnode

? ? ? vnode = render.call(vm._renderProxy, vm.$createElement)?

? ? }

? ? ...

? ? return vnode

? }

}

render.call 執(zhí)行冀宴,傳入了 vm.createElement灭贷,這里就是用戶可以通過手寫render函數(shù),用來生成vnode的實現(xiàn)略贮。示例如下甚疟,其中h就是vm.createElement。

<div id="app">

? {{title}}

</div>

<script>

? window.app = new Vue({

? ? data: {

? ? ? title: 'vue render'

? ? },

? ? // 手寫 render 函數(shù)逃延,h === vm.$createElement

? ? render(h) {

? ? ? return h(

? ? ? ? 'div',

? ? ? ? {

? ? ? ? ? attrs: {

? ? ? ? ? ? id: 'demo'

? ? ? ? ? }

? ? ? ? },

? ? ? ? this.title

? ? ? );

? ? }

? }).$mount('#app');

</script>

USB Microphone https://www.soft-voice.com/

Wooden Speakers? https://www.zeshuiplatform.com/

亞馬遜測評 www.yisuping.cn

深圳網(wǎng)站建設www.sz886.com

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末览妖,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子真友,更是在濱河造成了極大的恐慌黄痪,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盔然,死亡現(xiàn)場離奇詭異桅打,居然都是意外死亡,警方通過查閱死者的電腦和手機愈案,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門挺尾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人站绪,你說我怎么就攤上這事遭铺。” “怎么了恢准?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵魂挂,是天一觀的道長。 經(jīng)常有香客問我馁筐,道長涂召,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任敏沉,我火速辦了婚禮果正,結(jié)果婚禮上炎码,老公的妹妹穿的比我還像新娘。我一直安慰自己秋泳,他們只是感情好浪感,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布翩活。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪旦万。 梳的紋絲不亂的頭發(fā)上橄仆,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天歌豺,我揣著相機與錄音桅滋,去河邊找鬼。 笑死既绩,一個胖子當著我的面吹牛概龄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播饲握,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼私杜,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了救欧?” 一聲冷哼從身側(cè)響起衰粹,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎笆怠,沒想到半個月后铝耻,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡蹬刷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年瓢捉,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片办成。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡泡态,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出迂卢,到底是詐尸還是另有隱情某弦,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布而克,位于F島的核電站靶壮,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏员萍。R本人自食惡果不足惜亮钦,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望充活。 院中可真熱鬧蜂莉,春花似錦、人聲如沸混卵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽幕随。三九已至蚁滋,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間赘淮,已是汗流浹背辕录。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留梢卸,地道東北人走诞。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像蛤高,于是被迫代替她去往敵國和親蚣旱。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344

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