vue 題目

作者:Vicky丶Amor
鏈接:http://www.reibang.com/p/b1564296a78b
來源:簡(jiǎn)書
著作權(quán)歸作者所有什湘。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處声怔。
嚴(yán)重抄襲 看作者的

說說 SPA 單頁面的理解,它的優(yōu)缺點(diǎn)分別是什么?

SPA( single page application ) 僅在頁面初始化時(shí)加載相應(yīng)的HTML JS 和 css, 一旦頁面加載完成, single page 不會(huì)因?yàn)橛脩舻牟僮鞫M(jìn)行頁面的重新加載或跳轉(zhuǎn);取而代之的時(shí)利用路由機(jī)制實(shí)現(xiàn)HTML內(nèi)容的變換,避免頁面的重新加載

優(yōu)點(diǎn)

用戶體驗(yàn)好,快,內(nèi)容的改變不需要加載整個(gè)頁面,避免了不必要的跳轉(zhuǎn)和重復(fù)渲染;
基于上面一點(diǎn)舱呻,SPA 相對(duì)對(duì)服務(wù)器壓力写谆稹;
前后端職責(zé)分離箱吕,架構(gòu)清晰芥驳,前端進(jìn)行交互邏輯,后端負(fù)責(zé)數(shù)據(jù)處理茬高;

缺點(diǎn)

初次加載耗時(shí)多:為實(shí)現(xiàn)單頁 Web 應(yīng)用功能及顯示效果兆旬,需要在加載頁面的時(shí)候?qū)?JavaScript、CSS 統(tǒng)一加載怎栽,部分頁面按需加載丽猬;
前進(jìn)后退路由管理 由于單頁應(yīng)用在一個(gè)頁面中顯示所有的內(nèi)容,所以不能使用瀏覽器的前進(jìn)后退功能脚祟,所有的頁面切換需要自己建立堆棧管理谬以;
SEO 難度較大:由于所有的內(nèi)容都在一個(gè)頁面中動(dòng)態(tài)替換顯示沥寥,所以在 SEO 上其有著天然的弱勢(shì)妈经。

v-show 與 v-if 有什么區(qū)別

v-if 是動(dòng)態(tài)的向dom 樹內(nèi)添加或者刪除dom元素,
編譯過程: v-if 是真正的條件渲染,因?yàn)樗鼤?huì)確保在切換過程中條件快內(nèi)的事件監(jiān)聽器和子組件 合適地銷毀和重建內(nèi)容, 也是 惰性的, 如果在初始化渲染時(shí)條件為假,則什么也不做,直到條件第一次變?yōu)檎鏁r(shí),才會(huì)開始渲染條件快

v-show 不管初始化條件是什么元素總是會(huì)被渲染,并且只是簡(jiǎn)單的基于css的 display 屬性進(jìn)行切換

所以v-if適用于運(yùn)行時(shí)很少改變條件,不需要頻繁切換條件的場(chǎng)景, v-show 適用于頻繁切換條件的場(chǎng)景

Class 與 Style 如何動(dòng)態(tài)綁定?

Class 可以通過對(duì)象語法和數(shù)組語法進(jìn)行動(dòng)態(tài)綁定:

<div v-bind:class="{ active: isActive, 'text-danger': hasError }"></div>

data: {
  isActive: true,
  hasError: false
}

數(shù)組語法:

<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>

data: {
  activeClass: 'active',
  errorClass: 'text-danger'
}

Style 也可以通過對(duì)象語法和數(shù)組語法進(jìn)行動(dòng)態(tài)綁定:

對(duì)象語法:

<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>

data: {
  activeColor: 'red',
  fontSize: 30
}

數(shù)組語法:

<div v-bind:style="[styleColor, styleSize]"></div>

data: {
  styleColor: {
     color: 'red'
   },
  styleSize:{
     fontSize:'23px'
  }
}

理解Vue 的單向數(shù)據(jù)流?

所以的prop 其父子prop之間形成了一個(gè)單向下行綁定 父級(jí)prop的更新會(huì)向下流動(dòng)到子組件中,但是反過來則不行,這樣防止從子組件意外改變父級(jí)組件的狀態(tài),從而導(dǎo)致你應(yīng)用的 數(shù)據(jù)流向 難以理解

每次父級(jí)組件發(fā)生更新時(shí)吹泡,子組件中所有的 prop 都將會(huì)刷新為最新的值骤星。這意味著你不應(yīng)該在一個(gè)子組件內(nèi)部改變 prop。如果你這樣做了爆哑,Vue 會(huì)在瀏覽器的控制臺(tái)中發(fā)出警告洞难。子組件想修改時(shí),只能通過 $emit 派發(fā)一個(gè)自定義事件揭朝,父組件接收到后队贱,由父組件修改

有兩種常見試圖改變一個(gè)prop的情形:

這個(gè) prop 用來傳遞一個(gè)初始值;這個(gè)子組件接下來希望將其作為一個(gè)本地的 prop 數(shù)據(jù)來使用潭袱。 在這種情況下柱嫌,最好定義一個(gè)本地的 data 屬性并將這個(gè) prop 用作其初始值:

props: {
    msg: String
  },
data () {
  return {
    emit: this.msg
  }
}
mounted () {
    this.emit += '33333333333'
  }

這個(gè) prop 以一種原始的值傳入且需要進(jìn)行轉(zhuǎn)換。 在這種情況下屯换,最好使用這個(gè) prop 的值來定義一個(gè)計(jì)算屬性

props: ['size'],
computed: {
  normalizedSize: function () {
    return this.size.trim().toLowerCase()
  }
}

computed和watch的區(qū)別和運(yùn)用的場(chǎng)景?

computed: 是計(jì)算屬性,依賴其他屬性值,并且computed的值有緩存,只有它依賴的屬性值發(fā)生改變,下一次獲取computed的值時(shí)才會(huì)重新計(jì)算computed的值;

watch: 更多的是 [觀察]的作用,類似于某些數(shù)據(jù)的監(jiān)聽回調(diào),每當(dāng)監(jiān)聽的數(shù)據(jù)變化是都會(huì)執(zhí)行回調(diào)進(jìn)行后續(xù)的操作:

運(yùn)用場(chǎng)景:

1.當(dāng)我們需要進(jìn)行數(shù)值計(jì)算,并且依賴與其他數(shù)據(jù)時(shí),應(yīng)該使用computed,因?yàn)榭梢岳胏omputed的緩存特性,避免每次獲取值時(shí),都要重新計(jì)算

