iOS中UIScrollView、UIWebView、UICollectionView实现商品详情页图文混排

图文混排

实现思路

  1. 将文本和图片拼接为HTML代码。
  2. 使用JavaScript添加点击事件。
  3. 使用MagicWebViewWebP提供UIWebView加载webp格式图片支持。
  4. 使用UIWebView加载HTML代码。
  5. 使用UIWebView代理方法,拦截页面发出的请求,获取selectIndex。

实现效果

组件 描述 说明
UIScrollView 根容器 高度自适应(KVO处理UIWebView + UICollectionView高度)
UIWebView 图文混排展示 加载HTML代码
UICollectionView 更多推荐展示
实现效果

问题汇总

1、如何实现JavaScript与Objective-C间传值?

点击Webview中的图片,放大,需要JavaScript和Objective-C传值,获取到具体需要放大哪张图片。

本方案中,不需要引入WebViewJavascriptBridge,而是通过【控制Webview重定向方法,拦截发出的请求】来实现。

示例:
// 每个<img>添加点击事件(window.location.href),其中selectIndex为图片标识
<img onload="this.onclick = function() {window.location.href = 'selectIndex=' + 0;}" style="clear:both; display:block; margin:auto;" width="100%" src="https://cdn1.showjoy.com/images/5a/5aa6f5c436754174a114abdb0f1581e0.jpg.webp">

// webview发起请求拦截
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
  
    // 获取img标识index
    NSString *url = request.URL.absoluteString;
    NSRange range = [url rangeOfString:@"selectIndex="];
    if (range.location != NSNotFound) {
        NSInteger begin = range.location + range.length;
        NSString *index = [url substringFromIndex:begin];
        NSLog(@"img: %@", index);
        return NO;
    }
    return YES;
  
}

2、如何实现UIWebView高度自适应?

UIWebView自适应高度的方案有很多,选择一个较为科学的方式,显得尤为重要。

本方案中,通过【KVO监听Webview的contentSize】来实现,需要注意KVO的添加、移除,稍有不慎有Crash风险。

示例:
// 添加监听
[self.webView.scrollView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:nil];

- (UIWebView *)webView
{
    if (!_webView) {
        _webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
        _webView.delegate = self;
        _webView.scrollView.bounces = NO;
        _webView.scrollView.showsHorizontalScrollIndicator = NO;
        _webView.scrollView.scrollEnabled = NO;
        _webView.scalesPageToFit = YES;
    }
    return _webView;
}

// 修改webview的frame
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"contentSize"]) {
        CGSize resize = [self.webView sizeThatFits:CGSizeZero];
        self.webView.frame =  CGRectMake(0, 0, CGRectGetWidth(self.frame), resize.height);
    }
}

// 移除监听
-(void)dealloc
{
    [self.webView.scrollView removeObserver:self forKeyPath:@"contentSize"];
}

3、如何实现UIWebView显示webp格式图片?

UIWebView、WKWebview本身都不支持webp格式图片,需要额外扩展。

可以直接访问我的GitHub,下载MagicWebViewWebP,将【MagicWebViewWebP.framework】直接导入工程。

参考: UIWebView、WKWebView支持WebP图片显示

示例:
// 导入头文件
#import <MagicWebViewWebP/MagicWebViewWebPManager.h>

// 注册 MagicURLProtocol
[[MagicWebViewWebPManager shareManager] registerMagicURLProtocolWebView:self.webView];

// 销毁 MagicURLProtocol
-(void)dealloc
{
    [[MagicWebViewWebPManager shareManager] unregisterMagicURLProtocolWebView:self.webView];
}

4、如何实现图文混排 + UIKit组件?

使用UIWebView加载自定义HTML代码的方式,实现图文混排。
点击图片,放大,function()跳转链接,携带selectIndex标识,通过拦截UIWebView的请求来获取selectIndex标识。

通过KVO获取到WebView高度,重新设置webView.frame,collectionView.frame,scrollView.contentSize

本方案中,图文混排+UIKit组件,具体逻辑如下:

5、如何自定义HTML代码?

本方案中,以纯图片为例,处理后的HTML如下:

<html>
<head>
</head>
<body>
    <div class="img-box">
        <img onload="this.onclick = function() {window.location.href = 'selectIndex=' + 0;}" style="clear:both; display:block; margin:auto;" width="100%" src="https://cdn1.showjoy.com/images/5a/5aa6f5c436754174a114abdb0f1581e0.jpg.webp">
    </div>
    <div class="img-box">
        <img onload="this.onclick = function() {window.location.href = 'selectIndex=' + 1;}" style="clear:both; display:block; margin:auto;" width="100%" src="https://cdn1.showjoy.com/images/d8/d8756f54d7524afba4939e5fab9754d6.jpg.webp">
    </div>
    ......
