iOS之OC與JS交互(WKWebView)

前言

最近項(xiàng)目開發(fā)中用到了OC與JS交互方面的知識(shí)幽钢,以前也用過UIWebView JS與OC交互方面的班眯,使用的蘋果在iOS7開放的javascriptCore框架,使用起來挺方便快捷,javascriptCore源碼是開放的,有興趣的可以去了解一下梦碗。

自從iOS8,蘋果就UIWebView性能不好,推出了WKWebView蓖救,以及github上評(píng)分很高的WebViewJavascriptBridge里面最新版本也最WKWebView做了兼容叉弦。

實(shí)現(xiàn)的方式

所以我總結(jié)的方式,分UIWebview藻糖、WKWebView、以及通用版本的第三方WebViewJavascriptBridge库车,進(jìn)行實(shí)現(xiàn)巨柒。

  • UIWebView中JS與OC交互
  • WKWebView中JS與OC交互(只能iOS8及之后的版本)
  • WebViewJavascriptBridge對(duì)UIWebView與WKWebView做了統(tǒng)一處理。

WKWebView出現(xiàn)背景和優(yōu)點(diǎn)

UIWebView自iOS2就有柠衍,WKWebView從iOS8才有洋满,毫無疑問WKWebView將逐步取代笨重的UIWebView。

通過簡單的測試即可發(fā)現(xiàn)UIWebView占用過多內(nèi)存珍坊,且內(nèi)存峰值更是夸張牺勾。WKWebView網(wǎng)頁加載速度也有提升,但是并不像內(nèi)存那樣提升那么多

下面列舉一些其它的優(yōu)勢(shì):

  • 更多的支持HTML5的特性

  • 官方宣稱的高達(dá)60fps的滾動(dòng)刷新率以及內(nèi)置手勢(shì)

  • Safari相同的JavaScript引擎

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

  • 另外用的比較多的阵漏,增加加載進(jìn)度屬性:estimatedProgress

了解WKWebView要涉及一些類

首頁使用WKWebView要引進(jìn):

#import <WebKit/WebKit.h>
  • WKWebView使用
//初始化
self.webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT) configuration:config];

// UI代理
self.webView.UIDelegate = self;

// 導(dǎo)航代理        self.webView.navigationDelegate = self;

// 是否允許手勢(shì)左滑返回上一級(jí), 類似導(dǎo)航控制的左滑返回   self.webView.allowsBackForwardNavigationGestures = YES;

//可返回的頁面列表, 存儲(chǔ)已打開過的網(wǎng)頁 
WKBackForwardList * backForwardList = [self.webView backForwardList];

 //頁面后退
 [self.webView goBack];
 
 //頁面前進(jìn)
 [self.webView goForward];
 
 //刷新當(dāng)前頁面
 [self.webView reload];
 
 //加載本地的html
 NSString *path = [[[NSBundle mainBundle] bundlePath]  stringByAppendingPathComponent:@"test.html"];
 
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL fileURLWithPath:path]];
[self.webView loadRequest:request];
    
  • WKWebViewConfiguration:為添加WKWebView配置信息
//創(chuàng)建網(wǎng)頁配置對(duì)象
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
        
// 創(chuàng)建設(shè)置對(duì)象
WKPreferences *preference = [[WKPreferences alloc]init];

//最小字體大小 當(dāng)將javaScriptEnabled屬性設(shè)置為NO時(shí)驻民,可以看到明顯的效果
preference.minimumFontSize = 0;

//設(shè)置是否支持javaScript 默認(rèn)是支持的
preference.javaScriptEnabled = YES;

// 在iOS上默認(rèn)為NO,表示是否允許不經(jīng)過用戶交互由javaScript自動(dòng)打開窗口        
preference.javaScriptCanOpenWindowsAutomatically = YES;
config.preferences = preference;
        
// 是使用h5的視頻播放器在線播放, 還是使用原生播放器全屏播放
config.allowsInlineMediaPlayback = YES;
        
//設(shè)置視頻是否需要用戶手動(dòng)播放  設(shè)置為NO則會(huì)允許自動(dòng)播放
config.requiresUserActionForMediaPlayback = YES;
       