2.當(dāng)我們需要在數(shù)據(jù)變化時(shí)執(zhí)行異步或開銷較大的操作時(shí),應(yīng)該使用watch, 使用watch選項(xiàng)允許我們執(zhí)行異步操作 限制我們執(zhí)行該操作的頻率编丘,并在我們得到最終結(jié)果前,設(shè)置中間狀態(tài)彤悔。這些都是計(jì)算屬性無法做到的

直接給一個(gè)數(shù)組項(xiàng)賦值嘉抓,Vue 能檢測(cè)到變化嗎?

由于 JavaScript 的限制晕窑,Vue 不能檢測(cè)到以下數(shù)組的變動(dòng):

當(dāng)你利用索引直接設(shè)置一個(gè)數(shù)組項(xiàng)時(shí)掌眠,例如:vm.items[indexOfItem] = newValue
當(dāng)你修改數(shù)組的長(zhǎng)度時(shí),例如:vm.items.length = newLength
為了解決第一個(gè)問題幕屹,Vue 提供了以下操作方法:

// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
// vm.$set蓝丙,Vue.set的一個(gè)別名
vm.$set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)

為了解決第二個(gè)問題级遭,Vue 提供了以下操作方法:

vm.items.splice(newLength)

vue 的父組件和子組件生命周期鉤子函數(shù)執(zhí)行順序?

image.png
image.png

beforeCreate 組件實(shí)例剛被創(chuàng)建 組件計(jì)算之前,, data 屬性等
created 組件實(shí)例創(chuàng)建完成 屬性已經(jīng)綁定 但DOM還未生成 $el 屬性還不存在
beforeMount 模板編輯/掛載之前
mounted 模板編譯掛載之后

beforeUpdate 組件更新之前
updated 組件更新之后
activated for keep-alive 組件被激活時(shí)調(diào)用
deactivated for keep-alive 組件被移除時(shí)調(diào)用
beforeDestroy 組件銷毀前調(diào)用
destroyed 組件銷毀時(shí)調(diào)用

create 和 mounted 相關(guān)

beforeCreated : el 和 data 并未初始化
created 完成了 data 數(shù)據(jù)的初始化 el 沒有
beforeMount 完成了el 和data 初始化
mounted 完成掛載
另外在標(biāo)紅處,我們能發(fā)現(xiàn)el還是 {{message}}渺尘,這里就是應(yīng)用的 Virtual DOM(虛擬Dom)技術(shù)挫鸽,先把坑占住了。到后面mounted掛載的時(shí)候再把值渲染進(jìn)去鸥跟。

image.png
beforeUpdate 和update相關(guān)

這里我們?cè)?chrome console里執(zhí)行以下命令

app.message= 'yes !! I do';

下面就能看到data里的值被修改后丢郊,將會(huì)觸發(fā)update的操作

image.png
destroy 相關(guān)
app.$destroy();

對(duì)組件實(shí)例進(jìn)行銷毀,,當(dāng)前組件已被刪除,但頁面內(nèi)容還在,但不能做后續(xù)對(duì)他的任何操作,,,keep-alive 可以緩存 組件

異步請(qǐng)求

可以在鉤子函數(shù) created beforeMount mounted 中調(diào)用,因?yàn)樵谶@三個(gè)鉤子函數(shù)中,data已經(jīng)創(chuàng)建好了,在created鉤子函數(shù)中調(diào)用異步請(qǐng)求優(yōu)點(diǎn):
1.能夠快速獲取服務(wù)端數(shù)據(jù),減少頁面loading時(shí)間
2.ssr 不支持 beforeMount 、mounted 鉤子函數(shù)医咨,所以放在 created 中有助于一致性枫匾;

父組件可以監(jiān)聽子組件的生命周期嗎?

比如有父組件 Parent 和子組件 Child,如果父組件監(jiān)聽到子組件掛載 mounted 就做一些邏輯處理拟淮,可以通過以下寫法實(shí)現(xiàn):

// Parent.vue
<Child @mounted="doSomething"/>

// Child.vue
mounted() {
  this.$emit("mounted");
}

以上需要手動(dòng)通過 $emit 觸發(fā)父組件的事件干茉,更簡(jiǎn)單的方式可以在父組件引用子組件時(shí)通過@hook來監(jiān)聽即可,如下所示:

// 父組件 
<template>
    <HelloWorld msg="Welcome to Your Vue.js App" @hook:mounted="something"/>
</template>
export default {
  name: 'home',
  methods: {
    something () {
      console.log('parent')
    }
  },
  components: {
    HelloWorld
  }
}

// 子組件
export default {
  name: 'HelloWorld',
  mounted () {
    console.log('child')
  }
}
打印結(jié)果 先 child   ---- > 后 parent

當(dāng)然 @hook 方法不僅僅時(shí)可以監(jiān)聽mounted,其他的生命周期事件, 例如: created update 等 都可以監(jiān)聽

談?wù)?keep-alive的了解

keep-alive 是vue內(nèi)置的一個(gè)組件,可以使被包含的組件保留狀態(tài),避免重新渲染

  1. 一般結(jié)合路由和動(dòng)態(tài)組件一起使用,用于緩存組件
    2.提供include 和 exclude 屬性,兩者都支持字符串和正側(cè)表達(dá)式,include表示只有名稱匹配的組件會(huì)被緩存,exclude表示任何名稱匹配的組件都不會(huì)被緩存,其中exclude的優(yōu)先級(jí)比include高
    3.對(duì)應(yīng)兩個(gè)鉤子函數(shù),activated 和 deactivated,當(dāng)組件被激活時(shí),觸發(fā)鉤子函數(shù),activated,當(dāng)組件被移除時(shí),觸發(fā)鉤子函數(shù)deactivated

組件中的data為什么是一個(gè)函數(shù)

未什么組件中的data必須是一個(gè)函數(shù),然后return一個(gè)對(duì)象,而new Vue實(shí)例里,data可以直接是一個(gè)對(duì)象?

因?yàn)榻M件是用來復(fù)用的,且js里對(duì)象是引用關(guān)系,如果組件中data是一個(gè)對(duì)象,這樣作用域沒有隔離,子組件中的data屬性值會(huì)互相影響,如果組件中data選項(xiàng)是一個(gè)函數(shù),那么每個(gè)實(shí)例可以維護(hù)一份被返回對(duì)象的獨(dú)立拷貝,組件實(shí)例之間的data屬性值不會(huì)互相影響,而new Vue的實(shí)例 是不會(huì)被復(fù)用的,因此不存在引用對(duì)象的問題

