WebKit學(xué)習(xí)—用WKWebView封裝一個常用的WebViewController

慣例先看效果圖(后附demo地址)

webVideo.gif

??在iOS項目開發(fā)中,絕大多數(shù)功能都是我們原生開發(fā)的,但是像一些諸如用戶協(xié)議說明,公司介紹构舟,App內(nèi)的活動頁以及引用的其他網(wǎng)頁都需要借助web頁面來實現(xiàn),有的頁面簡單堵幽,只需要加載一個簡單的url即可狗超,有的頁面則需要用到OC和JS的交互來實現(xiàn)。

???提到WebView朴下,我們可能首先想起UIWebView努咐,在iOS8.0之前,都是用此來加載網(wǎng)頁殴胧,但是當(dāng)我們打開Apple的開發(fā)文檔(在此插一句題外話渗稍,當(dāng)我們開發(fā)的時候肯定會遇到一些問題佩迟,就拿這個UIWebView來說,我們想知道它加載網(wǎng)頁的方法竿屹,因此我們可能首先想到的就是去百度一下看看报强,有時候卻發(fā)現(xiàn)找來找去,不同的人有不同的寫法甚至是寫的并不對拱燃,或者說的并不明白秉溉,這時候我建議還是查看Apple的官方文檔,我們要習(xí)慣看Apple官方文檔碗誉,因為不僅權(quán)威而且還原汁原味召嘶。)發(fā)現(xiàn)UIWebView是在UIKit下的Content Views中。打開UIWebView后哮缺,有個提示:

In apps that run in iOS 8 and later, use the WKWeb<wbr style="margin-top: 0px; margin-bottom: 0px;">View class instead of using UIWebView. Additionally, consider setting the WKPreferences property java<wbr style="margin-top: 0px;">Script<wbr style="margin-bottom: 0px;">Enabled to NO if you render files that are not supposed to run JavaScript.

意思是說在iOS 8.0之后用WKWebView來替代UIWebView弄跌,此外WKWebView對于和JS的交互相比較UIWebView而言還需要不同的設(shè)置。蘋果在此讓我們用WKWebView來替代UIWebView尝苇,我們再來看下WKWebView铛只,通過Apple開發(fā)文檔發(fā)現(xiàn)有一個專門的WebKit,并不是在UIKit中糠溜。


20180308135618.png

UIWebView是在UIKit下


20180308135832.png

WKWebView是在WebKit下


???UIWebView就這么被替代了格仲,相信很多開發(fā)者還是很習(xí)慣UIWebView來開發(fā)的,因為使用方法相對簡單诵冒,但是相較于UIWebView,WKWebView更強大谊惭,他有什么新特性呢汽馋?

1.更多的支持HTML5的特性

2.官方宣稱的高達60fps的滾動刷新率以及內(nèi)置手勢

3.Safari相同的JavaScript引擎

4.將UIWebViewDelegate與UIWebView拆分成了14類與3個協(xié)議(官方文檔說明)

5.另外用的比較多的,增加加載進度屬性:estimatedProgress

哇圈盔,一看這么多優(yōu)點豹芯。。驱敲。這些優(yōu)點都是相對于UIWebView而言的铁蹈,真是沒有比較就沒有傷害。對于上面官方說的WKWebView的新特性众眨,有的開發(fā)者專門那UIWebView和WKWebView去測試了握牧,確實發(fā)現(xiàn)WKWebView比UIWebView在內(nèi)存上和加載速度上明顯更勝一籌,在實際開開發(fā)中娩梨,我們也能明顯感覺得到沿腰,加載同樣一個網(wǎng)頁,WKWebView比UIWebView相應(yīng)速度明顯快很多狈定。

對于UIWebView的使用方法颂龙,在這里就不多贅述了习蓬,Apple開發(fā)文檔有詳細(xì)的說明也比較簡單章咧,本文的重點是在我們開發(fā)中封裝一個公用的WebView伺帘,因此我們的主角還是WKWebView,當(dāng)然蓄坏,考慮到系統(tǒng)適配企巢,我們?nèi)匀豢梢允褂肬IWebView枫慷,但是現(xiàn)在運行iOS8.0的設(shè)備已經(jīng)很少了吧,如果要是為了考慮到自己項目的兼容性包斑,可以做一個系統(tǒng)版本的適配流礁。再次我們就以WKWebView為主。

開始前的思考

在開始之前罗丰,我們先想一下我們的Web請求一般會有怎樣的應(yīng)用場景