</body>
</html>

6、如何实现并发执行多个网络请求,统一处理?

本方案中,利用GCD创建队列组,提交多个任务到队列组,多个任务同时执行,监听队列组执行完毕,在主线程刷新UI。

注意: dispatch_group_enter() 、 dispatch_group_leave()将队列组中的任务未执行完毕的任务数目加减1(两个函数要配合使用)

参考: 玩转GCD

示例:
- (void)exampleMoreNetwork{
    
    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t serialQueue = dispatch_queue_create("magic_gcd_group", DISPATCH_QUEUE_SERIAL);
    
    // 网络请求1
    dispatch_group_enter(group);
    dispatch_group_async(group, serialQueue, ^{
        [[MagicNetworkManager shareManager] GET:@"网络请求1" Parameters:nil Success:^(NSURLResponse *response, id responseObject) {
            dispatch_group_leave(group);
        } Failure:^(NSURLResponse *response, id error) {
            dispatch_group_leave(group);
        }];
    });
    
    // 网络请求2
    dispatch_group_enter(group);
    dispatch_group_async(group, serialQueue, ^{
        [[MagicNetworkManager shareManager] GET:@"网络请求2" Parameters:nil Success:^(NSURLResponse *response, id responseObject) {
            dispatch_group_leave(group);
        } Failure:^(NSURLResponse *response, id error) {
            dispatch_group_leave(group);
        }];
    });
    
    // 所有网络请求结束
    dispatch_group_notify(group, serialQueue, ^{
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            dispatch_async(dispatch_get_main_queue(), ^{
                // 主线程刷新UI
            });
        });
    });
    
}

图文混排——核心

目录结构

实现代理方法,放大图片,跳转商品,置顶。
实现针对showjoy.com域名,图片url拼接.webp。
实现UIScrollView作为根容器,自适应内容高度。
实现UIWebView支持webp格式图片。
实现自定义HTML代码,图片居中,window.location.href事件传递selectIndex,UIWebView代理拦截selectIndex。
通过HTML,JavaScript,还可以实现更多功能。。。。。。

ProductLoadMorePicTextView.h
#import <UIKit/UIKit.h>
#import "ProductDetailModel.h"
#import "ProductLoadMorePicTextModel.h"

@protocol ProductLoadMorePicTextViewDelegate <NSObject>
- (void)productLoadMorePicTextViewZoomImageWithIndex:(NSInteger)index;
- (void)productLoadMorePicTextViewPushProductWithSkuId:(NSString *)skuId;
- (void)productLoadMorePicTextViewGoTop;
@end

@interface ProductLoadMorePicTextView : UIView
@property (nonatomic, weak) id <ProductLoadMorePicTextViewDelegate> delegate;
- (instancetype)initWithFrame:(CGRect)frame productDetailModel:(ProductDetailModel *)productDetailModel picTextModel:(ProductLoadMorePicTextModel *)picTextModel;
- (void)reload;
@end
ProductLoadMorePicTextView.m
#import "ProductLoadMorePicTextView.h"
#import "ProductLoadMorePicTextCollectionViewCell.h"
#import "MagicScrollPageRefreshHeader.h"
#import <MagicWebViewWebP/MagicWebViewWebPManager.h>

static const CGFloat recommendViewHeight = 170.0;
static const CGFloat recommendViewSpace = 10.0;
static const CGFloat recommendItemWidth = 105.0;
static const CGFloat recommendItemSpace = 5.0;
static const CGFloat recommendTitleHeight = 40.0;

@interface ProductLoadMorePicTextView ()<UIWebViewDelegate, UICollectionViewDataSource, UICollectionViewDelegate>
@property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) UIWebView *webView;
@property (nonatomic, strong) UICollectionView *collectionView;
@property (nonatomic, strong) UILabel *recommendLabel;
@property (nonatomic, strong) NSMutableArray *recommendDataArray;
@property (nonatomic, strong) NSMutableArray *picTextDataArray;
@end

@implementation ProductLoadMorePicTextView

- (instancetype)initWithFrame:(CGRect)frame productDetailModel:(ProductDetailModel *)productDetailModel picTextModel:(ProductLoadMorePicTextModel *)picTextModel
{
    self = [super initWithFrame:frame];
    if (self) {
        self.recommendDataArray = [NSMutableArray arrayWithArray:productDetailModel.recommend];
        self.picTextDataArray = [NSMutableArray arrayWithArray:picTextModel.itemPic.packageImages];
        [self createSubViewsWithPicTextModel:picTextModel];
    }
    return self;
}