Vue組件間通信有哪幾種方式?

props / $emit 適用父子組件通信
ref 與$parent / $children

ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素很泊;如果用在子組件上角虫,引用就指向組件實(shí)例
$parent/$children 訪問父/子實(shí)例

$emit / $on 適用與父子 隔代,兄弟組件通信

這種方法通過一個(gè)空的vue實(shí)例作為中央事件總線(事件中心),用它來觸發(fā)事件和監(jiān)聽事件,從而實(shí)現(xiàn)任何組件的通信,包括父子,隔代,兄弟組件

$attrs / $listeners 適用與隔代組件通信

$attrs包含了父作用域中不被 prop 所識(shí)別 (且獲取) 的特性綁定 ( class 和 style 除外 )。當(dāng)一個(gè)組件沒有聲明任何 prop 時(shí)委造,這里會(huì)包含所有父作用域的綁定 ( class 和 style 除外 )戳鹅,并且可以通過 v-bind="$attrs" 傳入內(nèi)部組件。通常配合 inheritAttrs 選項(xiàng)一起使用昏兆。
$listeners: 包含了父作用域中的 (不含 .native 修飾器的) v-on 事件監(jiān)聽器枫虏。它可以通過 v-on="$listeners" 傳入內(nèi)部組件

provide / inject 適用于隔代組件通信

祖先組件中通過 provider 來提供變量,然后在子孫組件中通過 inject 來注入變量爬虱。 provide / inject API 主要解決了跨級(jí)組件間的通信問題模软,不過它的使用場(chǎng)景,主要是子組件獲取上級(jí)組件的狀態(tài)饮潦,跨級(jí)組件間建立了一種主動(dòng)提供與依賴注入的關(guān)系燃异。

Vuex 適用于 父子、隔代继蜡、兄弟組件通信

你使用過Vuex嗎

Vuex 是一個(gè)專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式回俐。每一個(gè) Vuex 應(yīng)用的核心就是 store(倉庫)∠〔ⅲ“store” 基本上就是一個(gè)容器仅颇,它包含著你的應(yīng)用中大部分的狀態(tài) ( state )。
(1)Vuex 的狀態(tài)存儲(chǔ)是響應(yīng)式的碘举。當(dāng) Vue 組件從 store 中讀取狀態(tài)的時(shí)候忘瓦,若 store 中的狀態(tài)發(fā)生變化,那么相應(yīng)的組件也會(huì)相應(yīng)地得到高效更新引颈。

(2)改變 store 中的狀態(tài)的唯一途徑就是顯式地提交 (commit) mutation耕皮。這樣使得我們可以方便地跟蹤每一個(gè)狀態(tài)的變化境蜕。
主要包括以下幾個(gè)模塊:
State:定義了應(yīng)用狀態(tài)的數(shù)據(jù)結(jié)構(gòu),可以在這里設(shè)置默認(rèn)的初始狀態(tài)凌停。
Getter:允許組件從 Store 中獲取數(shù)據(jù)粱年,mapGetters 輔助函數(shù)僅僅是將 store 中的 getter 映射到局部計(jì)算屬性。
Mutation:是唯一更改 store 中狀態(tài)的方法罚拟,且必須是同步函數(shù)台诗。
Action:用于提交 mutation,而不是直接變更狀態(tài)赐俗,可以包含任意異步操作拉队。
Module:允許將單一的 Store 拆分為多個(gè) store 且同時(shí)保存在單一的狀態(tài)樹中。

使用過 Vue SSR 嗎阻逮?說說 SSR粱快?

Vue.js 是構(gòu)建客戶端應(yīng)用程序的框架。默認(rèn)情況下夺鲜,可以在瀏覽器中輸出 Vue 組件皆尔,進(jìn)行生成 DOM 和操作 DOM呐舔。然而币励,也可以將同一個(gè)組件渲染為服務(wù)端的 HTML 字符串,將它們直接發(fā)送到瀏覽器珊拼,最后將這些靜態(tài)標(biāo)記"激活"為客戶端上完全可交互的應(yīng)用程序食呻。

即:SSR大致的意思就是vue在客戶端將標(biāo)簽渲染成的整個(gè) html 片段的工作在服務(wù)端完成,服務(wù)端形成的html 片段直接返回給客戶端這個(gè)過程就叫做服務(wù)端渲染澎现。

(1)服務(wù)端渲染的優(yōu)點(diǎn):

更好的 SEO: 因?yàn)?SPA 頁面的內(nèi)容是通過 Ajax 獲取仅胞,而搜索引擎爬取工具并不會(huì)等待 Ajax 異步完成后再抓取頁面內(nèi)容,所以在 SPA 中是抓取不到頁面通過 Ajax 獲取到的內(nèi)容剑辫;而 SSR 是直接由服務(wù)端返回已經(jīng)渲染好的頁面(數(shù)據(jù)已經(jīng)包含在頁面中)干旧,所以搜索引擎爬取工具可以抓取渲染好的頁面;
更快的內(nèi)容到達(dá)時(shí)間(首屏加載更快): SPA 會(huì)等待所有 Vue 編譯后的 js 文件都下載完成后妹蔽,才開始進(jìn)行頁面的渲染椎眯,文件下載等需要一定的時(shí)間等,所以首屏渲染需要一定的時(shí)間胳岂;SSR 直接由服務(wù)端渲染好頁面直接返回顯示编整,無需等待下載 js 文件及再去渲染等,所以 SSR 有更快的內(nèi)容到達(dá)時(shí)間乳丰;

(1)服務(wù)端渲染的缺點(diǎn):

更多的開發(fā)條件限制: 例如服務(wù)端渲染只支持 beforCreate 和 created 兩個(gè)鉤子函數(shù)掌测,這會(huì)導(dǎo)致一些外部擴(kuò)展庫需要特殊處理,才能在服務(wù)端渲染應(yīng)用程序中運(yùn)行产园;并且與可以部署在任何靜態(tài)文件服務(wù)器上的完全靜態(tài)單頁面應(yīng)用程序 SPA 不同汞斧,服務(wù)端渲染應(yīng)用程序夜郁,需要處于 Node.js server 運(yùn)行環(huán)境;
更多的服務(wù)器負(fù)載:在 Node.js 中渲染完整的應(yīng)用程序断箫,顯然會(huì)比僅僅提供靜態(tài)文件的 server 更加大量占用CPU 資源 (CPU-intensive - CPU 密集)拂酣,因此如果你預(yù)料在高流量環(huán)境 ( high traffic ) 下使用,請(qǐng)準(zhǔn)備相應(yīng)的服務(wù)器負(fù)載仲义,并明智地采用緩存策略婶熬。