1.加載簡單的一個頁面 無附加操作

2.原生(OC)和web頁面(JS)交互神帅;包括JS調(diào)用OC和OC執(zhí)行JS代碼兩種方式

其中第一點很好實現(xiàn),基本不用多做處理萌抵,第二點找御,OC和JS交互就比較復(fù)雜了,首先我們先對WKWebView初始化:

- (WKWebView* )wkWebView {
    if (!_wkWebView) {
        WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc]init];
        config.preferences = [[WKPreferences alloc]init];
        config.allowsInlineMediaPlayback = YES;
        config.selectionGranularity = YES;
        //自定義配置绍填,一般用于js調(diào)用oc方法(OC攔截URL中的數(shù)據(jù)做自定義操作)
        WKUserContentController *userContentController = [[WKUserContentController alloc] init];
        [userContentController addScriptMessageHandler:self name:@"backPresent"];
        //JS注入 向網(wǎng)頁中添加自己的JS方法
        NSString *cookie = self.cookies;
        WKUserScript *cookieScript = [[WKUserScript alloc] initWithSource:cookie injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
        [userContentController addUserScript:cookieScript];
        config.userContentController = userContentController;
        
        _wkWebView = [[WKWebView alloc]initWithFrame:CGRectMake(0, NAVI_HEIGHT, self.view.bounds.size.width, self.view.bounds.size.height - NAVI_HEIGHT) configuration:config];
        _wkWebView.navigationDelegate = self;
        _wkWebView.UIDelegate = self;
        //添加此屬性可觸發(fā)側(cè)滑返回上一網(wǎng)頁與下一網(wǎng)頁操作
        _wkWebView.allowsBackForwardNavigationGestures = YES;
    return _wkWebView;
}

WKWebViewConfiguration

在初始化方法中有一個必傳參數(shù)WKWebViewConfiguration,我們首先來看一下這個WKWebViewConfiguration是什么鬼霎桅,Apple開發(fā)文檔是這么說的:

Overview
Using the WKWebViewConfiguration class, you can determine how soon a webpage is rendered, how media playback is handled, the granularity of items that the user can select, and many other options.
WKWebViewConfiguration is only used when a web view is first initialized. You cannot use this class to change the web view's configuration after it has been created.

??說白了,通過這個類我們可以設(shè)置WKWebView的網(wǎng)頁渲染時間讨永,網(wǎng)頁媒體文件處理方式以及一些WKWebView的基本設(shè)置滔驶,只能在初始化的時候設(shè)置。也就是說通過設(shè)置WKWebViewConfiguration我們可以配置WKWebView的web頁面的處理方式卿闹。除了WKWebViewConfiguration之外揭糕,還有一個WKScriptMessageHandler類需要我們注意。

WKScriptMessageHandler

A class conforming to the WKScriptMessageHandler protocol provides a method for receiving messages from JavaScript running in a webpage.

其實就是一個遵循的協(xié)議锻霎,他的作用是能把JS的消息發(fā)送給OC

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;

這個協(xié)議中有兩個參數(shù)一個是WKUserContentController著角,一個是WKScriptMessage,WKUserContentController負(fù)責(zé)將WKScriptMessage調(diào)度出來,因此要是實現(xiàn)JS調(diào)用OC旋恼,就要遵循這個協(xié)議并實現(xiàn)這個方法吏口。而且還要將WKUserContentController和WKScriptMessage在初始化時設(shè)置到WKWebViewConfiguration中去。

WKUserContentController

A WKUserContentController object provides a way for JavaScript to post messages and inject user scripts to a web view.

WKUserContentController有兩個核心方法:

//添加JS調(diào)用OC的橋梁冰更,這里的name就是WKScriptMessage中的name产徊。
- (void)addScriptMessageHandler:(id<WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name;
//向請求的頁面中注入JS代碼,如果需要在請求的頁面中加入自己的JS代碼蜀细,用此方法囚痴。
- (void)addUserScript:(WKUserScript *)userScript;

WKScriptMessage

WKScriptMessage就是JS通知OC時候攜帶的數(shù)據(jù),其中常用的屬性有

1.name

//name就是對應(yīng)中的name
- (void)addScriptMessageHandler:(id<WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name;

2.body 攜帶JS傳送的數(shù)據(jù)

WKUserScript

WKUserScript主要作用就是攜帶正確可執(zhí)行的JS代碼然后注入到要請求的webView中审葬,有一個初始化方法

- (instancetype)initWithSource:(NSString *)source injectionTime:(WKUserScriptInjectionTime)injectionTime forMainFrameOnly:(BOOL)forMainFrameOnly;

其中WKUserScriptInjectionTime是個枚舉類型深滚,以供選擇合適執(zhí)行JS代碼奕谭。

typedef enum WKUserScriptInjectionTime : NSInteger {
    WKUserScriptInjectionTimeAtDocumentStart,//開始時注入
    WKUserScriptInjectionTimeAtDocumentEnd  //結(jié)束時注入
} WKUserScriptInjectionTime;

熟悉了以上幾個類,我們就可以初始化一個WKWebView并且配置我們用以O(shè)C和JS交互的一些配置痴荐,在此我使用了懶加載的方式:

- (WKWebView* )wkWebView {
    if (!_wkWebView) {
        WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc]init];
        config.preferences = [[WKPreferences alloc]init];
        config.allowsInlineMediaPlayback = YES;
        config.selectionGranularity = YES;
        //自定義配置血柳,一般用于js調(diào)用oc方法(OC攔截URL中的數(shù)據(jù)做自定義操作)
        WKUserContentController *userContentController = [[WKUserContentController alloc] init];
        [userContentController addScriptMessageHandler:self name:@"backPresent"];
        //JS注入 向網(wǎng)頁中添加自己的JS方法
        NSString *cookie = self.cookies;
        WKUserScript *cookieScript = [[WKUserScript alloc] initWithSource:cookie injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
        [userContentController addUserScript:cookieScript];
        config.userContentController = userContentController;
        
        _wkWebView = [[WKWebView alloc]initWithFrame:CGRectMake(0, NAVI_HEIGHT, self.view.bounds.size.width, self.view.bounds.size.height - NAVI_HEIGHT) configuration:config];
        _wkWebView.navigationDelegate = self;
        _wkWebView.UIDelegate = self;
        //添加此屬性可觸發(fā)側(cè)滑返回上一網(wǎng)頁與下一網(wǎng)頁操作
        _wkWebView.allowsBackForwardNavigationGestures = YES;
        //下拉刷新
        if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 10.0 && _canDownRefresh) {
            _wkWebView.scrollView.refreshControl = self.refreshControl;
        }
        //進度監(jiān)聽
        [_wkWebView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:NULL];
    }
    return _wkWebView;
}

??在這段代碼中,我們首先設(shè)置了WKWebView的基本配置WKWebViewConfiguration生兆,然后再配置WKUserContentController难捌,將我們要JS調(diào)用OC的方法實現(xiàn),如果還需要向JS中注入我們添加的JS方法鸦难,則再配置WKUserScript根吁,完成這些之后,WKWebViewConfiguration配置就基本完成合蔽,然后我們初始化WKWebView并給他一個frame击敌。下面我們再看下WKWebView的兩個代理。
??在使用UIWebView的時候拴事,我們只設(shè)置UIWebViewDelegate就好了沃斤,在這個協(xié)議中包含了很多WebView的方法,包括加載刃宵,加載完成等衡瓶,而在WKWebView中,蘋果將其分解為WKNavigationDelegate和WKUIDelegate兩部分牲证,其實個人感覺這樣分下來更清晰哮针,我們知道一個WebView的組件加載網(wǎng)頁的時候,一般就兩個方面:

1.WebView對于網(wǎng)頁的渲染坦袍,這更多的是體現(xiàn)在UI上的提現(xiàn)诚撵,沒有很多頁面邏輯的處理。
2.WebView對于網(wǎng)頁的加載键闺,包括開始加載,加載完成澈驼,以及OC與JS的交互辛燥,這一層更多的是體現(xiàn)的是原生與Web頁面的交互,包含更多的交互缝其。

基于這兩點挎塌,我們發(fā)現(xiàn)WKUINavigationDelegate和WKUIDelegate這兩個代理很好的將UI和加載交互分開來了,讓我們可以更專注UI和交互不同模塊内边。

WKUINavigationDelegate

這個代理中包含很多方法榴都,我們看下比較常用的。

- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation;

見名知意漠其,這個方法是當(dāng)webView加載web頁面的時候調(diào)用的嘴高。當(dāng)開始加載頁面時竿音,我們可以在這里做想做的操作。

- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation;

與上面方法相反拴驮,當(dāng)頁面加載完成時會調(diào)用此方法春瞬。

- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error;

加載頁面出錯時調(diào)動,我們可以在此做進一步操作套啤,比如重新加載

- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;

這個方法決定返回方法是否允許加載宽气,其中有一個block參數(shù)來決定我們是否允許加載,WKNavigationResponsePolicy是一個枚舉類型

typedef enum WKNavigationResponsePolicy : NSInteger {
    WKNavigationResponsePolicyCancel, // 不允許加載
    WKNavigationResponsePolicyAllow //允許加載
} WKNavigationResponsePolicy; 

WKUIDelegate

這個代理中的方法潜沦,最常用的就是Displaying UI Panels下的這三種提示框的加載:

//加載一個提示框
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler;
//確認(rèn)框
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler;
輸入框
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString *result))completionHandler;

此外還有創(chuàng)建新的WebView和關(guān)閉WebView的方法萄涯,還有關(guān)于ForceTouch的支持方法,在文檔中都有詳細(xì)的說明唆鸡。
了解這些以后涝影,我們就基本可以創(chuàng)建出一個WKWebView,而且能實現(xiàn)與OC與JS的一些交互喇闸,通過設(shè)置他的代理方法來實現(xiàn)加載進度控制等袄琳,不過在WebView中,我們還會有點擊下一頁或者返回上一頁燃乍,或者對于加載一個進度的展示等需求唆樊,這些我們也要考慮在內(nèi)。
我們來看下WKWebView中有哪些屬性和方法刻蟹。

Property

title 標(biāo)題

URL 當(dāng)前url

scrollView

estimatedProgress 加載進度 浮點型

allowsBackForwardNavigationGestures 手勢支持

Method

// HTML加載方法
- (WKNavigation *)loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL;
//重新加載
- (WKNavigation *)reload;
//停止加載
- (void)stopLoading;
//上一頁(不是關(guān)閉)
- (WKNavigation *)goBack;
//下一頁
- (WKNavigation *)goForward;
//加載
- (WKNavigation *)loadRequest:(NSURLRequest *)request;
//執(zhí)行JS方法
- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^)(id, NSError *error))completionHandler;

??我們可以看到WKWebView中的屬性和方法還是很多的逗旁,上面這些方法和屬性平時用到的幾率很大。在屬性中舆瘪,我們看到有個estimatedProgress這個屬性片效,通過這個屬性我們再結(jié)合UIProgressView就能給用戶一個很好的UI展示來展示當(dāng)前頁面的加載進度。此外通過WKWebView的goBack和goForward方法我們可以控制WKWebView的加載上一頁還是下一頁英古,或者是通過stopLoading停止當(dāng)前頁面加載淀衣。還有一個evaluateJavaScript方法,我們可以用來讓webView直行JS代碼召调,這個相比于我們在創(chuàng)建WKWebView時候注入JS代碼有更好的可控性膨桥。

??下面我們說一下如何將estimatedProgress和UIProgressView相結(jié)合做出加載框的效果。我們先想一下唠叛,加載進度要實時展現(xiàn)只嚣,通過獲取這個屬性的值我們就能得到,但要實時展現(xiàn)艺沼,也許你已經(jīng)想到需要用KVO監(jiān)聽這個屬性值的變化册舞,來實時刷新UI,這是一個好的方法障般。

- (UIProgressView* )loadingProgressView {
    if (!_loadingProgressView) {
        _loadingProgressView = [[UIProgressView alloc]initWithFrame:CGRectMake(0, NAVI_HEIGHT, self.view.bounds.size.width, 2)];
        _loadingProgressView.progressTintColor = _loadingProgressColor?_loadingProgressColor:Main_COLOR;
    }
    return _loadingProgressView;
}
//進度監(jiān)聽
        [_wkWebView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:NULL];

監(jiān)聽變化處理

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    if ([keyPath isEqualToString:@"estimatedProgress"]) {
        _loadingProgressView.progress = [change[@"new"] floatValue];
        if (_loadingProgressView.progress == 1.0) {
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(.4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                _loadingProgressView.hidden = YES;
            });
        }
    }
}

??當(dāng)estimatedProgress值不停變化调鲸,我們的progress也不停變化盛杰,當(dāng)progress的值到1.0的時候,說明網(wǎng)頁已經(jīng)加載完成了线得,在這我用了個延時執(zhí)行饶唤,之后讓progress隱藏,然后當(dāng)webView有了新的請求再次加載的時候再讓progress顯示贯钩。