//設(shè)置是否允許畫中畫技術(shù) 在特定設(shè)備上有效
config.allowsPictureInPictureMediaPlayback = YES;

//設(shè)置請(qǐng)求的User-Agent信息中應(yīng)用程序名稱 iOS9后可用
config.applicationNameForUserAgent = @"ChinaDailyForiPad";

//自定義的WKScriptMessageHandler 是為了解決內(nèi)存不釋放的問題
WeakWebViewScriptMessageDelegate *weakScriptMessageDelegate = [[WeakWebViewScriptMessageDelegate alloc] initWithDelegate:self];

//這個(gè)類主要用來做native與JavaScript的交互管理
WKUserContentController * wkUController = [[WKUserContentController alloc] init];

//注冊(cè)一個(gè)name為jsToOcNoPrams的js方法
[wkUController addScriptMessageHandler:weakScriptMessageDelegate name:@"js調(diào)用OC的方法"];

[wkUController addScriptMessageHandler:weakScriptMessageDelegate name:@"js調(diào)用OC的方法"]; 

config.userContentController = wkUController;
       
  • WKUserScript:用于進(jìn)行JavaScript注入
//以下代碼適配文本大小履怯,由UIWebView換為WKWebView后回还,會(huì)發(fā)現(xiàn)字體小了很多,這應(yīng)該是WKWebView與html的兼容問題叹洲,解決辦法是修改原網(wǎng)頁柠硕,要么我們手動(dòng)注入JS

NSString *jSString = @"var meta = document.createElement('meta'); 
meta.setAttribute('name', 'viewport'); 
meta.setAttribute('content', 
'width=device-width'); 
document.getElementsByTagName('head')
[0].appendChild(meta);";

//用于進(jìn)行JavaScript注入
WKUserScript *wkUScript = [[WKUserScript alloc] initWithSource:jSString 
injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];

[config.userContentController addUserScript:wkUScript];

  • WKUserContentController:這個(gè)類主要用來做native與JavaScript的交互管理
 //這個(gè)類主要用來做native與JavaScript的交互管理
WKUserContentController * wkUController = [[WKUserContentController alloc] init];

//注冊(cè)一個(gè)name為jsToOcNoPrams的js方法,設(shè)置處理接收J(rèn)S方法的代理
[wkUController addScriptMessageHandler:self  name:@"jsCallOCNoPrams"];
[wkUController addScriptMessageHandler:self  name:@"jsCallOCNoPrams"];
config.userContentController = wkUController;

//用完記得移除
//移除注冊(cè)的js方法,避免內(nèi)存泄露
[[self.webView configuration].userContentController 
removeScriptMessageHandlerForName:@"jsToOcNoPrams"];

[[self.webView configuration].userContentController 
removeScriptMessageHandlerForName:@"jsToOcWithPrams"];

  • WKScriptMessageHandler:這個(gè)協(xié)議類專門用來處理監(jiān)聽JavaScript方法從而調(diào)用原生OC方法运提,和WKUserContentController搭配使用蝗柔。
注意:遵守WKScriptMessageHandler協(xié)議闻葵,代理是由WKUserContentControl設(shè)置

//通過接收J(rèn)S傳出消息的name進(jìn)行捕捉的回調(diào)方法
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {

    /*
     message.body: 觸發(fā)js方法傳的值
     message.name: 觸發(fā)js的方法名
    */
    NSLog(@"傳的值L: --%@ \n 方法名: --- %@",message.body, message.name);
}

  • WKNavigationDelegate :主要處理一些跳轉(zhuǎn)、加載處理操作
// 頁面開始加載時(shí)調(diào)用
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
}

// 頁面加載失敗時(shí)調(diào)用
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error {
   
} 

// 當(dāng)內(nèi)容開始返回時(shí)調(diào)用
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation {
}

// 頁面加載完成之后調(diào)用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
   
}

//提交發(fā)生錯(cuò)誤時(shí)調(diào)用
- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error {
    
}  

// 接收到服務(wù)器跳轉(zhuǎn)請(qǐng)求即服務(wù)重定向時(shí)之后調(diào)用
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation {
}

// 根據(jù)WebView對(duì)于即將跳轉(zhuǎn)的HTTP請(qǐng)求頭信息和相關(guān)信息來決定是否跳轉(zhuǎn)
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    
}
    