- (void)createSubViewsWithPicTextModel:(ProductLoadMorePicTextModel *)picTextModel
{
    [self addSubview:self.scrollView];
    [[MagicWebViewWebPManager shareManager] registerMagicURLProtocolWebView:self.webView];
    [self.scrollView addSubview:self.webView];
    [self.scrollView addSubview:self.recommendLabel];
    [self.scrollView addSubview:self.collectionView];
    [self.webView.scrollView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:nil];
    
    MC_SELF_WEAK(self)
    MagicScrollPageRefreshHeader *header = [MagicScrollPageRefreshHeader headerWithRefreshingBlock:^{
        [weakself.scrollView.mj_header endRefreshing];
        [weakself executeProductLoadMorePicTextViewGoTop];
    }];
    self.scrollView.mj_header = header;
}

#pragma mark -Lazy
- (UIScrollView *)scrollView
{
    if (!_scrollView) {
        _scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
        _scrollView.backgroundColor = [UIColor colorWithRed:0.95 green:0.95 blue:0.95 alpha:1.00];
    }
    return _scrollView;
}

- (UIWebView *)webView
{
    if (!_webView) {
        _webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
        _webView.delegate = self;
        _webView.scrollView.bounces = NO;
        _webView.scrollView.showsHorizontalScrollIndicator = NO;
        _webView.scrollView.scrollEnabled = NO;
        _webView.scalesPageToFit = YES;
    }
    return _webView;
}

- (UILabel *)recommendLabel{
    if (!_recommendLabel) {
        _recommendLabel = [[UILabel alloc] init];
        _recommendLabel.text = @"   更多推荐";
        _recommendLabel.textColor = [UIColor colorWithRed:0.30 green:0.30 blue:0.30 alpha:1.00];
        _recommendLabel.font = [UIFont systemFontOfSize:12];
        _recommendLabel.backgroundColor = [UIColor whiteColor];
    }
    return _recommendLabel;
}

- (UICollectionView *)collectionView
{
    if (!_collectionView) {
        UICollectionViewFlowLayout *flowLayout = [UICollectionViewFlowLayout new];
        flowLayout.sectionInset = UIEdgeInsetsMake(0, 0, 0, recommendItemSpace);
        flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
        flowLayout.itemSize = CGSizeMake(recommendItemWidth, recommendViewHeight);
        _collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:flowLayout];
        _collectionView.backgroundColor = [UIColor whiteColor];
        _collectionView.delegate = self;
        _collectionView.dataSource = self;
        [_collectionView registerClass:[ProductLoadMorePicTextCollectionViewCell class] forCellWithReuseIdentifier:@"cell"];
    }
    return _collectionView;
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"contentSize"]) {
        CGSize resize = [self.webView sizeThatFits:CGSizeZero];
        self.webView.frame =  CGRectMake(0, 0, CGRectGetWidth(self.frame), resize.height);
        self.recommendLabel.frame = CGRectMake(0, CGRectGetMaxY(self.webView.frame) + recommendViewSpace, CGRectGetWidth(self.frame), recommendTitleHeight);
        self.collectionView.frame = CGRectMake(0, CGRectGetMaxY(self.recommendLabel.frame), CGRectGetWidth(self.frame), recommendViewHeight);
        self.scrollView.contentSize = CGSizeMake(CGRectGetWidth(self.frame), CGRectGetMaxY(self.collectionView.frame) + recommendViewSpace);
    }
}

-(void)dealloc
{
    [[MagicWebViewWebPManager shareManager] unregisterMagicURLProtocolWebView:self.webView];
    [self.webView.scrollView removeObserver:self forKeyPath:@"contentSize"];
    self.scrollView = nil;
    self.webView = nil;
    self.collectionView = nil;
    self.recommendDataArray = nil;
    self.picTextDataArray = nil;
}


#pragma mark - UIWebViewDelegate
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
    return [self handleWebviewEventWithRequest:request];
}

- (void)webViewDidStartLoad:(UIWebView *)webView
{
    
}

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    
}

- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
    NSLog(@"商品详情web错误 %@", error);
}

- (BOOL)handleWebviewEventWithRequest:(NSURLRequest *)request
{
    NSString *url = request.URL.absoluteString;
    NSRange range = [url rangeOfString:@"selectIndex="];
    if (range.location != NSNotFound) {
        NSInteger begin = range.location + range.length;
        NSString *index = [url substringFromIndex:begin];
        [self executeProductLoadMorePicTextViewZoomImageWithIndexString:index];
        return NO;
    }
    return YES;
}

