(譯)Mantra官方文檔

Mantra官方文檔(翻譯)

轉載請注明作者及原文鏈接

工作草案-版本0.2.0

簡介

這是一個Mantra草案規范,一個由Kadira創建的Meteor的應用程序架構。 它幫助開發人員構建可維護的,面向未來的Meteor應用程序。

版權

The MIT License (MIT)

Copyright (c) 2016 Kadira Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

轉載我的翻譯也要署名哦~

內容

(這兒有個目錄,可我不想寫啦,在我的博客中目錄會自動生成哦~)

1 概述

Mantra是Meteor的應用程序架構。 有了Mantra,我們試圖實現以下兩個主要目標。
1.可維護性
可維護性是與大型團隊合作的關鍵因素。 我們通過對我們應用程序的每個部分進行單元測試來實現這一點,同時遵循一個標準。 這樣很容易讓新手加入團隊。
2.未來證明(Future Proof)
JavaScript就像是一個充滿選擇的土地。 我們對每個問題有不止一個最佳解決方案。 現在很難說什么是最好的解決方案,未來會有什么變化。
Mantra依賴一套將持續很長時間的核心原則,我們允許其他人根據需要進行更改。

1.1 Mantra里有什么?

  • 它有一個現代的,基于React的UI組件層。
  • 它有一個在你的應用程序中定義業務邏輯的地方, 我們稱之為 動作(action)。
  • Mantra本身不提供狀態管理,但它允許你使用各種各樣的狀態管理器,包括Meteor / Tracker,Redux,Rx.js Observable,Promise和幾乎任何其他的狀態管理器。
  • 它有一種通過組合容器(containers)將狀態(states)和動作(action)集成到UI組件中的方法。
  • 它允許你依賴注入。
  • 它幫助你單元測試UI,動作和集成(容器)。
  • 它對目錄布局,文件命名和其他內容都有一些標準。

1.2 Mantra不是什么?

  • 它不是一個應用程序平臺,應用程序平臺專注于應用打包,傳輸,部署等任務。Mantra使用Meteor作為應用程序平臺。
  • 它不是一個樣板,即使我們有著同樣的目錄結構。
  • 它不是一個代碼生成器,我們可能會有一個代碼生成工具(譯者注:已經有了,詳見mantra-cli),但這并不是Mantra的核心部分

1.3 Mantra是什么?

  • 它是一套如何構建Meteor應用程序的標準。
  • 它還帶有一套已經被整理過的且被維護著的庫,幫助你在Meteor上實現Mantra。

1.4 為什么要規范?

Mantra是一個應用程序架構。 會有很多人使用Mantra,包括應用程序開發人員,工具創建者,教程作者和項目經理,所以擁有一個每個人都遵循的標準是非常重要的。 這就是為什么要規范。

1.5 在你閱讀之前

雖然本規范是以一種簡單易懂的語句編寫的。 但是,如果你對以下領域有充分的了解,你讀起來可能會感到流暢。

  • ES2015
  • React
  • React Containers
  • Meteor基礎(Pub / Sub,Tracker,ReactiveDict等)

請參閱附錄A以了解有關上述領域的更多信息

2 核心組件

以下是Mantra的核心組件及其組織方式:

2.1 聚焦客戶端

Mantra特別注重你的應用程序的客戶端。 Mantra不會將客戶端和服務端代碼混合在一起;相反,它建議代碼共享。原因是:

  • 客戶端是你應該付出很多努力的地方。它是你的代碼庫中最大的一部分。服務器端代碼庫相對更容易組織和管理。
  • 客戶端應用程序將使用schema與服務器交互??蛻舳藨贸绦虿粦撽P心服務端如何實現的。
    Mantra不支持Universal Apps這個觀點。它鼓勵不同的平臺不同的應用程序并在其之間代碼共享。通常有一個服務器與幾個客戶端應用程序之間交互。
    基于上述觀點,將客戶端和服務端代碼混合在一起并不是一個好主意。
    當我們在本規范中進一步討論Mantra時,它將指的是你應用程序的客戶端。