// 根據(jù)客戶端受到的服務(wù)器響應(yīng)頭以及response相關(guān)信息來決定是否可以跳轉(zhuǎn)
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler {

    NSString * urlStr = navigationResponse.response.URL.absoluteString;
    NSLog(@"當(dāng)前跳轉(zhuǎn)地址:%@",urlStr);
    //允許跳轉(zhuǎn)    
    decisionHandler(WKNavigationResponsePolicyAllow);
    
    //不允許跳轉(zhuǎn)
    decisionHandler(WKNavigationResponsePolicyCancel);
} 

//進(jìn)程被終止時(shí)調(diào)用
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView {

}
  • WKUIDelegate :主要處理JS腳本癣丧,確認(rèn)框槽畔,警告框等
/**
     *  web界面中有彈出警告框時(shí)調(diào)用
     *
     *  @param webView           實(shí)現(xiàn)該代理的webview
     *  @param message           警告框中的內(nèi)容
     *  @param completionHandler 警告框消失調(diào)用
     */
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"HTML的彈出框" message:message?:@"" preferredStyle:UIAlertControllerStyleAlert];
    [alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler();
    }])];
    [self presentViewController:alertController animated:YES completion:nil];
}
    // 確認(rèn)框
    //JavaScript調(diào)用confirm方法后回調(diào)的方法 confirm是js中的確定框,需要在block中把用戶選擇的情況傳遞進(jìn)去
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler{
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"" message:message?:@"" preferredStyle:UIAlertControllerStyleAlert];
    [alertController addAction:([UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
        completionHandler(NO);
    }])];
    [alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler(YES);
    }])];
    [self presentViewController:alertController animated:YES completion:nil];
}
    // 輸入框
    //JavaScript調(diào)用prompt方法后回調(diào)的方法 prompt是js中的輸入框 需要在block中把用戶輸入的信息傳入
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler{
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:prompt message:@"" preferredStyle:UIAlertControllerStyleAlert];
    [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        textField.text = defaultText;
    }];
    [alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler(alertController.textFields[0].text?:@"");
    }])];
    [self presentViewController:alertController animated:YES completion:nil];
}
    // 頁面是彈出窗口 _blank 處理
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures {
    if (!navigationAction.targetFrame.isMainFrame) {
        [webView loadRequest:navigationAction.request];
    }
    return nil;
}

  • 網(wǎng)頁內(nèi)容加載進(jìn)度條和title的實(shí)現(xiàn)坎缭,使用KVO
//添加監(jiān)測網(wǎng)頁加載進(jìn)度的觀察者
    [self.webView addObserver:self
                   forKeyPath:@"estimatedProgress"
                      options:0
                      context:nil];
   //添加監(jiān)測網(wǎng)頁標(biāo)題title的觀察者
    [self.webView addObserver:self
                   forKeyPath:@"title"
                      options:NSKeyValueObservingOptionNew
                      context:nil];

   //kvo 監(jiān)聽進(jìn)度 必須實(shí)現(xiàn)此方法
-(void)observeValueForKeyPath:(NSString *)keyPath
                     ofObject:(id)object
                       change:(NSDictionary<NSKeyValueChangeKey,id> *)change
                      context:(void *)context{
    if ([keyPath isEqualToString:NSStringFromSelector(@selector(estimatedProgress))]
        && object == self.webView) {
        
       NSLog(@"網(wǎng)頁加載進(jìn)度 = %f",_webView.estimatedProgress);
       self.progressView.progress = self.webView.estimatedProgress;
       
       if (self.webView.estimatedProgress >= 1.0f) {
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                self.progressView.progress = 0;
            });
       } 
    }else if([keyPath isEqualToString:@"title"]
             && object == self.webView){
        self.navigationItem.title = self.webView.title;
    }else{
        [super observeValueForKeyPath:keyPath
                             ofObject:object
                               change:change
                              context:context];
    }
}

 //移除觀察者,不然會(huì)引起崩潰
- (void)dealloc {
   
[self.webView removeObserver:self forKeyPath:@"estimatedProgress"];
[self.webView removeObserver:self forKeyPath:@"title"];

}
                  