#pragma mark - CustomHTML

- (void)loadWebViewCustomHTMLWithImageUrls:(NSArray *)imageUrls
{
    NSMutableString *html = [NSMutableString string];
    [html appendString:@"<html>"];
    [html appendString:@"<head>"];
    [html appendString:@"</head>"];
    [html appendString:@"<body>"];
    [html appendString:[self settingWebViewBodyWithImageUrlArray:imageUrls]];
    [html appendString:@"</body>"];
    [html appendString:@"</html>"];
    [self.webView loadHTMLString:html baseURL:nil];
}

- (NSString *)settingWebViewBodyWithImageUrlArray:(NSArray *)imageUrlArray
{
    NSMutableString *body = [NSMutableString string];
    for (NSInteger i = 0; i < imageUrlArray.count; i++) {
        NSString *imgUrl = [NSString stringWithFormat:@"%@", [imageUrlArray objectAtIndex:i]];
        imgUrl = [self handlerImgUrlString:imgUrl];
        NSMutableString *html = [NSMutableString string];
        [html appendString:@"<div class=\"img-box\">"];
        NSString *onload = [NSString stringWithFormat:@"this.onclick = function() {window.location.href = 'selectIndex=' + %ld;}", i];
        [html appendFormat:@"<img onload=\"%@\" style=\"clear:both; display:block; margin:auto;\" width=\"100%%\" src=\"%@\">", onload, imgUrl];
        [html appendString:@"</div>"];
        [body appendString:html];
    }
    return body;
}

#pragma mark -UICollectionViewDataSource
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
    return self.recommendDataArray.count;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
    ProductLoadMorePicTextCollectionViewCell *cell = (ProductLoadMorePicTextCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];
    cell.productRecommendModel = [self.recommendDataArray objectAtIndex:indexPath.row];
    return cell;
}

#pragma mark -UICollectionViewDelegate
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
   ProductRecommend *productRecommendModel = [self.recommendDataArray objectAtIndex:indexPath.row];
   [self executeProductLoadMorePicTextViewPushProductWithSkuId:productRecommendModel.ID];
}


#pragma mark -ProductLoadMoreViewDelegate
- (void)executeProductLoadMorePicTextViewZoomImageWithIndexString:(NSString *)indexString
{
    if ([self.delegate respondsToSelector:@selector(productLoadMorePicTextViewZoomImageWithIndex:)]) {
        [self.delegate productLoadMorePicTextViewZoomImageWithIndex:[indexString integerValue]];
    }
}

- (void)executeProductLoadMorePicTextViewPushProductWithSkuId:(NSInteger)skuId
{
    if ([self.delegate respondsToSelector:@selector(productLoadMorePicTextViewPushProductWithSkuId:)]) {
        [self.delegate productLoadMorePicTextViewPushProductWithSkuId:[NSString stringWithFormat:@"%ld", skuId]];
    }
}

- (void)executeProductLoadMorePicTextViewGoTop
{
    if ([self.delegate respondsToSelector:@selector(productLoadMorePicTextViewGoTop)]) {
        [self.delegate productLoadMorePicTextViewGoTop];
    }
}


#pragma mark - Reload
- (void)reload{
    [self loadWebViewCustomHTMLWithImageUrls:self.picTextDataArray];
    [self.collectionView reloadData];
}

#pragma mark - IMGURL
- (NSString *)handlerImgUrlString:(NSString *)imgUrlString
{
    NSString *result = [NetworkManager httpsSchemeHandler:imgUrlString];
    // webp
    if ([result containsString:@"showjoy.com"] && ![result hasSuffix:@".webp"]) {
        result = [result stringByAppendingString:@".webp"];
    }
    return result;
}
@end

图文混排——使用

ProductLoadMoreViewController中,保证两个接口都请求完成后,刷新ProductLoadMorePicTextView。

#import "ProductLoadMoreViewController.h"
#import "MagicNetworkManager.h"
#import "ProductLoadMorePicTextView.h"

static NSString * const SJProductAPI = @"https://shopappserver.showjoy.com/api/shop/sku";
static NSString * const SJProductPicTextAPI = @"https://shopappserver.showjoy.com/api/shop/item/pictext";
static NSString * const SJProductSkuId = @"146931";


@interface ProductLoadMoreViewController () <ProductLoadMorePicTextViewDelegate>

@end

