WebKit框架核心--WKWebView

前言

在前邊一個文章里寫到WKWebView與JS交互去廣告的問題劣挫,故在此專門寫一下WebKit框架的應(yīng)用于解析,網(wǎng)上資源很多东帅,在這里整理一下压固。

在iOS8之前,在應(yīng)用中嵌入網(wǎng)頁通常需要使用UIWebView這樣一個類靠闭,這個類通過URL或者HTML文件來加載網(wǎng)頁視圖帐我,功能十分有限,只能作為輔助嵌入原生應(yīng)用程序中愧膀。雖然UIWebView也可以做原生與JavaScript交互的相關(guān)處理拦键,然而也有很大的局限性,JavaScript要調(diào)用原生方法通常需要約定好協(xié)議之后通過Request來傳遞檩淋。WebKit框架中添加了一些原生與JavaScript交互的方法芬为,增強(qiáng)了網(wǎng)頁視圖與原生的交互能力。并且WebKit框架中采用導(dǎo)航堆棧的模型來管理網(wǎng)頁的跳轉(zhuǎn),開發(fā)者也可以更加容易的控制和管理網(wǎng)頁的渲染媚朦。在這里不再贅述UIWebView的使用方法捡絮。

一、WebKit框架概覽

WebKit框架中涉及的類很多莲镣,框架的設(shè)計十分面向?qū)ο蠛湍K化福稳,開發(fā)者在使用時可以輕松的寫出結(jié)構(gòu)清晰的代碼。在進(jìn)行使用前瑞侮,我們首先應(yīng)該清楚整個框架的結(jié)構(gòu)和開發(fā)思路的圆,下面一張腦圖中基本列出了WebKit框架中所涉及到的所有重要的類以及他們之間的相互關(guān)系:

104532_WAVb_2340880.png

如上圖所示,WebKit框架中最核心的類應(yīng)該屬于WKWebView了半火,這個類專門用來渲染網(wǎng)頁視圖越妈,其他類和協(xié)議都將基于它和服務(wù)于它。

  • WKWebView:網(wǎng)頁的渲染與展示钮糖,通過WKWebViewConfiguration可以進(jìn)行配置梅掠。
  • WKWebViewConfiguration:這個類專門用來配置WKWebView
  • WKPreference:這個類用來進(jìn)行M相關(guān)設(shè)置店归。
  • WKProcessPool:這個類用來配置進(jìn)程池阎抒,與網(wǎng)頁視圖的資源共享有關(guān)。
  • WKUserContentController:這個類主要用來做nativeJavaScript的交互管理消痛。
  • WKUserScript:用于進(jìn)行JavaScript注入且叁。
  • WKScriptMessageHandler:這個類專門用來處理JavaScript調(diào)用native的方法。
  • WKNavigationDelegate:網(wǎng)頁跳轉(zhuǎn)間的導(dǎo)航管理協(xié)議秩伞,這個協(xié)議可以監(jiān)聽網(wǎng)頁的活動逞带。
  • WKNavigationAction:網(wǎng)頁某個活動的示例化對象。
  • WKUIDelegate:用于交互處理JavaScript中的一些彈出框纱新。
  • WKBackForwardList:堆棧管理的網(wǎng)頁列表展氓。
  • WKBackForwardListItem:每個網(wǎng)頁節(jié)點(diǎn)對象。
二脸爱、 使用WKWebViewConfigurationWebView進(jìn)行配置

使用下面的代碼可以創(chuàng)建一個WKWebView視圖遇汞,創(chuàng)建WebView視圖時,需要使用WKWebViewConfiguration來進(jìn)行配置:

 WKWebView * WK;
WKWebViewConfiguration * config = [[WKWebViewConfiguration alloc]init];
WK = [[WKWebView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height-40) configuration:config];
 [WK loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]]];

WKWebViewConfiguration中可以進(jìn)行配置的方法和屬性如下:

 //設(shè)置進(jìn)程池
    WKProcessPool * pool = [[WKProcessPool alloc]init];
    config.processPool = pool;

WKProcessPool類中沒有暴露任何屬性和方法阅羹,配置為同一個進(jìn)程池的WebView會共享數(shù)據(jù)勺疼,例如Cookie、用戶憑證等捏鱼,開發(fā)者可以通過編寫管理類來分配不同維度的WebView在不同進(jìn)程池中。

    //進(jìn)行偏好設(shè)置
    WKPreferences * preference = [[WKPreferences alloc]init];
    //最小字體大小 當(dāng)將javaScriptEnabled屬性設(shè)置為NO時酪耕,可以看到明顯的效果
    preference.minimumFontSize = 0;
    //設(shè)置是否支持javaScript 默認(rèn)是支持的
    preference.javaScriptEnabled = YES;
    //設(shè)置是否允許不經(jīng)過用戶交互由javaScript自動打開窗口
    preference.javaScriptCanOpenWindowsAutomatically = YES;
    config.preferences = preference;