WKWebView的JS和OC的交互

首先要遵守 WKScriptMessageHandler協(xié)議, WKNavigationDelegate,WKUIDelegate 代理

  • WKScriptMessageHandler協(xié)議 專門用來處理監(jiān)聽JavaScript方法從而調(diào)用原生OC方法
  • WKNavigationDelegate 主要處理一些跳轉(zhuǎn)竟痰、加載處理操作
  • WKUIDelegate 回?cái)r截alert、confirm掏呼、prompt三種js彈框
JS方法 WKUIDelegate方法
alert(message) -webView: runJavaScriptAlertPanelWithMessage: initiatedByFrame:completionHandler:
confirm(message) -webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:
prompt(prompt, defaultText) webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:completionHandler:

注意:WKUIDelegate中的三個(gè)方法都有completionHandlerblock參數(shù)坏快,在iOS實(shí)現(xiàn)對(duì)應(yīng)的功能后必須調(diào)用此block完成回調(diào),否則會(huì)崩潰

其次初始化WKWebView設(shè)置這兩個(gè)WKUIDelegate憎夷、WKNavigationDelegate


//webview添加配置
[self configWKWebView];

 //加載本地的html
NSString *path = [[[NSBundle mainBundle] bundlePath]  stringByAppendingPathComponent:@"test.html"];

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL fileURLWithPath:path]];
[self.webView loadRequest:request];

給WKWebView添加配置

//給wkwebview添加配置
- (void)configWKWebView {
    
    WKWebViewConfiguration *config = [WKWebViewConfiguration new];
    //JS調(diào)用OC方法
    // WKScriptMessageHandler:這個(gè)協(xié)議類專門用來處理監(jiān)聽JavaScript方法從而調(diào)用原生OC方法
    [config.userContentController addScriptMessageHandler:self name:@"getUserIdFromOC"];
    
    
    self.webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height) 
    configuration:config];
     self.webView.UIDelegate = self;
    self.webView.navigationDelegate = self;
    [self.view addSubview:self.webView];
    
}

OC調(diào)用JS

當(dāng)webview加載完成時(shí)候莽鸿,再使用OC調(diào)用JS

- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
    
    //OC調(diào)用JS
    [self getParamsFromOC];
}

- (void)getParamsFromOC {
    
    //js的方法名和參數(shù),把OC的userId傳到j(luò)s里
    NSString *js = @"getParamsFromOC('張三','18歲')";
    
    [self.webView evaluateJavaScript:js completionHandler:^(id _Nullable response, NSError * _Nullable error) {
        
        //當(dāng)js里面的方法有返回值時(shí)候,response就會(huì)有值拾给,沒有為null
        NSLog(@"response: %@ error: %@", response, error);
    }];
}

我把JS里面主要的代碼寫出來, 在<script></script>

function getParamsFromOC(responseData1,responseData2) {
                    
    alert(responseData1+responseData2);
    //有返回值
    return {'userId':'123456'};
}

getParamsFromOC這個(gè)方法名就是OC調(diào)用JS的方法名字祥得,傳了兩個(gè)參數(shù)值張三、18歲
return {'userId':'123456'};有返回值的情況下蒋得,在evaluateJavaScript:js completionHandler: 打印response數(shù)據(jù):

response: {
    userId = 123456;
}

如果沒有return级及,默認(rèn)是return null;额衙,所以打印為null

JS調(diào)用OC

下面這個(gè)方法就是調(diào)用JS的getUserIdFromOC方法

//相當(dāng)于注冊(cè)js的方法
[config.userContentController 
addScriptMessageHandler:self name:@"getUserIdFromOC"];

在H5頁面的body里添加一個(gè)button饮焦,點(diǎn)擊事件

<input type="button" value="WKWebView調(diào)用OC方法" 
onclick="getUserIdFromOC({'userId':'123456'});"/>

在Html中 在<script></script>中添加方法


function getUserIdFromOC(responseData) {
                        
    //WKWebView調(diào)用oc方法,規(guī)定的寫法
    window.webkit.messageHandlers.
    getUserIdFromOC.postMessage(responseData);
}
 