然而,大多數應用程序將具有服務器端組件。因此,我們還提供一個服務器端的目錄布局。有關詳情,請參閱附錄B。

2.2 ES2015語法和ES2015模塊

我們依賴ES2015及其模塊的很多新特性,因此,為了使用Mantra,你需要使用Meteor 1.3,它附帶了ES2015模塊。

2.3 使用React作為UI

我們使用React作為Mantra中的UI(表示)層。
UI組件不應該知道關于應用程序的其余部分的任何內容,并且不應該讀取或修改應用程序的狀態。 用于渲染UI組件的數據和事件處理程序應通過props從容器傳遞或作為動作(action)從其內部的事件處理程序中傳遞。 有時需要在UI組件內使用臨時局部狀態,但該狀態不應在其自身組件外引用。
在編寫UI組件時,你可以將任意React組件引入程序,包括

  • 在應用程序中定義的其他UI組件。
  • 來自NPM的UI組件(如material-ui)。
  • 應用中的任何容器(我們稍后會討論這個問題)。
    還可以導入任何庫函數并在UI組件中使用它們。 你可以直接從NPM模塊引入,但不能從任何Meteor軟件包引入。 這些函數應該是純函數。
    這里是一個簡單的UI組件:
import React from 'react';

const PostList = ({posts}) => (
  <div className='postlist'>
    <ul>
      {posts.map(post => (
        <li key={post._id}>
          <a href={`/post/${post._id}`}>{post.title}</a>
        </li>
      ))}
    </ul>
  </div>
);

export default PostList;

2.4 動作(Actions)

動作是你在app中寫業務邏輯的地方,它們包括:

  • 驗證
  • State 管理
  • 與遠程數據源的交互
    一個動作是一個簡單的函數,它的第一個參數是整個應用的Context,其他參數通常來自函數調用時。

注意: 在動作中,你所做的一切都應是基于應用的Context傳遞給動作的其他參數。你不能引用任何ES2015的modules 除了庫以外。還應避免在動作中使用全局變量。

這是一個動作:

export default{
    create({Meteor,LocalState,FlowRouter},title,content){
        if(!title||!content){
            return LocalState.set('SAVING_ERROR','Title & Content are required!');
        }
    }
    LocalState.set('SAVING_ERROR',null);
    //這里調用“config/method_stubs”中的一個method
    //這是我們如何做延遲補償
    Meteor.call('posts.create', id, title, content, (err) => {
      if (err) {
        return LocalState.set('SAVING_ERROR', err.message);
      }
    });
    FlowRouter.go(`/post/${id}`);

    clearErrors({LocalState}){
        return     LocalState.set('SAVING_ERROR', null);
    }

};

2.5 狀態(state)管理

在app中,我們需要處理不同種類的狀態。我們可以把他們分為兩類。

  1. 本地狀態 - 從來不會同步到遠程服務器的狀態(錯誤,驗證信息,當前的頁面)
  2. 遠程狀態 - 這是通常從遠程服務器獲取并與其同步的state。
    我們有不同的解決方案來管理我們app中的states,包括:
  • Meteor/MiniMongo (遠程狀態)
  • Tracker/ReactiveDict (本地狀態)
  • FlowRouter (本地狀態)
  • Redux (本地狀態)
  • GraphQL (遠程狀態)
  • Falcor (遠程狀態)

這就是JavaScript社區一直在創新的地方。因此,Mantra在涉及到狀態管理時是靈活的。你可以使用任何你想使用的。
舉個例子,你可以在你的應用啟動時使用以下狀態:

  • Meteor/MiniMongo (遠程狀態)
  • Tracker/ReactiveDict (本地狀態)
  • FlowRouter (本地狀態)
    之后你也可以換用其他解決方案。