@implementation ProductLoadMoreViewController{
    ProductDetailModel *_productModel;
    ProductLoadMorePicTextModel *_productPicTextModel;
    ProductLoadMorePicTextView *_picTextView;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.view.backgroundColor = [UIColor grayColor];
    [self networkRequestData];
}

#pragma mark - Network
- (void)networkRequestData
{
   [QuicklyHUD showWindowsProgressHUDText:@"加载中..."];
    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t serialQueue = dispatch_queue_create("product_group", DISPATCH_QUEUE_SERIAL);
    
    // 商品信息
    dispatch_group_enter(group);
    dispatch_group_async(group, serialQueue, ^{
        [[MagicNetworkManager shareManager] GET:SJProductAPI Parameters:@{@"skuId" : SJProductSkuId} Success:^(NSURLResponse *response, id responseObject) {
            [ProductDetailModel mj_setupObjectClassInArray:^NSDictionary *{
                return @{@"shop" : [ProductShop class],
                         @"skuList" : [ProductSkuList class],
                         @"value" : [ProductValue class],
                         @"saleInfo" : [ProductSaleInfo class],
                         @"recommend" : [ProductRecommend class],
                         @"skuCommission" : [ProductSkuCommission class],
                         @"item" : [ProductItem class],
                         @"tagSkus" : [ProductTagSkus class],
                         @"tagMap" : [ProductTagMap class],
                         @"skuEnsures" : [ProductSkuEnsures class],
                         @"salesPromotion" : [ProductSalesPromotion class]};
            }];
            _productModel = [ProductDetailModel mj_objectWithKeyValues:[responseObject valueForKey:@"data"]];
            dispatch_group_leave(group);
        } Failure:^(NSURLResponse *response, id error) {
            dispatch_group_leave(group);
        }];
    });
    
    // 图文信息
    dispatch_group_enter(group);
    dispatch_group_async(group, serialQueue, ^{
        [[MagicNetworkManager shareManager] GET:SJProductPicTextAPI Parameters:@{@"skuId" : SJProductSkuId} Success:^(NSURLResponse *response, id responseObject) {
            [ProductLoadMorePicTextModel mj_setupObjectClassInArray:^NSDictionary *{
                return @{@"item" : [PicTextItem class],
                         @"itemPic" : [PicTextItemPic class],
                         @"spu" : [PicTextSpu class]};
            }];
            _productPicTextModel = [ProductLoadMorePicTextModel mj_objectWithKeyValues:[responseObject valueForKey:@"data"]];
            dispatch_group_leave(group);
        } Failure:^(NSURLResponse *response, id error) {
            dispatch_group_leave(group);
        }];
    });
    
    // 主线程刷新UI
    dispatch_group_notify(group, serialQueue, ^{
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            dispatch_async(dispatch_get_main_queue(), ^{
                [QuicklyHUD hiddenMBProgressHUDForView:MC_APP_WINDOW];
                [self reloadPicTextView];
            });
        });
    }); 
}

#pragma mark - Reload
- (void)reloadPicTextView
{
    if (_picTextView) {
        [_picTextView removeFromSuperview];
        _picTextView.delegate = nil;
        _picTextView = nil;
    }
    CGFloat border = 20.0f;
    _picTextView = [[ProductLoadMorePicTextView alloc] initWithFrame:CGRectMake(border, border, MC_SCREEN_W - 2 * border, MC_SCREEN_H - MC_NAVIGATION_BAR_H - MC_STATUS_BAR_H - 2 * border) productDetailModel:_productModel picTextModel:_productPicTextModel];
    _picTextView.delegate = self;
    [self.view addSubview:_picTextView];
    [_picTextView reload];
}

#pragma mark - ProductLoadMorePicTextViewDelegate
- (void)productLoadMorePicTextViewGoTop
{
    [QuicklyHUD showWindowsOnlyTextHUDText:@"Go Top"];
}

- (void)productLoadMorePicTextViewZoomImageWithIndex:(NSInteger)index
{
    [QuicklyHUD showWindowsOnlyTextHUDText:[NSString stringWithFormat:@"img: %ld", index]];
}

- (void)productLoadMorePicTextViewPushProductWithSkuId:(NSString *)skuId
{
    [QuicklyHUD showWindowsOnlyTextHUDText:[NSString stringWithFormat:@"skuId: %@", skuId]];
}
@end

Demo

MagicCubeKit - 实验室 - ProductLoadMoreViewController

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,898评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,401评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,058评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,539评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,382评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,319评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,706评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,370评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,664评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,715评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,476评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,326评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,730评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,003评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,275评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,683评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,877评论 2 335

推荐阅读更多精彩内容