WKPerference實例為WebView提供一個偏好設(shè)置导梆。

    //設(shè)置內(nèi)容交互控制器 用于處理JavaScript與native交互
    WKUserContentController * userController = [[WKUserContentController alloc]init];
    //設(shè)置處理代理并且注冊要被js調(diào)用的方法名稱
    [userController addScriptMessageHandler:self name:@"name"];
    //js注入,注入一個測試方法。
    NSString *javaScriptSource = @"function userFunc(){window.webkit.messageHandlers.name.postMessage( {\"name\":\"HS\"})}";
    WKUserScript *userScript = [[WKUserScript alloc] initWithSource:javaScriptSource injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES];// forMainFrameOnly:NO(全局窗口)看尼,yes(只限主窗口)
    [userController addUserScript:userScript];
    config.userContentController = userController;

WKUserContentController專門用來管理nativeJavaScript的交互行為递鹉,addScriptMessageHandler:name:方法來注冊要被js調(diào)用的方法名稱,之后再JavaScript中使用window.webkit.messageHandlers.name.postMessage()方法來像native發(fā)送消息藏斩,支持OC中字典躏结,數(shù)組,NSNumber等原生數(shù)據(jù)類型狰域,JavaScript代碼中的name要和上面注冊的相同媳拴。在native代理的回調(diào)方法中,會獲取到JavaScript傳遞進(jìn)來的消息兆览,如下:

-(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
    //這里可以獲取到JavaScript傳遞進(jìn)來的消息
}

WKScriptMessage類是JavaScript傳遞的對象實例屈溉,其中屬性如下:

//傳遞的消息主體
@property (nonatomic, readonly, copy) id body;
//傳遞消息的WebView
@property (nullable, nonatomic, readonly, weak) WKWebView *webView;
//傳遞消息的WebView當(dāng)前頁面對象
@property (nonatomic, readonly, copy) WKFrameInfo *frameInfo;
//消息名稱
@property (nonatomic, readonly, copy) NSString *name;

WKUserContentController實例的addUserScript:用于注入JavaScript代碼,后面會專門介紹抬探。

    //設(shè)置數(shù)據(jù)存儲store
    config.websiteDataStore = [WKWebsiteDataStore defaultDataStore];

WebKit框架采用其本身的緩存框架子巾,WKWebsiteDataStore類用來處理數(shù)據(jù)的存儲,其中屬性和方法如下:

@interface WKWebsiteDataStore : NSObject
//獲取默認(rèn)的存儲器 此存儲器為持久性的會被寫入磁盤
+ (WKWebsiteDataStore *)defaultDataStore;
//獲取一個臨時的存儲器
+ (WKWebsiteDataStore *)nonPersistentDataStore;
//存儲器是否是臨時的
@property (nonatomic, readonly, getter=isPersistent) BOOL persistent;
//所有可以存儲的類型
+ (NSSet<NSString *> *)allWebsiteDataTypes;
@end

具體設(shè)置

    //設(shè)置是否將網(wǎng)頁內(nèi)容全部加載到內(nèi)存后再渲染
    config.suppressesIncrementalRendering = NO;
    //設(shè)置HTML5視頻是否允許網(wǎng)頁播放 設(shè)置為NO則會使用本地播放器
    config.allowsInlineMediaPlayback =  YES;
    //設(shè)置是否允許ariPlay播放
    config.allowsAirPlayForMediaPlayback = YES;
    //設(shè)置視頻是否需要用戶手動播放  設(shè)置為NO則會允許自動播放
    config.requiresUserActionForMediaPlayback = NO;
    //設(shè)置是否允許畫中畫技術(shù) 在特定設(shè)備上有效
    config.allowsPictureInPictureMediaPlayback = YES;
    //設(shè)置選擇模式 是按字符選擇 還是按模塊選擇
    /*
    typedef NS_ENUM(NSInteger, WKSelectionGranularity) {
        //按模塊選擇
        WKSelectionGranularityDynamic,
        //按字符選擇
        WKSelectionGranularityCharacter,
    } NS_ENUM_AVAILABLE_IOS(8_0);
    */
    config.selectionGranularity = WKSelectionGranularityCharacter;
    //設(shè)置請求的User-Agent信息中應(yīng)用程序名稱 iOS9后可用
    config.applicationNameForUserAgent = @"HS";