如果沒有 SSR 開發(fā)經(jīng)驗(yàn)的同學(xué),可以參考本文作者的另一篇 SSR 的實(shí)踐文章《Vue SSR 踩坑之旅》埃撵,里面 SSR 項(xiàng)目搭建以及附有項(xiàng)目源碼赵颅。

vue-router 路由模式有幾種?

vue-router 有 3 種路由模式:hash暂刘、history饺谬、abstract,對(duì)應(yīng)的源碼如下所示:

switch (mode) {
  case 'history':
    this.history = new HTML5History(this, options.base)
    break
  case 'hash':
    this.history = new HashHistory(this, options.base, this.fallback)
    break
  case 'abstract':
    this.history = new AbstractHistory(this, options.base)
    break
  default:
    if (process.env.NODE_ENV !== 'production') {
      assert(false, `invalid mode: ${mode}`)
    }
}

hash: 使用 URL hash 值來作路由谣拣。支持所有瀏覽器募寨,包括不支持 HTML5 History Api 的瀏覽器;

history : 依賴 HTML5 History API 和服務(wù)器配置森缠。具體可以查看 HTML5 History 模式拔鹰;

abstract : 支持所有 JavaScript 運(yùn)行環(huán)境,如 Node.js 服務(wù)器端贵涵。如果發(fā)現(xiàn)沒有瀏覽器的 API列肢,路由會(huì)自動(dòng)強(qiáng)制進(jìn)入這個(gè)模式.

能說下 vue-router 中常用的 hash 和 history 路由模式實(shí)現(xiàn)原理嗎?

hash 模式的實(shí)現(xiàn)原理

早期的前端路由的實(shí)現(xiàn)就是基于 location.hash 來實(shí)現(xiàn)的宾茂。其實(shí)現(xiàn)原理很簡(jiǎn)單瓷马,location.hash 的值就是 URL 中 # 后面的內(nèi)容。比如下面這個(gè)網(wǎng)站跨晴,它的 location.hash 的值為 '#search':

https://www.word.com#search

hash 路由模式的實(shí)現(xiàn)主要是基于下面幾個(gè)特性:

  • URL 中 hash 值只是客戶端的一種狀態(tài)欧聘,也就是說當(dāng)向服務(wù)器端發(fā)出請(qǐng)求時(shí),hash 部分不會(huì)被發(fā)送端盆;
  • hash 值的改變怀骤,都會(huì)在瀏覽器的訪問歷史中增加一個(gè)記錄。因此我們能通過瀏覽器的回退爱谁、前進(jìn)按鈕控制hash 的切換晒喷;
  • 可以通過 a 標(biāo)簽,并設(shè)置 href 屬性访敌,當(dāng)用戶點(diǎn)擊這個(gè)標(biāo)簽后凉敲,URL 的 hash 值會(huì)發(fā)生改變;或者使用 JavaScript 來對(duì) loaction.hash 進(jìn)行賦值,改變 URL 的 hash 值爷抓;
  • 我們可以使用 hashchange 事件來監(jiān)聽 hash 值的變化势决,從而對(duì)頁面進(jìn)行跳轉(zhuǎn)(渲染)。
(2)history 模式的實(shí)現(xiàn)原理

HTML5 提供了 History API 來實(shí)現(xiàn) URL 的變化蓝撇。其中做最主要的 API 有以下兩個(gè):history.pushState() 和 history.repalceState()果复。這兩個(gè) API 可以在不進(jìn)行刷新的情況下,操作瀏覽器的歷史紀(jì)錄渤昌。唯一不同的是虽抄,前者是新增一個(gè)歷史記錄,后者是直接替換當(dāng)前的歷史記錄独柑,如下所示:

window.history.pushState(null, null, path);
window.history.replaceState(null, null, path);

history 路由模式的實(shí)現(xiàn)主要基于存在下面幾個(gè)特性:

  • pushState 和 repalceState 兩個(gè) API 來操作實(shí)現(xiàn) URL 的變化 迈窟;
  • 我們可以使用 popstate 事件來監(jiān)聽 url 的變化,從而對(duì)頁面進(jìn)行跳轉(zhuǎn)(渲染)忌栅;
  • history.pushState() 或 history.replaceState() 不會(huì)觸發(fā) popstate 事件车酣,這時(shí)我們需要手動(dòng)觸發(fā)頁面跳轉(zhuǎn)(渲染)。

什么是 MVVM索绪?

Model–View–ViewModel (MVVM) 是一個(gè)軟件架構(gòu)設(shè)計(jì)模式湖员,由微軟 WPF 和 Silverlight 的架構(gòu)師 Ken Cooper 和 Ted Peters 開發(fā),是一種簡(jiǎn)化用戶界面的事件驅(qū)動(dòng)編程方式瑞驱。由 John Gossman(同樣也是 WPF 和 Silverlight 的架構(gòu)師)于2005年在他的博客上發(fā)表

MVVM 源自于經(jīng)典的 Model–View–Controller(MVC)模式 娘摔,MVVM 的出現(xiàn)促進(jìn)了前端開發(fā)與后端業(yè)務(wù)邏輯的分離,極大地提高了前端開發(fā)效率钱烟,MVVM 的核心是 ViewModel 層晰筛,它就像是一個(gè)中轉(zhuǎn)站(value converter)嫡丙,負(fù)責(zé)轉(zhuǎn)換 Model 中的數(shù)據(jù)對(duì)象來讓數(shù)據(jù)變得更容易管理和使用拴袭,該層向上與視圖層進(jìn)行雙向數(shù)據(jù)綁定,向下與 Model 層通過接口請(qǐng)求進(jìn)行數(shù)據(jù)交互曙博,起呈上啟下作用拥刻。如下圖所示:

image.png

(1)View 層

View 是視圖層,也就是用戶界面父泳。前端主要由 HTML 和 CSS 來構(gòu)建 般哼。

(2)Model 層