注意: Mantra在管理狀態時有一些強制規則

  • 所有的狀態的寫操作都要在其對應的動作中完成。
  • 你既可以在動作中讀取狀態也可以在容器中讀取狀態。
  • 不允許直接在UI 組件中讀寫狀態,UI 組件不應該知道任何應用程序中的狀態。

下面的鏈接是一些關于狀態的使用例子
Reading from local state – inside a container
Writing into local state – inside an action
Reading from a remote state – inside a container

2.6 容器(Containers)

容器是Mantra的集合層,他們執行這些操作:

  • 使用狀態來修改變量,并通過props將它們傳遞到UI組件。
  • 將動作(action)傳遞到UI組件中。
  • 將應用Context中的項目傳遞到UI組件中
    容器是一個React component。

容器使用react‐komposer,它支持不同的數據源,包括 Meteor/Tracker, Promises, Rx.js Observable,和幾乎所有其他的數據源。

通常情況下,在容器中需要些下面這些函數:

  • composer函數用來從狀態管理中獲取數據。
  • mapper函數從依賴注入層獲取數據。
    創建容器的一些規則:
  • 單個文件中應該只有一個容器,并且這個容器必須是默認引出的(default export)
  • composer函數和mapper函數必須從容器模塊引出(exported)
  • composer函數只能使用props傳遞變量
  • mapper函數必須是純函數(Pure function)

注意:如果需要傳遞應用Context給一個組件,請使用mapper函數函數通過props傳遞。

這是一個容器的例子:

import PostList from '../components/postlist.jsx';
import {useDeps, composeWithTracker, composeAll} from 'mantra-core';

export const composer = ({context}, onData) => {
  const {Meteor, Collections} = context();
  if (Meteor.subscribe('posts.list').ready()) {
    const posts = Collections.Posts.find().fetch();
    onData(null, {posts});
  }
};

export default composeAll(
  composeWithTracker(composer),
  useDeps()
)(PostList);

2.7 應用Context

應用Context可用于所有操作和容器,因此這是應用程序中共享變量的地方,他們包括:

  • Meteor namespace
  • Meteor Collections
  • 本地狀態
  • FlowRouter
  • 其他Meteor包
  • Redux Stores
  • Rest Clients
  • DDP Clients
    這是一個簡單的應用Context的例子:
import * as Collections from '/lib/collections';
import {Meteor} from 'meteor/meteor';
import {FlowRouter} from 'meteor/kadira:flow-router';
import {ReactiveDict} from 'meteor/reactive-dict';
import {Tracker} from 'meteor/tracker';

export default function () {
  return {
    Meteor,
    FlowRouter,
    Collections,
    LocalState: new ReactiveDict(),
    Tracker
  };
}

2.8 依賴注入

Mantra使用依賴注入來隔離應用程序的不同部分,包括UI組件和動作(actions)。

我們使用一個名為react-simple-di的項目,它在后臺使用React Context。 它同時接受應用Context和動作(action)作為依賴。

一旦配置,應用程序Context會注入到每一個action中,它是action的第一個參數,因此你不需要手動傳遞應用Context。

應用程序Context也可以在容器中訪問。

2.8.1 配置依賴注入

依賴關系將注入到應用程序的頂級組件中,通常是一個布局組件,你可以在你的路由中注入,看一下這個例子:

import React from 'react';
export default function (injectDeps) {
  //這是注入部分:
  const MainLayoutCtx = injectDeps(MainLayout);

  // 路由相關代碼
  //......
}

2.9 路由和組件掛載(Mounting)

注意:當我們提到組件時,會同時包含容器(containers)和UI組件(UI components)

我們通常使用路由去掛載組件到UI,這可以有多種解決方案(比如Flow RouterReact Router)

路由只是一個工具,它在Mantra中的唯一功能就是將組件掛載到UI上。

看一下使用FlowRouter當做路由的例子:

import React from 'react';
import {FlowRouter} from 'meteor/kadira:flow-router';
import {mount} from 'react-mounter';

import MainLayout from '/client/modules/core/components/main_layout.jsx';
import PostList from '/client/modules/core/containers/postlist';

export default function (injectDeps) {
  const MainLayoutCtx = injectDeps(MainLayout);

  FlowRouter.route('/', {
    name: 'posts.list',
    action() {
      mount(MainLayoutCtx, {
        content: () => (<PostList />)
      });
    }
  });
}

注意:如果你需要根據某些條件重定向(例如用戶未被授權),請使用action來代替像FlowRouter的triggersEnter這樣的路由選項。 從組件或容器的composer函數調用action。

2.10 庫

每個應用程序都有一些實用的功能去完成不同的任務,你也可以通過NPM獲取它們。這些庫將引出(export)函數。所以,你可以在應用程序的任何位置引用他們,包括動作,組件和容器。

當在組件庫中使用庫函數時,它應該是純函數。

2.11 測試

測試是Mantra的一個核心部分,Mantra幫助你測試應用程序的每一個部分。我們強制執行這些規則有助于你編寫測試程序。你可以使用熟悉的工具,如MochaChaiSinon來進行測試。

使用Mantra,你可以在應用程序中單元測試以下三個核心部分:

2.11.1 UI測試

我們使用enzyme為UI進行測試,點擊這里看一些簡單的測試用例。

2.12 Mantra 模塊

Mantra遵循模塊化架構。 除了“應用程序Context”之外,Mantra的所有組件都應駐留在模塊中。

你可以創建很多很多的模塊,并通過imports使它們建立聯系。

2.12.1 應用程序Context和模塊的關系

應用程序Context是應用程序的核心。 它需要在不屬于任何模塊的地方定義。 所有模塊可以作為依賴關系訪問應用程序Context,模塊不應更新應用程序Context。

2.12.2 模塊的定義

Mantra模塊可以包含定義它的主文件文件。 它暴露動作,路由和接受context的函數。 通常是 index.js 文件。

一個簡單的模塊定義像這樣:

export default {
  // 可選的
  load(context, actions) {
    // 做一些模塊的初始化工作
  },
  // 可選的
  actions: {
    myNamespace: {
      doSomething: (context, arg1) => {}
    }
  },
  // 可選的
  routes(injectDeps) {
    const InjectedComp = injectDeps(MyComp);
    // 加載路由并將"被注入的組件"顯示在屏幕上。
  }
};
2.12.3 隱式模塊

如果一個模塊沒有任何action和路由,或者不需要任何初始化,那么可以避免使用定義文件。這種隱式模塊可能包含以下內容:

  • UI組件
  • 容器
2.12.4 模塊容器和UI組件的關系

模塊容器和UI組件應能夠通過ES2015模塊引入(imported)。

2.12.5 模塊動作

模塊可以通過命名空間暴露動作。 這些命名空間對于應用程序是全局的,模塊應該保證它們是唯一的。 一個模塊可以暴露多個命名空間。

最后,來自每個模塊的所有這些命名空間都被合并,并且可以在action和容器內訪問。

2.12.6 路由

你可以使用任意的路由庫進行路由。如果需要,也可以在多個模塊中使用路由定義。

2.12.7 核心模塊

Mantra是100%模塊化的,應用程序中應至少有一個模塊, 我們稱之為核心模塊。 它只是一個簡單的模塊,但你需要在任何其他模塊之前加載它。 這個模塊最好放在下面這些地方:

  • 核心路由
  • 應用配置
  • 通用庫
  • 通用動作
    和其他特定的應用代碼中。
    根據應用程序,有多種方式組織模塊,詳見附錄C
2.12.8 子模塊

在一個模塊中,不能 包含子模塊。這是為防止不必要的復雜性而做出的決定。 否則,編寫多層嵌套模塊是會很難管理。

2.13 單一入口