三小压、 WKWebView中的屬性和方法解析

下面列舉了WKWebView中常用的屬性和方法线梗。

//設(shè)置導(dǎo)航代理
@property (nullable, nonatomic, weak) id <WKNavigationDelegate> navigationDelegate;
//設(shè)置UI代理
@property (nullable, nonatomic, weak) id <WKUIDelegate> UIDelegate;
//導(dǎo)航列表
@property (nonatomic, readonly, strong) WKBackForwardList *backForwardList;
//通過url加載網(wǎng)頁視圖
- (nullable WKNavigation *)loadRequest:(NSURLRequest *)request;
//通過文件加載網(wǎng)頁視圖
- (nullable WKNavigation *)loadFileURL:(NSURL *)URL allowingReadAccessToURL:(NSURL *)readAccessURL NS_AVAILABLE(10_11, 9_0);
//通過HTML字符串加載網(wǎng)頁視圖
- (nullable WKNavigation *)loadHTMLString:(NSString *)string baseURL:(nullable NSURL *)baseURL;
//通過data數(shù)據(jù)加載網(wǎng)頁視圖
- (nullable WKNavigation *)loadData:(NSData *)data MIMEType:(NSString *)MIMEType characterEncodingName:(NSString *)characterEncodingName baseURL:(NSURL *)baseURL NS_AVAILABLE(10_11, 9_0);
//渲染導(dǎo)航列表中的某個網(wǎng)頁節(jié)點(diǎn)
- (nullable WKNavigation *)goToBackForwardListItem:(WKBackForwardListItem *)item;
//網(wǎng)頁標(biāo)題
@property (nullable, nonatomic, readonly, copy) NSString *title;
//網(wǎng)頁的url
@property (nullable, nonatomic, readonly, copy) NSURL *URL;
//網(wǎng)頁是否正在加載中
@property (nonatomic, readonly, getter=isLoading) BOOL loading;
//加載進(jìn)度 可以監(jiān)聽這個屬性的值配合UIProgressView來設(shè)計進(jìn)度條
@property (nonatomic, readonly) double estimatedProgress;
//是否全部是安全連接
@property (nonatomic, readonly) BOOL hasOnlySecureContent;
//證書列表
@property (nonatomic, readonly, copy) NSArray *certificateChain;
//是否可以回退
@property (nonatomic, readonly) BOOL canGoBack;
//是否可以前進(jìn)
@property (nonatomic, readonly) BOOL canGoForward;
//回退網(wǎng)頁
- (nullable WKNavigation *)goBack;
//前進(jìn)網(wǎng)頁
- (nullable WKNavigation *)goForward;
//刷新網(wǎng)頁
- (nullable WKNavigation *)reload;
//忽略緩存的刷新
- (nullable WKNavigation *)reloadFromOrigin;
//停止加載
- (void)stopLoading;
//執(zhí)行JavaScript代碼
- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ __nullable)(__nullable id, NSError * __nullable error))completionHandler;
//是否允許右滑返回手勢
@property (nonatomic) BOOL allowsBackForwardNavigationGestures;

WKBackForwardList類為導(dǎo)航管理的網(wǎng)頁列表類,其中屬性方法意義如下:

@interface WKBackForwardList : NSObject
//當(dāng)前所在的網(wǎng)頁節(jié)點(diǎn)
@property (nullable, nonatomic, readonly, strong) WKBackForwardListItem *currentItem;
//前進(jìn)的一個網(wǎng)頁節(jié)點(diǎn)
@property (nullable, nonatomic, readonly, strong) WKBackForwardListItem *forwardItem;
//回退的一個網(wǎng)頁節(jié)點(diǎn)
@property (nullable, nonatomic, readonly, strong) WKBackForwardListItem *backItem;
//獲取某個index的網(wǎng)頁節(jié)點(diǎn)
- (nullable WKBackForwardListItem *)itemAtIndex:(NSInteger)index;
//獲取回退的節(jié)點(diǎn)數(shù)組
@property (nonatomic, readonly, copy) NSArray<WKBackForwardListItem *> *backList;
//獲取前進(jìn)的節(jié)點(diǎn)數(shù)組
@property (nonatomic, readonly, copy) NSArray<WKBackForwardListItem *> *forwardList;
@end

WebKit中怠益,網(wǎng)頁節(jié)點(diǎn)被抽象成為了WKBackForwardListItem類缠导,這個類中封裝的屬性如下:

@interface WKBackForwardListItem : NSObject
//當(dāng)前節(jié)點(diǎn)的URL
@property (readonly, copy) NSURL *URL;
//當(dāng)前節(jié)點(diǎn)的標(biāo)題
@property (nullable, readonly, copy) NSString *title;
//創(chuàng)建此WebView的初始URL
@property (readonly, copy) NSURL *initialURL;
四、 關(guān)于nativeJavaScript交互

WebKit中的nativeJavaScript的交互主要有4類溉痢。

  • JavaScript調(diào)用native方法
    這種方式是由WKUserContentController注冊僻造,并在代理方法中實現(xiàn)的。
  • native調(diào)用JavaScript方法
    這種方式通過WKWebView直接調(diào)用evaluteJavaScript:completionHandler:方法來實現(xiàn)孩饼。
  • JavaScript代碼注入
    這種方式可以在網(wǎng)頁中注入一些自定義的JavaScript代碼髓削,也可以注入自定義的方法,再使用evaluteJavaScript:completionHandler:來調(diào)用方法镀娶。JavaScript代碼的注入也是通過WKUserContentController來完成的立膛,使用addUserScript:方法來注入JavaScript,其中需要通過WKUserScript類來生成要注入的對象梯码,這個類使用如下方法來進(jìn)行實例化:
/*
source為要注入的js代碼
WKUserScriptInjectionTime設(shè)置注入的時機(jī)
forMainFrameOnly參數(shù)設(shè)置是否只在主頁面注入
typedef NS_ENUM(NSInteger, WKUserScriptInjectionTime) {
    //原js代碼運(yùn)行前注入
    WKUserScriptInjectionTimeAtDocumentStart,
    //原js代碼運(yùn)行后注入
    WKUserScriptInjectionTimeAtDocumentEnd
} NS_ENUM_AVAILABLE(10_10, 8_0);

*/
- (instancetype)initWithSource:(NSString *)source injectionTime:(WKUserScriptInjectionTime)injectionTime forMainFrameOnly:(BOOL)forMainFrameOnly;
  • 通過WKUIDelegate來交互
    這種方式主要用于相應(yīng)JavaScript中的彈出框宝泵,后面會詳細(xì)介紹這個協(xié)議。
五轩娶、WKNavagationDelegate中方法解析

WKNavagationDelegate協(xié)議重要有兩個作用儿奶,監(jiān)聽頁面渲染流程與控制頁面跳轉(zhuǎn),其中方法如下:

/*
決定是否響應(yīng)網(wǎng)頁的某個動作鳄抒,例如加載闯捎,回退椰弊,前進(jìn),刷新等瓤鼻,在這個方法中秉版,必須執(zhí)行decisionHandler()代碼塊,并將是否允許這個活動執(zhí)行在block中進(jìn)行傳入
*/
/*
WKNavigationAction是網(wǎng)頁動作的抽象化茬祷,其中封裝了許多行為信息清焕,后面會介紹
WKNavigationActionPolicy為開發(fā)者回執(zhí),枚舉如下:
typedef NS_ENUM(NSInteger, WKNavigationActionPolicy) {
    //取消此次行為
    WKNavigationActionPolicyCancel,
    //允許此次行為
    WKNavigationActionPolicyAllow,
} NS_ENUM_AVAILABLE(10_10, 8_0);
*/
-(void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
    decisionHandler(WKNavigationActionPolicyAllow);
}
//需要響應(yīng)身份驗證時調(diào)用 同樣在block中需要傳入用戶身份憑證
-(void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler{
    //用戶身份信息
    NSURLCredential *newCred = [NSURLCredential credentialWithUser:@""
                                                          password:@""
                                                       persistence:NSURLCredentialPersistenceNone];
    // 為 challenge 的發(fā)送方提供 credential
    [[challenge sender] useCredential:newCred
           forAuthenticationChallenge:challenge];
    completionHandler(NSURLSessionAuthChallengeUseCredential,newCred);
}
//接收到數(shù)據(jù)后是否允許執(zhí)行渲染
/*
其中祭犯,WKNavigationResponse為請求回執(zhí)信息
WKNavigationResponsePokicy為開發(fā)者回執(zhí)秸妥,枚舉如下:
typedef NS_ENUM(NSInteger, WKNavigationResponsePolicy) {
    //取消渲染
    WKNavigationResponsePolicyCancel,
    //允許渲染
    WKNavigationResponsePolicyAllow,
} NS_ENUM_AVAILABLE(10_10, 8_0);
*/
-(void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
    decisionHandler(WKNavigationResponsePolicyAllow);
}
//=====================下面這個協(xié)議方法用于監(jiān)聽流程=========================================
//頁面加載啟動時調(diào)用
-(void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{

}
//當(dāng)主機(jī)接收到的服務(wù)重定向時調(diào)用
-(void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation{

}
//內(nèi)容到達(dá)主機(jī)時調(diào)用
-(void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation{

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

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

}
//主頁數(shù)據(jù)加載發(fā)生錯誤時調(diào)用
-(void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(nonnull NSError *)error{

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

}
六、 WKUIDelegate協(xié)議中方法解析
//創(chuàng)建新的webView時調(diào)用的方法
-(WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures{
    return webView;
}
//關(guān)閉webView時調(diào)用的方法
-(void)webViewDidClose:(WKWebView *)webView{

}
//下面這些方法是交互JavaScript的方法
//JavaScript調(diào)用alert方法后回調(diào)的方法 message中為alert提示的信息 必須要在其中調(diào)用completionHandler()
-(void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler{
    NSLog(@"%@",message);
    completionHandler();
}
//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{
    NSLog(@"%@",message);
    completionHandler(YES);
}
//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{
    NSLog(@"%@",prompt);
    completionHandler(@"123");
}
七筛峭、 拓展

首先,在注冊要被JavaScript調(diào)用的方法時需要設(shè)置代理陪每,在不需要時需要將代理移除影晓,WKUserContentController中也提供了移除這個代理的方法,如果不移除檩禾,將會造成WebView不能釋放挂签。方法如下:

//注冊一個監(jiān)聽方法
- (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name;
//移除一個方法的監(jiān)聽
- (void)removeScriptMessageHandlerForName:(NSString *)name;

同樣與注入JavaScript對應(yīng),也可以將注入的代碼移除盼产,方法如下:

//注入一個JavaScript抽象對象
- (void)addUserScript:(WKUserScript *)userScript;
//移除所有注入
- (void)removeAllUserScripts;

在上面饵婆,經(jīng)常會見到WKNavagationAction這個類,這個類中封裝的是一些頁面活動信息戏售,如下:

@interface WKNavigationAction : NSObject
//原頁面
@property (nonatomic, readonly, copy) WKFrameInfo *sourceFrame;
//目標(biāo)頁面
@property (nullable, nonatomic, readonly, copy) WKFrameInfo *targetFrame;
//請求URL
@property (nonatomic, readonly, copy) NSURLRequest *request;
//活動類型
/*
typedef NS_ENUM(NSInteger, WKNavigationType) {
    //鏈接激活
    WKNavigationTypeLinkActivated,
    //提交操作
    WKNavigationTypeFormSubmitted,
    //前進(jìn)操作
    WKNavigationTypeBackForward,
    //刷新操作
    WKNavigationTypeReload,
    //重提交操作 例如前進(jìn) 后退 刷新
    WKNavigationTypeFormResubmitted,
    //其他類型
    WKNavigationTypeOther = -1,
} NS_ENUM_AVAILABLE(10_10, 8_0);
*/
@property (nonatomic, readonly) WKNavigationType navigationType;
@end
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末侨核,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子灌灾,更是在濱河造成了極大的恐慌搓译,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锋喜,死亡現(xiàn)場離奇詭異些己,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)嘿般,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進(jìn)店門段标,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人炉奴,你說我怎么就攤上這事逼庞。” “怎么了盆佣?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵往堡,是天一觀的道長械荷。 經(jīng)常有香客問我共耍,道長虑灰,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任痹兜,我火速辦了婚禮穆咐,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘字旭。我一直安慰自己对湃,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布遗淳。 她就那樣靜靜地躺著拍柒,像睡著了一般。 火紅的嫁衣襯著肌膚如雪屈暗。 梳的紋絲不亂的頭發(fā)上拆讯,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天,我揣著相機(jī)與錄音养叛,去河邊找鬼种呐。 笑死,一個胖子當(dāng)著我的面吹牛弃甥,可吹牛的內(nèi)容都是我干的爽室。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼淆攻,長吁一口氣:“原來是場噩夢啊……” “哼阔墩!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起瓶珊,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤轰绵,失蹤者是張志新(化名)和其女友劉穎拧廊,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡喷兼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了趾痘。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片逆济。...
    茶點(diǎn)故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖绊汹,靈堂內(nèi)的尸體忽然破棺而出稽屏,到底是詐尸還是另有隱情,我是刑警寧澤西乖,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布狐榔,位于F島的核電站坛增,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏薄腻。R本人自食惡果不足惜收捣,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望庵楷。 院中可真熱鬧罢艾,春花似錦、人聲如沸尽纽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽弄贿。三九已至春锋,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間差凹,已是汗流浹背期奔。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留直奋,地道東北人能庆。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像脚线,于是被迫代替她去往敵國和親搁胆。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評論 2 354

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