Model 是指數(shù)據(jù)模型,泛指后端進(jìn)行的各種業(yè)務(wù)邏輯處理和數(shù)據(jù)操控惠窄,對(duì)于前端來說就是后端提供的 api 接口蒸眠。

(3)ViewModel 層

ViewModel 是由前端開發(fā)人員組織生成和維護(hù)的視圖數(shù)據(jù)層。在這一層杆融,前端開發(fā)者對(duì)從后端獲取的 Model 數(shù)據(jù)進(jìn)行轉(zhuǎn)換處理楞卡,做二次封裝,以生成符合 View 層使用預(yù)期的視圖數(shù)據(jù)模型。需要注意的是 ViewModel 所封裝出來的數(shù)據(jù)模型包括視圖的狀態(tài)和行為兩部分蒋腮,而 Model 層的數(shù)據(jù)模型是只包含狀態(tài)的淘捡,比如頁面的這一塊展示什么,而頁面加載進(jìn)來時(shí)發(fā)生什么池摧,點(diǎn)擊這一塊發(fā)生什么焦除,這一塊滾動(dòng)時(shí)發(fā)生什么這些都屬于視圖行為(交互),視圖狀態(tài)和行為都封裝在了 ViewModel 里作彤。這樣的封裝使得 ViewModel 可以完整地去描述 View 層膘魄。

MVVM 框架實(shí)現(xiàn)了雙向綁定,這樣 ViewModel 的內(nèi)容會(huì)實(shí)時(shí)展現(xiàn)在 View 層竭讳,前端開發(fā)者再也不必低效又麻煩地通過操縱 DOM 去更新視圖瓣距,MVVM 框架已經(jīng)把最臟最累的一塊做好了,我們開發(fā)者只需要處理和維護(hù) ViewModel代咸,更新數(shù)據(jù)視圖就會(huì)自動(dòng)得到相應(yīng)更新蹈丸。這樣 View 層展現(xiàn)的不是 Model 層的數(shù)據(jù),而是 ViewModel 的數(shù)據(jù)呐芥,由 ViewModel 負(fù)責(zé)與 Model 層交互逻杖,這就完全解耦了 View 層和 Model 層,這個(gè)解耦是至關(guān)重要的思瘟,它是前后端分離方案實(shí)施的重要一環(huán)荸百。

我們以下通過一個(gè) Vue 實(shí)例來說明 MVVM 的具體實(shí)現(xiàn),有 Vue 開發(fā)經(jīng)驗(yàn)的同學(xué)應(yīng)該一目了然:

(1)View 層

<div id="app">
    <p>{{message}}</p>
    <button v-on:click="showMessage()">Click me</button>
</div>

2)ViewModel 層

var app = new Vue({
    el: '#app',
    data: {  // 用于描述視圖狀態(tài)   
        message: 'Hello Vue!', 
    },
    methods: {  // 用于描述視圖行為  
        showMessage(){
            let vm = this;
            alert(vm.message);
        }
    },
    created(){
        let vm = this;
        // Ajax 獲取 Model 層的數(shù)據(jù)
        ajax({
            url: '/your/server/data/api',
            success(res){
                vm.message = res;
            }
        });
    }
})

(3) Model 層

{
    "url": "/your/server/data/api",
    "res": {
        "success": true,
        "name": "IoveC",
        "domain": "www.cnblogs.com"
    }
}

Vue 是如何實(shí)現(xiàn)數(shù)據(jù)雙向綁定的滨攻?

Vue 數(shù)據(jù)雙向綁定主要是指:數(shù)據(jù)變化更新視圖够话,視圖變化更新數(shù)據(jù),如下圖所示:

image.png
  • 輸入框內(nèi)容變化時(shí)光绕,Data 中的數(shù)據(jù)同步變化女嘲。即 View => Data 的變化。
  • Data 中的數(shù)據(jù)變化時(shí)诞帐,文本節(jié)點(diǎn)的內(nèi)容同步變化欣尼。即 Data => View 的變化。

其中停蕉,View 變化更新 Data 愕鼓,可以通過事件監(jiān)聽的方式來實(shí)現(xiàn),所以 Vue 的數(shù)據(jù)雙向綁定的工作主要是如何根據(jù) Data 變化更新 View慧起。

Vue 主要通過以下 4 個(gè)步驟來實(shí)現(xiàn)數(shù)據(jù)雙向綁定的:
實(shí)現(xiàn)一個(gè)監(jiān)聽器 Observer:對(duì)數(shù)據(jù)對(duì)象進(jìn)行遍歷菇晃,包括子屬性對(duì)象的屬性,利用 Object.defineProperty() 對(duì)屬性都加上 setter 和 getter蚓挤。這樣的話磺送,給這個(gè)對(duì)象的某個(gè)值賦值剩失,就會(huì)觸發(fā) setter,那么就能監(jiān)聽到了數(shù)據(jù)變化册着。

實(shí)現(xiàn)一個(gè)解析器 Compile:解析 Vue 模板指令拴孤,將模板中的變量都替換成數(shù)據(jù),然后初始化渲染頁面視圖甲捏,并將每個(gè)指令對(duì)應(yīng)的節(jié)點(diǎn)綁定更新函數(shù)演熟,添加監(jiān)聽數(shù)據(jù)的訂閱者,一旦數(shù)據(jù)有變動(dòng)司顿,收到通知芒粹,調(diào)用更新函數(shù)進(jìn)行數(shù)據(jù)更新。

實(shí)現(xiàn)一個(gè)訂閱者 Watcher:Watcher 訂閱者是 Observer 和 Compile 之間通信的橋梁 大溜,主要的任務(wù)是訂閱 Observer 中的屬性值變化的消息啦撮,當(dāng)收到屬性值變化的消息時(shí)伤溉,觸發(fā)解析器 Compile 中對(duì)應(yīng)的更新函數(shù)。

實(shí)現(xiàn)一個(gè)訂閱器 Dep:訂閱器采用 發(fā)布-訂閱 設(shè)計(jì)模式,用來收集訂閱者 Watcher层坠,對(duì)監(jiān)聽器 Observer 和 訂閱者 Watcher 進(jìn)行統(tǒng)一管理夜矗。
以上四個(gè)步驟的流程圖表示如下妆偏,如果有同學(xué)理解不大清晰的我磁,可以查看作者專門介紹數(shù)據(jù)雙向綁定的文章《0 到 1 掌握:Vue 核心之?dāng)?shù)據(jù)雙向綁定》,有進(jìn)行詳細(xì)的講解厌衔、以及代碼 demo 示例璧帝。

