vue3.0--組合式API

setup

setup?函數是一個新的組件選項。作為在組件內使用 Composition API 的入口點。

調用時機

創建組件實例,然后初始化?props?,緊接著就調用setup?函數。從生命周期鉤子的視角來看,它會在?beforeCreate?鉤子之前被調用

模板中使用

如果?setup?返回一個對象,則對象的屬性將會被合并到組件模板的渲染上下文:

<template><div>{{ count }} {{ object.foo }}</div></template><script>import{ref,reactive}from'vue'exportdefault{setup(){constcount=ref(0)constobject=reactive({foo:'bar'})// 暴露給模板return{count,object,}},}</script>

注意?setup?返回的 ref 在模板中會自動解開,不需要寫?.value。

渲染函數 / JSX 中使用

setup?也可以返回一個函數,函數中也能使用當前?setup?函數作用域中的響應式數據:

import{h,ref,reactive}from'vue'exportdefault{setup(){constcount=ref(0)constobject=reactive({foo:'bar'})return()=>h('div',[count.value,object.foo])},}

參數

該函數接收?props?作為其第一個參數:

exportdefault{props:{name:String,},setup(props){console.log(props.name)},}

注意?props?對象是響應式的,watchEffect?或?watch?會觀察和響應?props?的更新:

exportdefault{props:{name:String,},setup(props){watchEffect(()=>{console.log(`name is: `+props.name)})},}

然而不要解構?props?對象,那樣會使其失去響應性:

exportdefault{props:{name:String,},setup({name}){watchEffect(()=>{console.log(`name is: `+name)// Will not be reactive!})},}

在開發過程中,props?對象對用戶空間代碼是不可變的(用戶代碼嘗試修改?props?時會觸發警告)。

第二個參數提供了一個上下文對象,從原來 2.x 中?this?選擇性地暴露了一些 property。

constMyComponent={setup(props,context){context.attrs? ? context.slots? ? context.emit},}

attrs?和?slots?都是內部組件實例上對應項的代理,可以確保在更新后仍然是最新值。所以可以解構,無需擔心后面訪問到過期的值:

constMyComponent={setup(props,{attrs}){// 一個可能之后回調用的簽名functiononClick(){console.log(attrs.foo)// 一定是最新的引用,沒有丟失響應性}},}

出于一些原因將?props?作為第一個參數,而不是包含在上下文中:

組件使用?props?的場景更多,有時候甚至只使用?props

將?props?獨立出來作為第一個參數,可以讓 TypeScript 對?props?單獨做類型推導,不會和上下文中的其他屬性相混淆。這也使得?setup?、?render?和其他使用了 TSX 的函數式組件的簽名保持一致。

this的用法

this?在?setup()?中不可用。由于?setup()?在解析 2.x 選項前被調用,setup()?中的?this?將與 2.x 選項中的?this?完全不同。同時在?setup()?和 2.x 選項中使用?this?時將造成混亂。在?setup()?中避免這種情況的另一個原因是:這對于初學者來說,混淆這兩種情況的?this?是非常常見的錯誤:

setup(){functiononClick(){this// 這里 `this` 與你期望的不一樣!}}

類型定義

interfaceData{[key:string]:unknown}interfaceSetupContext{attrs:Data? slots:Slotsemit:(event:string,...args:unknown[])=>void}functionsetup(props:Data,context:SetupContext):Data

提示

為了獲得傳遞給 setup() 參數的類型推斷,需要使用 defineComponent。

#響應式系統 API

#reactive

接收一個普通對象然后返回該普通對象的響應式代理。等同于 2.x 的?Vue.observable()

constobj=reactive({count:0})

響應式轉換是“深層的”:會影響對象內部所有嵌套的屬性。基于 ES2015 的 Proxy 實現,返回的代理對象不等于原始對象。建議僅使用代理對象而避免依賴原始對象。

類型定義

functionreactive<Textendsobject>(raw:T):T

#ref

接受一個參數值并返回一個響應式且可改變的 ref 對象。ref 對象擁有一個指向內部值的單一屬性?.value。

constcount=ref(0)console.log(count.value)// 0count.value++console.log(count.value)// 1

如果傳入 ref 的是一個對象,將調用?reactive?方法進行深層響應轉換。

模板中訪問

當 ref 作為渲染上下文的屬性返回(即在setup()?返回的對象中)并在模板中使用時,它會自動解套,無需在模板內額外書寫?.value:

<template><div>{{ count }}</div></template><script>exportdefault{setup(){return{count:ref(0),}},}</script>

作為響應式對象的屬性訪問

當 ref 作為 reactive 對象的 property 被訪問或修改時,也將自動解套 value 值,其行為類似普通屬性:

constcount=ref(0)conststate=reactive({count,})console.log(state.count)// 0state.count=1console.log(count.value)// 1

注意如果將一個新的 ref 分配給現有的 ref, 將替換舊的 ref:

constotherCount=ref(2)state.count=otherCountconsole.log(state.count)// 2console.log(count.value)// 1

注意當嵌套在 reactive?Object?中時,ref 才會解套。從?Array?或者?Map?等原生集合類中訪問 ref 時,不會自動解套:

constarr=reactive([ref(0)])// 這里需要 .valueconsole.log(arr[0].value)constmap=reactive(newMap([['foo',ref(0)]]))// 這里需要 .valueconsole.log(map.get('foo').value)

類型定義

interfaceRef<T>{value:T}functionref<T>(value:T):Ref<T>

有時我們可能需要為 ref 做一個較為復雜的類型標注。我們可以通過在調用?ref?時傳遞泛型參數來覆蓋默認推導:

constfoo=ref<string|number>('foo')// foo 的類型: Ref<string | number>foo.value=123// 能夠通過!

#computed

傳入一個 getter 函數,返回一個默認不可手動修改的 ref 對象。

constcount=ref(1)constplusOne=computed(()=>count.value+1)console.log(plusOne.value)// 2plusOne.value++// 錯誤!

或者傳入一個擁有?get?和?set?函數的對象,創建一個可手動修改的計算狀態。

constcount=ref(1)constplusOne=computed({get:()=>count.value+1,set:(val)=>{count.value=val-1},})plusOne.value=1console.log(count.value)// 0

類型定義

// 只讀的functioncomputed<T>(getter:()=>T):Readonly<Ref<Readonly<T>>>// 可更改的functioncomputed<T>(options:{get:()=>Tset:(value:T)=>void}):Ref<T>

#readonly

傳入一個對象(響應式或普通)或 ref,返回一個原始對象的只讀代理。一個只讀的代理是“深層的”,對象內部任何嵌套的屬性也都是只讀的。

constoriginal=reactive({count:0})constcopy=readonly(original)watchEffect(()=>{// 依賴追蹤console.log(copy.count)})// original 上的修改會觸發 copy 上的偵聽original.count++// 無法修改 copy 并會被警告copy.count++// warning!

#watchEffect

立即執行傳入的一個函數,并響應式追蹤其依賴,并在其依賴變更時重新運行該函數。

constcount=ref(0)watchEffect(()=>console.log(count.value))// -> 打印出 0setTimeout(()=>{count.value++// -> 打印出 1},100)

#停止偵聽

當?watchEffect?在組件的?setup()?函數或生命周期鉤子被調用時, 偵聽器會被鏈接到該組件的生命周期,并在組件卸載時自動停止。

在一些情況下,也可以顯式調用返回值以停止偵聽:

conststop=watchEffect(()=>{/* ... */})// 之后stop()

#清除副作用

有時副作用函數會執行一些異步的副作用, 這些響應需要在其失效時清除(即完成之前狀態已改變了)。所以偵聽副作用傳入的函數可以接收一個?onInvalidate?函數作入參, 用來注冊清理失效時的回調。當以下情況發生時,這個失效回調會被觸發:

副作用即將重新執行時

偵聽器被停止 (如果在?setup()?或 生命周期鉤子函數中使用了?watchEffect, 則在卸載組件時)

watchEffect((onInvalidate)=>{consttoken=performAsyncOperation(id.value)onInvalidate(()=>{// id 改變時 或 停止偵聽時// 取消之前的異步操作token.cancel()})})

我們之所以是通過傳入一個函數去注冊失效回調,而不是從回調返回它(如 React?useEffect?中的方式),是因為返回值對于異步錯誤處理很重要。

在執行數據請求時,副作用函數往往是一個異步函數:

constdata=ref(null)watchEffect(async()=>{data.value=awaitfetchData(props.id)})

我們知道異步函數都會隱式地返回一個 Promise,但是清理函數必須要在 Promise 被 resolve 之前被注冊。另外,Vue 依賴這個返回的 Promise 來自動處理 Promise 鏈上的潛在錯誤。

#副作用刷新時機

Vue 的響應式系統會緩存副作用函數,并異步地刷新它們,這樣可以避免同一個 tick 中多個狀態改變導致的不必要的重復調用。在核心的具體實現中, 組件的更新函數也是一個被偵聽的副作用。當一個用戶定義的副作用函數進入隊列時, 會在所有的組件更新后執行:

<template><div>{{ count }}</div></template><script>exportdefault{setup(){constcount=ref(0)watchEffect(()=>{console.log(count.value)})return{count,}},}</script>

在這個例子中:

count?會在初始運行時同步打印出來

更改?count?時,將在組件更新后執行副作用。

請注意,初始化運行是在組件?mounted?之前執行的。因此,如果你希望在編寫副作用函數時訪問 DOM(或模板 ref),請在?onMounted?鉤子中進行:

onMounted(()=>{watchEffect(()=>{// 在這里可以訪問到 DOM 或者 template refs})})

如果副作用需要同步或在組件更新之前重新運行,我們可以傳遞一個擁有?flush?屬性的對象作為選項(默認為?'post'):

// 同步運行watchEffect(()=>{/* ... */},{flush:'sync',})// 組件更新前執行watchEffect(()=>{/* ... */},{flush:'pre',})

#偵聽器調試

onTrack?和?onTrigger?選項可用于調試一個偵聽器的行為。

當一個 reactive 對象屬性或一個 ref 作為依賴被追蹤時,將調用?onTrack

依賴項變更導致副作用被觸發時,將調用?onTrigger

這兩個回調都將接收到一個包含有關所依賴項信息的調試器事件。建議在以下回調中編寫?debugger?語句來檢查依賴關系:

watchEffect(()=>{/* 副作用的內容 */},{onTrigger(e){debugger},})

onTrack?和?onTrigger?僅在開發模式下生效。

類型定義

functionwatchEffect(effect:(onInvalidate:InvalidateCbRegistrator)=>void,options?:WatchEffectOptions):StopHandleinterfaceWatchEffectOptions{flush?:'pre'|'post'|'sync'onTrack?:(event:DebuggerEvent)=>voidonTrigger?:(event:DebuggerEvent)=>void}interfaceDebuggerEvent{effect:ReactiveEffect? target:anytype:OperationTypes? key:string|symbol|undefined}typeInvalidateCbRegistrator=(invalidate:()=>void)=>voidtypeStopHandle=()=>void

#watch

watch?API 完全等效于 2.x?this.$watch?(以及?watch?中相應的選項)。watch?需要偵聽特定的數據源,并在回調函數中執行副作用。默認情況是懶執行的,也就是說僅在偵聽的源變更時才執行回調。

對比?watchEffect,watch?允許我們:

懶執行副作用;

更明確哪些狀態的改變會觸發偵聽器重新運行副作用;

訪問偵聽狀態變化前后的值。

偵聽單個數據源

偵聽器的數據源可以是一個擁有返回值的 getter 函數,也可以是 ref:

// 偵聽一個 getterconststate=reactive({count:0})watch(()=>state.count,(count,prevCount)=>{/* ... */})// 直接偵聽一個 refconstcount=ref(0)watch(count,(count,prevCount)=>{/* ... */})

偵聽多個數據源

watcher?也可以使用數組來同時偵聽多個源:

watch([fooRef,barRef],([foo,bar],[prevFoo,prevBar])=>{/* ... */})

與?watchEffect?共享的行為

watch 和 watchEffect 在停止偵聽,?清除副作用?(相應地?onInvalidate?會作為回調的第三個參數傳入),副作用刷新時機?和?偵聽器調試?等方面行為一致.

類型定義

// 偵聽單數據源functionwatch<T>(source:WatcherSource<T>,callback:(value:T,oldValue:T,onInvalidate:InvalidateCbRegistrator)=>void,options?:WatchOptions):StopHandle// 偵聽多數據源functionwatch<TextendsWatcherSource<unknown>[]>(sources:Tcallback:(values:MapSources<T>,oldValues:MapSources<T>,onInvalidate:InvalidateCbRegistrator)=>void,options?:WatchOptions):StopHandletypeWatcherSource<T>=Ref<T>|(()=>T)typeMapSources<T>={[KinkeyofT]:T[K]extendsWatcherSource<inferV>?V:never}// 共有的屬性 請查看 `watchEffect` 的類型定義interfaceWatchOptionsextendsWatchEffectOptions{immediate?:boolean// default: falsedeep?:boolean}

#生命周期鉤子函數

可以直接導入?onXXX?一族的函數來注冊生命周期鉤子:

import{onMounted,onUpdated,onUnmounted}from'vue'constMyComponent={setup(){onMounted(()=>{console.log('mounted!')})onUpdated(()=>{console.log('updated!')})onUnmounted(()=>{console.log('unmounted!')})},}

這些生命周期鉤子注冊函數只能在?setup()?期間同步使用, 因為它們依賴于內部的全局狀態來定位當前組件實例(正在調用?setup()?的組件實例), 不在當前組件下調用這些函數會拋出一個錯誤。

組件實例上下文也是在生命周期鉤子同步執行期間設置的,因此,在卸載組件時,在生命周期鉤子內部同步創建的偵聽器和計算狀態也將自動刪除。

與 2.x 版本生命周期相對應的組合式 API

beforeCreate?-> 使用?setup()

created?-> 使用?setup()

beforeMount?->?onBeforeMount

mounted?->?onMounted

beforeUpdate?->?onBeforeUpdate

updated?->?onUpdated

beforeDestroy?->?onBeforeUnmount

destroyed?->?onUnmounted

errorCaptured?->?onErrorCaptured

新增的鉤子函數

除了和 2.x 生命周期等效項之外,組合式 API 還提供了以下調試鉤子函數:

onRenderTracked

onRenderTriggered

兩個鉤子函數都接收一個?DebuggerEvent,與?watchEffect?參數選項中的?onTrack?和?onTrigger?類似:

exportdefault{onRenderTriggered(e){debugger// 檢查哪個依賴性導致組件重新渲染},}

#依賴注入

provide?和?inject?提供依賴注入,功能類似 2.x 的?provide/inject。兩者都只能在當前活動組件實例的?setup()?中調用。

import{provide,inject}from'vue'constThemeSymbol=Symbol()constAncestor={setup(){provide(ThemeSymbol,'dark')},}constDescendent={setup(){consttheme=inject(ThemeSymbol,'light'/* optional default value */)return{theme,}},}

inject?接受一個可選的的默認值作為第二個參數。如果未提供默認值,并且在 provide 上下文中未找到該屬性,則?inject?返回?undefined。

注入的響應性

可以使用?ref?來保證?provided?和?injected?之間值的響應:

// 提供者:constthemeRef=ref('dark')provide(ThemeSymbol,themeRef)// 使用者:consttheme=inject(ThemeSymbol,ref('light'))watchEffect(()=>{console.log(`theme set to: ${theme.value}`)})

如果注入一個響應式對象,則它的狀態變化也可以被偵聽。

類型定義

interfaceInjectionKey<T>extendsSymbol{}functionprovide<T>(key:InjectionKey<T>|string,value:T):void// 未傳,使用缺省值functioninject<T>(key:InjectionKey<T>|string):T|undefined// 傳入了默認值functioninject<T>(key:InjectionKey<T>|string,defaultValue:T):T

Vue 提供了一個繼承?Symbol?的?InjectionKey?接口。它可用于在提供者和消費者之間同步注入值的類型:

import{InjectionKey,provide,inject}from'vue'constkey:InjectionKey<string>=Symbol()provide(key,'foo')// 類型不是 string 則會報錯constfoo=inject(key)// foo 的類型: string | undefined

如果使用字符串作為鍵或沒有定義類型的符號,則需要顯式聲明注入值的類型:

constfoo=inject<string>('foo')// string | undefined

#模板 Refs

當使用組合式 API 時,reactive refs?和?template refs?的概念已經是統一的。為了獲得對模板內元素或組件實例的引用,我們可以像往常一樣在?setup()?中聲明一個 ref 并返回它:

<template><divref="root"></div></template><script>import{ref,onMounted}from'vue'exportdefault{setup(){constroot=ref(null)onMounted(()=>{// 在渲染完成后, 這個 div DOM 會被賦值給 root ref 對象console.log(root.value)// <div/>})return{root,}},}</script>

這里我們將?root?暴露在渲染上下文中,并通過?ref="root"?綁定到?div?作為其?ref。 在 Virtual DOM patch 算法中,如果一個 VNode 的?ref?對應一個渲染上下文中的 ref,則該 VNode 對應的元素或組件實例將被分配給該 ref。 這是在 Virtual DOM 的 mount / patch 過程中執行的,因此模板 ref 僅在渲染初始化后才能訪問。

ref 被用在模板中時和其他 ref 一樣:都是響應式的,并可以傳遞進組合函數(或從其中返回)。

配合 render 函數 / JSX 的用法

exportdefault{setup(){constroot=ref(null)return()=>h('div',{ref:root,})// 使用 JSXreturn()=><div ref={root}/>},}

在?v-for?中使用

模板 ref 在?v-for?中使用 vue 沒有做特殊處理,需要使用函數型的 ref(3.0 提供的新功能)來自定義處理方式:

<template><divv-for="(item, i) in list":ref="el => { divs[i] = el }">{{ item }}</div></template><script>import{ref,reactive,onBeforeUpdate}from'vue'exportdefault{setup(){constlist=reactive([1,2,3])constdivs=ref([])// 確保在每次變更之前重置引用onBeforeUpdate(()=>{divs.value=[]})return{list,divs,}},}</script>

#響應式系統工具集

#unref

如果參數是一個 ref 則返回它的?value,否則返回參數本身。它是?val = isRef(val) ? val.value : val?的語法糖。

functionuseFoo(x:number|Ref<number>){constunwrapped=unref(x)// unwrapped 一定是 number 類型}

#toRef

toRef?可以用來為一個 reactive 對象的屬性創建一個 ref。這個 ref 可以被傳遞并且能夠保持響應性。

conststate=reactive({foo:1,bar:2,})constfooRef=toRef(state,'foo')fooRef.value++console.log(state.foo)// 2state.foo++console.log(fooRef.value)// 3

當您要將一個 prop 中的屬性作為 ref 傳給組合邏輯函數時,toRef?就派上了用場:

exportdefault{setup(props){useSomeFeature(toRef(props,'foo'))},}

#toRefs

把一個響應式對象轉換成普通對象,該普通對象的每個 property 都是一個 ref ,和響應式對象 property 一一對應。

conststate=reactive({foo:1,bar:2,})conststateAsRefs=toRefs(state)/*

stateAsRefs 的類型如下:

{

? foo: Ref<number>,

? bar: Ref<number>

}

*/// ref 對象 與 原屬性的引用是 "鏈接" 上的state.foo++console.log(stateAsRefs.foo.value)// 2stateAsRefs.foo.value++console.log(state.foo)// 3

當想要從一個組合邏輯函數中返回響應式對象時,用?toRefs?是很有效的,該 API 讓消費組件可以 解構 / 擴展(使用?...?操作符)返回的對象,并不會丟失響應性:

functionuseFeatureX(){conststate=reactive({foo:1,bar:2,})// 對 state 的邏輯操作// 返回時將屬性都轉為 refreturntoRefs(state)}exportdefault{setup(){// 可以解構,不會丟失響應性const{foo,bar}=useFeatureX()return{foo,bar,}},}

#isRef

檢查一個值是否為一個 ref 對象。

#isProxy

檢查一個對象是否是由?reactive?或者?readonly?方法創建的代理。

#isReactive

檢查一個對象是否是由?reactive?創建的響應式代理。

如果這個代理是由?readonly?創建的,但是又被?reactive?創建的另一個代理包裹了一層,那么同樣也會返回?true。

#isReadonly

檢查一個對象是否是由?readonly?創建的只讀代理。

#高級響應式系統 API

#customRef

customRef?用于自定義一個?ref,可以顯式地控制依賴追蹤和觸發響應,接受一個工廠函數,兩個參數分別是用于追蹤的?track?與用于觸發響應的?trigger,并返回一個帶有?get?和?set?屬性的對象。

使用自定義 ref 實現帶防抖功能的?v-model?:

<inputv-model="text"/>

functionuseDebouncedRef(value,delay=200){lettimeoutreturncustomRef((track,trigger)=>{return{get(){track()returnvalue},set(newValue){clearTimeout(timeout)timeout=setTimeout(()=>{value=newValuetrigger()},delay)},}})}exportdefault{setup(){return{text:useDebouncedRef('hello'),}},}

類型定義

functioncustomRef<T>(factory:CustomRefFactory<T>):Ref<T>typeCustomRefFactory<T>=(track:()=>void,trigger:()=>void)=>{get:()=>Tset:(value:T)=>void}

#markRaw

顯式標記一個對象為“永遠不會轉為響應式代理”,函數返回這個對象本身。

constfoo=markRaw({})console.log(isReactive(reactive(foo)))// false// 如果被 markRaw 標記了,即使在響應式對象中作屬性,也依然不是響應式的constbar=reactive({foo})console.log(isReactive(bar.foo))// false

注意

markRaw?和下面的 shallowXXX 一族的 API 允許你可選擇性的覆蓋 reactive readonly 默認 "深層的" 特性,或者使用無代理的普通對象。設計這種「淺層讀取」有很多原因,比如:

一些值的實際上的用法非常簡單,并沒有必要轉為響應式,比如某個復雜的第三方類庫的實例,或者 Vue 組件對象

當渲染一個元素數量龐大,但是數據是不可變的,跳過 Proxy 的轉換可以帶來性能提升。

這些 API 被認為是高級的,是因為這種特性僅停留在根級別,所以如果你將一個嵌套的,沒有?markRaw?的對象設置為 reactive 對象的屬性,在重新訪問時,你又會得到一個 Proxy 的版本,在使用中最終會導致標識混淆的嚴重問題:執行某個操作同時依賴于某個對象的原始版本和代理版本。

constfoo=markRaw({nested:{},})constbar=reactive({// 盡管 `foo` 己經被標記為 raw 了, 但 foo.nested 并沒有nested:foo.nested,})console.log(foo.nested===bar.nested)// false

標識混淆在一般使用當中應該是非常罕見的,但是要想完全避免這樣的問題,必須要對整個響應式系統的工作原理有一個相當清晰的認知。

#shallowReactive

只為某個對象的私有(第一層)屬性創建淺層的響應式代理,不會對“屬性的屬性”做深層次、遞歸地響應式代理,而只是保留原樣。

conststate=shallowReactive({foo:1,nested:{bar:2,},})// 變更 state 的自有屬性是響應式的state.foo++// ...但不會深層代理isReactive(state.nested)// falsestate.nested.bar++// 非響應式

#shallowReadonly

只為某個對象的自有(第一層)屬性創建淺層的只讀響應式代理,同樣也不會做深層次、遞歸地代理,深層次的屬性并不是只讀的。

conststate=shallowReadonly({foo:1,nested:{bar:2,},})// 變更 state 的自有屬性會失敗state.foo++// ...但是嵌套的對象是可以變更的isReadonly(state.nested)// falsestate.nested.bar++// 嵌套屬性依然可修改

#shallowRef

創建一個 ref ,將會追蹤它的?.value?更改操作,但是并不會對變更后的?.value?做響應式代理轉換(即變更不會調用?reactive)

constfoo=shallowRef({})// 更改對操作會觸發響應foo.value={}// 但上面新賦的這個對象并不會變為響應式對象isReactive(foo.value)// false

#toRaw

返回由?reactive?或?readonly?方法轉換成響應式代理的普通對象。這是一個還原方法,可用于臨時讀取,訪問不會被代理/跟蹤,寫入時也不會觸發更改。不建議一直持有原始對象的引用。請謹慎使用。

constfoo={}constreactiveFoo=reactive(foo)console.log(toRaw(reactiveFoo)===foo)// true

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,461評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,538評論 3 417
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,423評論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,991評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,761評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,207評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,268評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,419評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,959評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,782評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,222評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,653評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,901評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,678評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,978評論 2 374