使用Mantra,我們希望我們的應用是可與預測的。因此,你的應用只能有一個入口點,它就是client/main.js

它將初始化應用程序Context并加載應用程序中的所有模塊。 這里有一個client / main.js文件示例:

import {createApp} from 'mantra-core';
import {initContext} from './configs/context';

// 模塊
import coreModule from './modules/core';
import commentsModule from './modules/comments';

// 初始化 context
const context = initContext();

// 創建 app
const app = createApp(context);
app.loadModule(coreModule);
app.loadModule(commentsModule);
app.init();

3 目錄布局

在Mantra中,我們強制使用一個公共目錄結構。 這是任何應用程序的可維護性的核心部分。

在本節中,我們只討論客戶端目錄布局。 要了解如何組織服務器端目錄布局,請參閱附錄B。

3.1 頂層目錄結構

所有與Mantra相關的代碼都保留在應用程序的client目錄中。 在內部,通常有兩個目錄和一個JavaScript文件。 他們是:

* configs
* modules
* main.js

讓我們詳細分析下他們中的每一個。

3.1.1 configs

此目錄包含應用程序中的根級別配置。 通常,這是一個放置所有模塊通用的應用程序范圍的全局配置的地方。
此目錄中的所有JavaScript文件都應使用默認引出函數(default export function),該功能可啟動某些任務,并在需要時返回。

注意:我們通常將應用Context放置在這里的context.js中。

3.1.2 modules

此目錄包含應用程序中的一個或多個模塊(在自己的目錄中)。 這里至少應該有一個模塊,它通常被稱為core。
在modules目錄中,通常有這些內容:

* actions
* components
* configs
* containers
* libs
* routes.jsx
* index.js

讓我們學習更多關于這個目錄下的目錄和文件。

3.1.2.1 actions

此目錄包含模塊中的所有action。 這里有一個目錄布局的示例:

* posts.js
* index.js
* tests
    - posts.js

posts.js是一個ES2015模塊,它引出具有action的JavaScript對象。 例如,下面是一個簡單的action模塊:

export default {
  create({Meteor, LocalState, FlowRouter}, title, content) {
    //...
  },

  clearErrors({LocalState}) {
    //...
  }
};

然后,在index.js中,我們引入所有action模塊并聚合所有action。 我們給每個模塊一個命名空間。

import posts from './posts';

export default {
  posts
};

在上面的例子中,我們給posts.js這個action模塊一個命名空間posts。

注意:這些命名空間在應用程序中應該是唯一的。 這是模塊的責任。

在tests目錄中,我們使用action的名稱為每個action模塊編寫測試。 請參閱附錄D以了解有關測試文件命名約定的更多信息。

點擊這里查看action的目錄布局

3.1.2.2 components

Components包含模塊化UI組件。 它的目錄布局如下:

* main_layout.jsx
* post.jsx
* style.css
* tests
  - main_layout.js
  - post.js
  • 在這個目錄下所有的.jsx文件都必須默認引出。他們必須是一個React類。
  • 你可以編寫與這些React組件相關的CSS文件,Meteor將為你綁定它們。
    就像在actions中,這里也有一個tests目錄。請參閱附錄D以了解有關測試文件命名約定的更多信息。

點擊這里查看components的目錄布局

3.1.2.3 containers

此目錄包含一組.js文件,每個文件表示一個容器。 每個文件應該作為React Container類默認引出。

這是一個通常的目錄布局:

* post.js
* postlist.js
* tests
    - post.js
    - postlist.js

這個目錄下也有一個tests目錄。請參閱附錄D以了解有關測試文件命名約定的更多信息。
點擊這里查看containers的目錄布局

3.1.2.4 configs

這個目錄包含應用中模塊層次的配置。

此目錄中的所有JavaScript文件必須引出一個默認函數,該函數可啟動任何任務,并在需要時返回一些內容。 該函數可以接受“應用程序Context”作為第一個參數。