image.png

Vue 框架怎么實(shí)現(xiàn)對(duì)象和數(shù)組的監(jiān)聽?

如果被問到 Vue 怎么實(shí)現(xiàn)數(shù)據(jù)雙向綁定富寿,大家肯定都會(huì)回答 通過 Object.defineProperty() 對(duì)數(shù)據(jù)進(jìn)行劫持睬隶,但是 Object.defineProperty() 只能對(duì)屬性進(jìn)行數(shù)據(jù)劫持,不能對(duì)整個(gè)對(duì)象進(jìn)行劫持页徐,同理無法對(duì)數(shù)組進(jìn)行劫持苏潜,但是我們?cè)谑褂?Vue 框架中都知道,Vue 能檢測(cè)到對(duì)象和數(shù)組(部分方法的操作)的變化泞坦,那它是怎么實(shí)現(xiàn)的呢窖贤?我們查看相關(guān)代碼如下:

  /**
   * Observe a list of Array items.
   */
  observeArray (items: Array<any>) {
    for (let i = 0, l = items.length; i < l; i++) {
      observe(items[i])  // observe 功能為監(jiān)測(cè)數(shù)據(jù)的變化
    }
  }

  /**
   * 對(duì)屬性進(jìn)行遞歸遍歷
   */
  let childOb = !shallow && observe(val) // observe 功能為監(jiān)測(cè)數(shù)據(jù)的變化

通過以上 Vue 源碼部分查看砖顷,我們就能知道 Vue 框架是通過遍歷數(shù)組 和遞歸遍歷對(duì)象贰锁,從而達(dá)到利用 Object.defineProperty() 也能對(duì)對(duì)象和數(shù)組(部分方法的操作)進(jìn)行監(jiān)聽。

Proxy 與 Object.defineProperty 優(yōu)劣對(duì)比

Proxy 的優(yōu)勢(shì)如下:
  • Proxy 可以直接監(jiān)聽對(duì)象而非屬性滤蝠;
  • Proxy 可以直接監(jiān)聽數(shù)組的變化豌熄;
  • Proxy 有多達(dá) 13 種攔截方法,不限于 apply、ownKeys物咳、deleteProperty锣险、has 等等是 Object.defineProperty 不具備的;
  • Proxy 返回的是一個(gè)新對(duì)象,我們可以只操作新的對(duì)象達(dá)到目的,而 - Object.defineProperty 只能遍歷對(duì)象屬性直接修改;
  • Proxy 作為新標(biāo)準(zhǔn)將受到瀏覽器廠商重點(diǎn)持續(xù)的性能優(yōu)化芯肤,也就是傳說中的新標(biāo)準(zhǔn)的性能紅利巷折;
Object.defineProperty 的優(yōu)勢(shì)如下:
  • 兼容性好,支持 IE9崖咨,而 Proxy 的存在瀏覽器兼容性問題,而且無法用 polyfill 磨平锻拘,因此 Vue 的作者才聲明需要等到下個(gè)大版本( 3.0 )才能用 Proxy 重寫。

Vue 怎么用 vm.$set() 解決對(duì)象新增屬性不能響應(yīng)的問題 击蹲?

受現(xiàn)代 JavaScript 的限制 署拟,Vue 無法檢測(cè)到對(duì)象屬性的添加或刪除。由于 Vue 會(huì)在初始化實(shí)例時(shí)對(duì)屬性執(zhí)行 getter/setter 轉(zhuǎn)化歌豺,所以屬性必須在 data 對(duì)象上存在才能讓 Vue 將它轉(zhuǎn)換為響應(yīng)式的推穷。但是 Vue 提供了 Vue.set (object, propertyName, value) / vm.$set (object, propertyName, value) 來實(shí)現(xiàn)為對(duì)象添加響應(yīng)式屬性,那框架本身是如何實(shí)現(xiàn)的呢类咧?

我們查看對(duì)應(yīng)的 Vue 源碼:vue/src/core/instance/index.js

export function set (target: Array<any> | Object, key: any, val: any): any {
  // target 為數(shù)組  
  if (Array.isArray(target) && isValidArrayIndex(key)) {
    // 修改數(shù)組的長(zhǎng)度, 避免索引>數(shù)組長(zhǎng)度導(dǎo)致splcie()執(zhí)行有誤
    target.length = Math.max(target.length, key)
    // 利用數(shù)組的splice變異方法觸發(fā)響應(yīng)式  
    target.splice(key, 1, val)
    return val
  }
  // key 已經(jīng)存在馒铃,直接修改屬性值  
  if (key in target && !(key in Object.prototype)) {
    target[key] = val
    return val
  }
  const ob = (target: any).__ob__
  // target 本身就不是響應(yīng)式數(shù)據(jù), 直接賦值
  if (!ob) {
    target[key] = val
    return val
  }
  // 對(duì)屬性進(jìn)行響應(yīng)式處理
  defineReactive(ob.value, key, val)
  ob.dep.notify()
  return val
}

我們閱讀以上源碼可知,vm.$set 的實(shí)現(xiàn)原理是:

  • 如果目標(biāo)是數(shù)組痕惋,直接使用數(shù)組的 splice 方法觸發(fā)相應(yīng)式骗露;

  • 如果目標(biāo)是對(duì)象,會(huì)先判讀屬性是否存在血巍、對(duì)象是否是響應(yīng)式萧锉,最終如果要對(duì)屬性進(jìn)行響應(yīng)式處理,則是通過調(diào)用 defineReactive 方法進(jìn)行響應(yīng)式處理( defineReactive 方法就是 Vue 在初始化對(duì)象時(shí)述寡,給對(duì)象屬性采用 Object.defineProperty 動(dòng)態(tài)添加 getter 和 setter 的功能所調(diào)用的方法)

虛擬 DOM 的優(yōu)缺點(diǎn)柿隙?