PS:window.webkit.messageHandlers.
方法名.postMessage()這個(gè)是WKWebView的統(tǒng)一寫法窍侧。這樣的話县踢,JS就調(diào)用了OC的方法

JS調(diào)用了OC的方法,會(huì)觸發(fā)下面WKScriptMessageHandler協(xié)議方法

//WKScriptMessageHandler 協(xié)議
- (void)userContentController:(nonnull WKUserContentController *)userContentController didReceiveScriptMessage:(nonnull WKScriptMessage *)message {
    
    /*
     message.body: 觸發(fā)js方法傳的值
     message.name: 觸發(fā)js的方法名
     */
    NSLog(@"傳的值L: --%@ \n 方法名: --- %@",message.body, message.name);
    //如果是JS的這個(gè)getUserIdFromOC方法
    if ([message.name isEqualToString:@"getUserIdFromOC"]) {
        
        NSLog(@"調(diào)用%@成功伟件,傳的值:%@",message.name, message.body);
        //對(duì)這個(gè)方法進(jìn)行處理操作
    }
}

點(diǎn)擊heml的按鈕硼啤,觸發(fā)OC的方法,打印結(jié)果如下:

調(diào)用getUserIdFromOC成功斧账,傳的值:{
    userId = 123456;
}

所以在WKWebView中OC與JS交互的整個(gè)流程已經(jīng)完畢谴返。

結(jié)尾

WKWebView是iOS8之后才出現(xiàn)的,使用了
所以要適配iOS8之前的咧织,針對(duì)系統(tǒng)判斷來進(jìn)行用UIWebView還是WKWebView進(jìn)行OC與JS交互】髁現(xiàn)在蘋果已經(jīng)XCode已經(jīng)不針對(duì)iOS8一下的進(jìn)行適配,所以大家盡量使用WKWebView來做處理拯爽。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末索抓,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌逼肯,老刑警劉巖耸黑,帶你破解...
    沈念sama閱讀 211,639評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異篮幢,居然都是意外死亡大刊,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門三椿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來缺菌,“玉大人,你說我怎么就攤上這事搜锰“橛簦” “怎么了?”我有些...
    開封第一講書人閱讀 157,221評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵蛋叼,是天一觀的道長焊傅。 經(jīng)常有香客問我,道長狈涮,這世上最難降的妖魔是什么狐胎? 我笑而不...
    開封第一講書人閱讀 56,474評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮歌馍,結(jié)果婚禮上握巢,老公的妹妹穿的比我還像新娘。我一直安慰自己松却,他們只是感情好镜粤,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著玻褪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪公荧。 梳的紋絲不亂的頭發(fā)上带射,一...
    開封第一講書人閱讀 49,816評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音循狰,去河邊找鬼窟社。 笑死,一個(gè)胖子當(dāng)著我的面吹牛绪钥,可吹牛的內(nèi)容都是我干的灿里。 我是一名探鬼主播,決...
    沈念sama閱讀 38,957評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼程腹,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼匣吊!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,718評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤色鸳,失蹤者是張志新(化名)和其女友劉穎社痛,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體命雀,經(jīng)...
    沈念sama閱讀 44,176評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蒜哀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吏砂。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片撵儿。...
    茶點(diǎn)故事閱讀 38,646評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖狐血,靈堂內(nèi)的尸體忽然破棺而出淀歇,到底是詐尸還是另有隱情,我是刑警寧澤氛雪,帶...
    沈念sama閱讀 34,322評(píng)論 4 330
  • 正文 年R本政府宣布房匆,位于F島的核電站,受9級(jí)特大地震影響报亩,放射性物質(zhì)發(fā)生泄漏浴鸿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評(píng)論 3 313
  • 文/蒙蒙 一弦追、第九天 我趴在偏房一處隱蔽的房頂上張望岳链。 院中可真熱鬧,春花似錦劲件、人聲如沸掸哑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽苗分。三九已至,卻和暖如春牵辣,著一層夾襖步出監(jiān)牢的瞬間摔癣,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評(píng)論 1 266
  • 我被黑心中介騙來泰國打工纬向, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留择浊,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,358評(píng)論 2 360
  • 正文 我出身青樓逾条,卻偏偏與公主長得像琢岩,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子师脂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評(píng)論 2 348

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