這是一個簡單的config文件:

export default function (context) {
  // do something
}

這些設置可以在加載這個模塊時被引用和調用。

注意:通常,這是我們保存用于樂觀更新的Meteor方法存根的地方。

點擊這里查看configs的目錄布局

3.1.2.5 libs

此目錄包含一組有效引出函數的JavaScript文件(.js.jsx)。 這也被稱為庫。 您可以在tests的子目錄中編寫庫的測試。

3.1.2.6 routes.jsx

這是包含模塊的路由定義的文件。 它有一個默認引出,它是一個函數。 下面是一個典型的路由定義:

import React from 'react';
import {FlowRouter} from 'meteor/kadira:flow-router';
import {mount} from 'react-mounter';

import MainLayout from '/client/modules/core/components/main_layout.jsx';
import PostList from '/client/modules/core/containers/postlist';

export default function (injectDeps) {
  const MainLayoutCtx = injectDeps(MainLayout);

  FlowRouter.route('/', {
    name: 'posts.list',
    action() {
      mount(MainLayoutCtx, {
        content: () => (<PostList />)
      });
    }
  });
}

如上所示,在加載模塊時,將使用一個名為injectDeps的函數來調用此默認引出,injectDeps函數可以將依賴項注入到React組件(或容器)中。

3.1.2.7 index.js

這是模塊的定義文件(主文件)。如果不需要執行以下任務則不需要此文件:

  • 加載路由
  • 定義action
  • 在加載模塊時運行配置

這是一個典型的模塊定義文件:

import methodStubs from './configs/method_stubs';
import actions from './actions';
import routes from './routes.jsx';

export default {
  routes,
  actions,
  load(context) {
    methodStubs(context);
  }
};

在模塊定義中,當模塊加載時,會調用.load()方法,所以,這里是調用配置的地方。

3.1.3main.js

這是Mantra應用程序的入口點。 它初始化應用程序Context并加載模塊。 因此,它使用一個名為mantra-core的實用程序庫。

這是一個簡單的main.js文件的例子:

import {createApp} from 'mantra-core';
import initContext from './configs/context';

// 模塊
import coreModule from './modules/core';
import commentsModule from './modules/comments';

// 初始化 context
const context = initContext();

// 創建應用(app)
const app = createApp(context);
app.loadModule(coreModule);
app.loadModule(commentsModule);
app.init();

4 未來的工作

Mantra是一個草稿,將有缺失的部分和我們可以做的改進。 我們已經確定以下功能對Mantra很重要,他們將在不久的將來可用。
(懶得翻了 過過再更~)

4.1 Server-Side Rendering (SSR)

It’s extremely possible to do SSR with Mantra. We are trying to do this in a tool‐agnostic manner, but the reference implementation will be based on FlowRouter SSR.

4.2 Distributing Mantra Modules via NPM

We could distribute Mantra modules via NPM. Once we do that, we could do reuse a lot of code between apps and organizations.

4.3 Standard for Styling

It’s better to have a standard for styling UI components.

4.4 Standard for Tests

It’s better to have a standard for writing test cases.

4.5 Reusing Composers

Sometimes, we can use reuse composers for the same function in many places. We need to find a pattern for doing that.

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

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,734評論 25 708
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,826評論 18 139
  • Meteor Mantra 系列文章: Meteor Mantra 介紹(一)- 基本概念Meteor Mantr...
    浮點量化閱讀 3,087評論 1 13
  • 核心組件 這里羅列了Mantra中的核心組件。 服務端與客戶端 Mantra非常關注客戶端,因為那是你寫大部分代碼...
    時見疏星閱讀 1,111評論 0 2
  • 久旱逢甘雨,他鄉遇故知,洞房花燭夜,金榜掛名時。 大吉大利之象,平常所謂雙喜臨門,已是罕見,如今四喜臨門,真是人間...
    運安閣閣主閱讀 842評論 0 0