優(yōu)點(diǎn):

  • 保證性能下限: 框架的虛擬 DOM 需要適配任何上層 API 可能產(chǎn)生的操作,它的一些 DOM 操作的實(shí)現(xiàn)必須是普適的鲫凶,所以它的性能并不是最優(yōu)的禀崖;但是比起粗暴的 DOM 操作性能要好很多,因此框架的虛擬 DOM 至少可以保證在你不需要手動(dòng)優(yōu)化的情況下螟炫,依然可以提供還不錯(cuò)的性能波附,即保證性能的下限;
  • 無需手動(dòng)操作 DOM: 我們不再需要手動(dòng)去操作 DOM昼钻,只需要寫好 View-Model 的代碼邏輯掸屡,框架會(huì)根據(jù)虛擬 DOM 和 數(shù)據(jù)雙向綁定,幫我們以可預(yù)期的方式更新視圖然评,極大提高我們的開發(fā)效率仅财;
  • 跨平臺(tái): 虛擬 DOM 本質(zhì)上是 JavaScript 對(duì)象,而 DOM 與平臺(tái)強(qiáng)相關(guān),相比之下虛擬 DOM 可以進(jìn)行更方便地跨平臺(tái)操作碗淌,例如服務(wù)器渲染盏求、weex 開發(fā)等等抖锥。
    缺點(diǎn):
  • 無法進(jìn)行極致優(yōu)化: 雖然虛擬 DOM + 合理的優(yōu)化,足以應(yīng)對(duì)絕大部分應(yīng)用的性能需求碎罚,但在一些性能要求極高的應(yīng)用中虛擬 DOM 無法進(jìn)行針對(duì)性的極致優(yōu)化磅废。

虛擬 DOM 實(shí)現(xiàn)原理?

虛擬 DOM 的實(shí)現(xiàn)原理主要包括以下 3 部分:

  • 用 JavaScript 對(duì)象模擬真實(shí) DOM 樹荆烈,對(duì)真實(shí) DOM 進(jìn)行抽象还蹲;
  • diff 算法 — 比較兩棵虛擬 DOM 樹的差異;
  • pach 算法 — 將兩個(gè)虛擬 DOM 對(duì)象的差異應(yīng)用到真正的 DOM 樹耙考。

如果對(duì)以上 3 個(gè)部分還不是很了解的同學(xué)谜喊,可以查看本文作者寫的另一篇詳解虛擬 DOM 的文章《深入剖析:Vue核心之虛擬DOM

Vue 中的 key 有什么作用?

<meta charset="utf-8">

key 是為 Vue 中 vnode 的唯一標(biāo)記倦始,通過這個(gè) key斗遏,我們的 diff 操作可以更準(zhǔn)確、更快速鞋邑。Vue 的 diff 過程可以概括為:oldCh 和 newCh 各有兩個(gè)頭尾的變量 oldStartIndex诵次、oldEndIndex 和 newStartIndex、newEndIndex枚碗,它們會(huì)新節(jié)點(diǎn)和舊節(jié)點(diǎn)會(huì)進(jìn)行兩兩對(duì)比逾一,即一共有4種比較方式:newStartIndex 和oldStartIndex 、newEndIndex 和 oldEndIndex 肮雨、newStartIndex 和 oldEndIndex 遵堵、newEndIndex 和 oldStartIndex,如果以上 4 種比較都沒匹配怨规,如果設(shè)置了key陌宿,就會(huì)用 key 再進(jìn)行比較,在比較的過程中波丰,遍歷會(huì)往中間靠壳坪,一旦 StartIdx > EndIdx 表明 oldCh 和 newCh 至少有一個(gè)已經(jīng)遍歷完了,就會(huì)結(jié)束比較掰烟。具體有無 key 的 diff 過程爽蝴,可以查看作者寫的另一篇詳解虛擬 DOM 的文章《深入剖析:Vue核心之虛擬DOM

所以 Vue 中 key 的作用是:key 是為 Vue 中 vnode 的唯一標(biāo)記,通過這個(gè) key纫骑,我們的 diff 操作可以更準(zhǔn)確蝎亚、更快速

更準(zhǔn)確:因?yàn)閹?key 就不是就地復(fù)用了,在 sameNode 函數(shù) a.key === b.key 對(duì)比中可以避免就地復(fù)用的情況惧磺。所以會(huì)更加準(zhǔn)確颖对。
更快速:利用 key 的唯一性生成 map 對(duì)象來獲取對(duì)應(yīng)節(jié)點(diǎn),比遍歷方式更快磨隘,源碼如下:

function createKeyToOldIdx (children, beginIdx, endIdx) {
  let i, key
  const map = {}
  for (i = beginIdx; i <= endIdx; ++i) {
    key = children[i].key
    if (isDef(key)) map[key] = i
  }
  return map
}

你有對(duì) Vue 項(xiàng)目進(jìn)行哪些優(yōu)化缤底?

如果沒有對(duì) Vue 項(xiàng)目沒有進(jìn)行過優(yōu)化總結(jié)的同學(xué),可以參考本文作者的另一篇文章《 Vue 項(xiàng)目性能優(yōu)化 — 實(shí)踐指南 》番捂,文章主要介紹從 3 個(gè)大方面个唧,22 個(gè)小方面詳細(xì)講解如何進(jìn)行 Vue 項(xiàng)目的優(yōu)化。

(1)代碼層面的優(yōu)化
  • v-if 和 v-show 區(qū)分使用場(chǎng)景
  • computed 和 watch 區(qū)分使用場(chǎng)景
  • v-for 遍歷必須為 item 添加 key设预,且避免同時(shí)使用 v-if
  • 長(zhǎng)列表性能優(yōu)化
  • 事件的銷毀
  • 圖片資源懶加載
  • 路由懶加載
  • 第三方插件的按需引入
  • 優(yōu)化無限列表性能
  • 服務(wù)端渲染 SSR or 預(yù)渲染
(2)Webpack 層面的優(yōu)化

Webpack 對(duì)圖片進(jìn)行壓縮
減少 ES6 轉(zhuǎn)為 ES5 的冗余代碼
提取公共代碼
模板預(yù)編譯
提取組件的 CSS
優(yōu)化 SourceMap
構(gòu)建結(jié)果輸出分析
Vue 項(xiàng)目的編譯優(yōu)化徙歼。

(3)基礎(chǔ)的 Web 技術(shù)的優(yōu)化
  • 開啟 gzip 壓縮

  • 瀏覽器緩存

  • CDN 的使用

  • 使用 Chrome Performance 查找性能瓶頸

對(duì)于即將到來的 vue3.0 特性你有什么了解的嗎?

Vue 3.0 正走在發(fā)布的路上鳖枕,Vue 3.0 的目標(biāo)是讓 Vue 核心變得更小魄梯、更快、更強(qiáng)大宾符,因此 Vue 3.0 增加以下這些新特性:

(1)監(jiān)測(cè)機(jī)制的改變

3.0 將帶來基于代理 Proxy 的 observer 實(shí)現(xiàn)酿秸,提供全語言覆蓋的反應(yīng)性跟蹤。這消除了 Vue 2 當(dāng)中基于 Object.defineProperty 的實(shí)現(xiàn)所存在的很多限制:

  • 只能監(jiān)測(cè)屬性魏烫,不能監(jiān)測(cè)對(duì)象

  • 檢測(cè)屬性的添加和刪除辣苏;

  • 檢測(cè)數(shù)組索引和長(zhǎng)度的變更;

  • 支持 Map哄褒、Set稀蟋、WeakMap 和 WeakSet。

新的 observer 還提供了以下特性:

  • 用于創(chuàng)建 observable 的公開 API呐赡。這為中小規(guī)模場(chǎng)景提供了簡(jiǎn)單輕量級(jí)的跨組件狀態(tài)管理解決方案退客。
  • 默認(rèn)采用惰性觀察。在 2.x 中链嘀,不管反應(yīng)式數(shù)據(jù)有多大井辜,都會(huì)在啟動(dòng)時(shí)被觀察到。如果你的數(shù)據(jù)集很大管闷,這可能會(huì)在應(yīng)用啟動(dòng)時(shí)帶來明顯的開銷粥脚。在 3.x 中,只觀察用于渲染應(yīng)用程序最初可見部分的數(shù)據(jù)包个。
  • 更精確的變更通知刷允。在 2.x 中,通過 Vue.set 強(qiáng)制添加新屬性將導(dǎo)致依賴于該對(duì)象的 watcher 收到變更通知碧囊。在 3.x 中树灶,只有依賴于特定屬性的 watcher 才會(huì)收到通知。
  • 不可變的 observable:我們可以創(chuàng)建值的“不可變”版本(即使是嵌套屬性)糯而,除非系統(tǒng)在內(nèi)部暫時(shí)將其“解禁”天通。這個(gè)機(jī)制可用于凍結(jié) prop 傳遞或 Vuex 狀態(tài)樹以外的變化。
  • 更好的調(diào)試功能:我們可以使用新的 renderTracked 和 renderTriggered 鉤子精確地跟蹤組件在什么時(shí)候以及為什么重新渲染熄驼。
(2)模板

模板方面沒有大的變更像寒,只改了作用域插槽烘豹,2.x 的機(jī)制導(dǎo)致作用域插槽變了,父組件會(huì)重新渲染诺祸,而 3.0 把作用域插槽改成了函數(shù)的方式携悯,這樣只會(huì)影響子組件的重新渲染,提升了渲染的性能筷笨。

同時(shí)憔鬼,對(duì)于 render 函數(shù)的方面,vue3.0 也會(huì)進(jìn)行一系列更改來方便習(xí)慣直接使用 api 來生成 vdom 胃夏。

(3)對(duì)象式的組件聲明方式

vue2.x 中的組件是通過聲明的方式傳入一系列 option轴或,和 TypeScript 的結(jié)合需要通過一些裝飾器的方式來做,雖然能實(shí)現(xiàn)功能仰禀,但是比較麻煩照雁。3.0 修改了組件的聲明方式,改成了類式的寫法悼瘾,這樣使得和 TypeScript 的結(jié)合變得很容易囊榜。

此外,vue 的源碼也改用了 TypeScript 來寫亥宿。其實(shí)當(dāng)代碼的功能復(fù)雜之后卸勺,必須有一個(gè)靜態(tài)類型系統(tǒng)來做一些輔助管理。現(xiàn)在 vue3.0 也全面改用 TypeScript 來重寫了烫扼,更是使得對(duì)外暴露的 api 更容易結(jié)合 TypeScript曙求。靜態(tài)類型系統(tǒng)對(duì)于復(fù)雜代碼的維護(hù)確實(shí)很有必要。

(4)其它方面的更改

vue3.0 的改變是全面的映企,上面只涉及到主要的 3 個(gè)方面悟狱,還有一些其他的更改:

  • 支持自定義渲染器,從而使得 weex 可以通過自定義渲染器的方式來擴(kuò)展堰氓,而不是直接 fork 源碼來改的方式挤渐。
  • 支持 Fragment(多個(gè)根節(jié)點(diǎn))和 Protal(在 dom 其他部分渲染組建內(nèi)容)組件,針對(duì)一些特殊的場(chǎng)景做了處理双絮。
  • 基于 treeshaking 優(yōu)化浴麻,提供了更多的內(nèi)置功能。

作者:Vicky丶Amor
鏈接:http://www.reibang.com/p/b1564296a78b
來源:簡(jiǎn)書
著作權(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閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蝌蹂,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡挟鸠,警方通過查閱死者的電腦和手機(jī)叉信,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門亩冬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來艘希,“玉大人,你說我怎么就攤上這事硅急「蚕恚” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵营袜,是天一觀的道長(zhǎng)撒顿。 經(jīng)常有香客問我,道長(zhǎng)荚板,這世上最難降的妖魔是什么凤壁? 我笑而不...
    開封第一講書人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮跪另,結(jié)果婚禮上拧抖,老公的妹妹穿的比我還像新娘。我一直安慰自己免绿,他們只是感情好唧席,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著嘲驾,像睡著了一般淌哟。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上辽故,一...
    開封第一講書人閱讀 51,146評(píng)論 1 297
  • 那天徒仓,我揣著相機(jī)與錄音,去河邊找鬼誊垢。 笑死掉弛,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的彤枢。 我是一名探鬼主播狰晚,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼缴啡!你這毒婦竟也來了壁晒?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤业栅,失蹤者是張志新(化名)和其女友劉穎秒咐,沒想到半個(gè)月后谬晕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡携取,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年攒钳,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片雷滋。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡不撑,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出晤斩,到底是詐尸還是另有隱情焕檬,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布澳泵,位于F島的核電站实愚,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏兔辅。R本人自食惡果不足惜腊敲,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望维苔。 院中可真熱鬧碰辅,春花似錦、人聲如沸蕉鸳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽潮尝。三九已至榕吼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間勉失,已是汗流浹背羹蚣。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留乱凿,地道東北人顽素。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像徒蟆,于是被迫代替她去往敵國(guó)和親胁出。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353