//頁面開始加載
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation{
    webView.hidden = NO;
    _loadingProgressView.hidden = NO;
    if ([webView.URL.scheme isEqual:@"about"]) {
        webView.hidden = YES;
    }
}

??當(dāng)網(wǎng)頁加載時間過久或者沒有網(wǎng)絡(luò)時募狂,給用戶提示當(dāng)前網(wǎng)絡(luò)環(huán)境不好,讓用戶選擇重新加載或者是退出網(wǎng)頁加載角雷。

添加手勢支持

添加對于多網(wǎng)頁連續(xù)加載的上下頁的水平橫掃返回上一頁下一頁的手勢祸穷,需要用到上面我們提到那個allowsBackForwardNavigationGestures這個屬性,我們需要設(shè)置其為YES勺三。這樣當(dāng)我們加載一連續(xù)的頁面時雷滚,可以通過屏幕側(cè)邊欄橫掃進行上一頁下一頁的切換。

添加下拉刷新

剛才我們提到WKWebView還有一個scrowView的屬性吗坚,在scrolView下還有一個在iOS10之后新的屬性是refreshControl祈远,這個屬性當(dāng)我們設(shè)置之后,可以支持下拉刷新操作商源,webView會重新加載车份。這個屬性是UIRefreshControl類,因此我們需要手動設(shè)置一個UIRefreshControl來添加刷新事件,讓webView重新加載牡彻。

- (UIRefreshControl* )refreshControl {
    if (!_refreshControl) {
        _refreshControl = [[UIRefreshControl alloc]init];
        [_refreshControl addTarget:self action:@selector(webViewReload) forControlEvents:UIControlEventValueChanged];
    }
    return _refreshControl;
}
- (void)webViewReload {
    if (_wkWebView.hidden) {
        _wkWebView.hidden = NO;
    }
    [_wkWebView reload];
}

至此我們基本完成了一個WKWebView的封裝扫沼,對于加載一般的網(wǎng)頁,WKWebView還是很好用的庄吼。

總結(jié)

從開始著手寫WKWebView到寫完后形成此文,這期間我也參看了一些資料,不過個人感覺最行之有效的還是通過我們對于需求的分析然后查看Apple的開發(fā)文檔,最詳細(xì)也最權(quán)威,這沒什么好說的,當(dāng)然如果你英文好,自己在看文檔解讀時感受可能會更深,比硬生生的翻譯成中文更能理解其中奧義.當(dāng)然這期間寫的還是比較倉促,代碼中海油很多可優(yōu)化的余地,有更好的思路,還請大家不吝賜教.
最后附上github地址:WHWebView連接地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末缎除,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子总寻,更是在濱河造成了極大的恐慌器罐,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件渐行,死亡現(xiàn)場離奇詭異轰坊,居然都是意外死亡,警方通過查閱死者的電腦和手機殊轴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來袒炉,“玉大人旁理,你說我怎么就攤上這事∥掖牛” “怎么了孽文?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵驻襟,是天一觀的道長。 經(jīng)常有香客問我芋哭,道長沉衣,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任减牺,我火速辦了婚禮豌习,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘拔疚。我一直安慰自己肥隆,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布稚失。 她就那樣靜靜地躺著栋艳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪句各。 梳的紋絲不亂的頭發(fā)上吸占,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天,我揣著相機與錄音凿宾,去河邊找鬼矾屯。 笑死,一個胖子當(dāng)著我的面吹牛菌湃,可吹牛的內(nèi)容都是我干的问拘。 我是一名探鬼主播,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼惧所,長吁一口氣:“原來是場噩夢啊……” “哼骤坐!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起下愈,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤纽绍,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后势似,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拌夏,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年履因,在試婚紗的時候發(fā)現(xiàn)自己被綠了障簿。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡栅迄,死狀恐怖站故,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤西篓,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布愈腾,位于F島的核電站,受9級特大地震影響岂津,放射性物質(zhì)發(fā)生泄漏虱黄。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一吮成、第九天 我趴在偏房一處隱蔽的房頂上張望橱乱。 院中可真熱鬧,春花似錦赁豆、人聲如沸仅醇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽析二。三九已至,卻和暖如春节预,著一層夾襖步出監(jiān)牢的瞬間叶摄,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工安拟, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蛤吓,地道東北人。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓糠赦,卻偏偏與公主長得像会傲,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子拙泽,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,914評論 2 355