深入折腾 Weex,知乎日报客户端开发

简介: 深入折腾了一下 Weex,做了一个知乎日报的客户端,同时实现了一种目前 Weex 尚未提供的 Native 页面切换思路。
深入折腾了一下 Weex,做了一个知乎日报的客户端,同时实现了一种目前 Weex 尚未提供的 Native 页面切换思路。

最后效果如下:



这个 demo 主要实践 4 件事情:

1. 模块注册
2. 组件注册
2. Native 方法调用
4. Native 页面切换 & 参数传递

整个 app 只有两个页面,都是纯 Weex 编写的,对于第一个页面非常的简单,布局类似于 iOS 的 TableView
<template>
  <scroller>
    <container repeat="{{list}}" news_id="{{news_id}}" onclick="onclick">
      <container class="cell">
        <image class="thumb" src="{{src}}"></image>
        <text class="title">{{title}}</text>
      </container>
      <text class="separator"></text>
    </container>
  </scroller>
</template>

然后我们使用 this.$sendHttp 发起 http 请求,这里知道,Weex 仅仅是一个渲染引擎,对于 http 请求,mtop 请求,甚至图片加载等功能,是需要业务注入实现类的。比如 WeexDemo 里面的 sendHttp 就是注入了 WXStreamModule 模块,然后在实现里面使用了 NSURLConnection,这个设计非常不错,在具体的业务当中,你可以把实现代码替换成任何你想要的 HTTP 库。

[WXSDKEngine registerModule:@"image" withClass:[WXImageModule class]];
[WXSDKEngine registerModule:@"stream" withClass:[WXStreamModule class]];
[WXSDKEngine registerModule:@"event" withClass:[WXEventModule class]];

这就是 Weex 注册模块的原理,其中图片模块是用 SDWebImage 实现的。我们同样也可以将其他的 Native 方法注册到模块里面,例如:

WX_EXPORT_METHOD(@selector(log:));

- (void)log:(NSString *)text {
    NSLog(@"LOG: %@", text);
}

然后在 JavaScript 代码里面只需要用 this.$call("event", "log", "Hello, World!"); 就能在 Native 里面输出 Hello World! 这提供了强大的扩展能力。

首页的展示是较为简单的,用的是 Weex 自带的 ImageText,但是详情页是一个 Web 页面,貌似我还没找到 Weex 提供的 WebView 渲染组件。(但是奇怪的是,我自建 WXWebViewComponent 的时候提示 Duplicated Symbol,难道是还未实现么),所以我们需要自建一个 WXComponent,用于 WebView 渲染。

当然我们也可以使用 Native 代码打开一个 WebView,不过这样显然不如纯 Weex 实现有趣。

#import "WXHtmlNodeComponent.h"
#import <WebKit/WebKit.h>

@interface WXHtmlNodeComponent()

@property (nonatomic, strong) NSString *URL;
@property (nonatomic, strong) NSString *html;
@property (nonatomic, strong) WKWebView *webView;

@end

@implementation WXHtmlNodeComponent

WX_CUSTOM_ATTRIBUTE(url, URL, NSString)
WX_CUSTOM_ATTRIBUTE(html, html, NSString)

+ (Class)viewClass {
    return [WKWebView class];
}

- (void)applyPropertiesToView:(UIView *)view {
    [super applyPropertiesToView:view];
    WKWebView *webView = (WKWebView *)view;
    if (self.html.length > 0) {
        [webView loadHTMLString:self.html baseURL:nil];
    } else if (self.URL.length > 0) {
        [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:self.URL]]];
    }
}

这个 Component 支持 urlhtml 两种 attribute,意味着可以从 url 或者 html 代码渲染他。我们把它注册到 webnode 这个名字上面,就能在详情页使用它了:

<template>
  <container>
    <WebNode url="{{context.url}}" class="webnode"></WebNode>
  </container>
</template>

<script>
  module.exports = {
    data: {
      context: "{{context}}"
    }
  }
</script>

<style>
  .webnode {
    height: 1222;
    flex: 1;
  }
</style>

然后最最关键的事情来了,当用户点击一行的时候,我们要从首页跳到详情页,而这两个页面都是 Weex 的(目前貌似 Weex 没有提供这样的能力)。

但是没有关系,我们有 Module,这里我实现了一套逻辑,包括了本地页面 Push 和 Weex 页面上下文传递逻辑。
- (void)push:(NSDictionary *)params {
    ViewController *controller = [[ViewController alloc] init];
    controller.URL = [NSURL URLWithString:params[@"url"]];
    controller.context = params[@"context"];
    UINavigationController *navigator = [(AppDelegate *)[[UIApplication sharedApplication] delegate] navigator];
    [navigator pushViewController:controller animated:YES];
}

然后在首页 onclick 的时候,只要把 context 带到 Module 里面的 push 方法,往下透传过下一个 Weex 页面,就能完成下个页面的初始化。

onclick: function(e) {
  var news_id = e.target.attr["news_id"];
  var context = this;
  var api = this.api(news_id);
  this.get(api, function(json) {
    var params = {
      url: "next weex url",
      context: {
        url: json.share_url,
        title: json.title
      }
    };
    context.$call("event", "push", params);
  });
}

具体来说,这里面使用了一个数据绑定上面的技巧,我把 weex 页面上的 data 字段放置了一个 "{{context}}"

<script>
  module.exports = {
    data: {
      context: "{{context}}"
    }
  }
</script>

这是一个占位符,会在 Native Code 里面被 Push 传进来的 context 替换(这是一个 NSDictionary),处理的过程只是做一次字符串替换

#import "WXHelper.h"
#import "JSONHelper.h"

@implementation WXHelper

+ (NSString *)scriptWithURL:(NSURL *)URL context:(NSDictionary *)context {
    
    NSString *script = [[NSString alloc] initWithContentsOfURL:URL encoding:NSUTF8StringEncoding error:nil];
    
    if (context == nil || ![context isKindOfClass:[NSDictionary class]]) {
        return script;
    }
    
    return [script stringByReplacingOccurrencesOfString:@"\"{{context}}\""
                                             withString:JSONStringWithObject(context) ?: @""];
}

@end

然后我们的上下文就会被绑定到下一个 weex 页面,其实根据这个思路,我们可以做更多的 Weex 和本地的交互,甚至把它做成 Framework 方便使用。

整个流程如下:

首页 weex 渲染 --> onclick --> module 传递上下文到下一个 weex --> weex 自定义组件 WebView 渲染

以上就是整个 demo 的完整思路。

最后

Weex 的模块注册、组件注册非常的有用,给业务扩展自己的能力,自定义自己的功能提供了强大的基础。
当然也希望 Weex 可以在 Native 交互方面提供更多有用的方法。

目录
相关文章
|
监控 JavaScript 安全
《VitePress 简易速速上手小册》第5章:社交媒体和网络互动(2024 最新版)
《VitePress 简易速速上手小册》第5章:社交媒体和网络互动(2024 最新版)
42 1
|
3月前
|
数据采集 移动开发 前端开发
2023年, 前端路上的开源总结(最新更新)
2023年, 前端路上的开源总结(最新更新)
20 0
|
7月前
|
移动开发 小程序 安全
【 uniapp - 黑马优购 | 开篇】uniapp简介与生产工具的安装使用
【 uniapp - 黑马优购 | 开篇】uniapp简介与生产工具的安装使用
78 0
|
9月前
|
API 开发者
uniapp 微信分享踩坑 onShareAppMessage
uniapp 微信分享踩坑 onShareAppMessage
181 0
|
9月前
|
Web App开发 数据采集 JSON
你必须知道的Chrome插件,大牛都在用!
你必须知道的Chrome插件,大牛都在用!
相亲交友源码,从不断实践中总结出的开发技巧
相亲交友源码,从不断实践中总结出的开发技巧
|
数据安全/隐私保护
从一个BUG聊微信朋友圈设计
最近生活方式发生了一点变化。搬家了,住的地方离公司更近了。 这就让我多了很多的操作空间,比如早上起来跑个步啥的。跑完步还能有点时间写博客,所以紧赶慢赶花了几个早上把这篇很早之前就想写的文章写出来了。 平时也会积累一些写博客的灵感,后面慢慢写吧。 过段时间打算想试试短视频的形式聊一些技术话题或者编程实战,计划中。。。
215 0
|
Web App开发 JavaScript 前端开发
😺我开发了一个Chrome插件,可以在掘金官网里撸猫!还可以实时和铲屎官们聊天
掘金又弄这种整活儿的活动了~~我就喜欢整活儿! 话不多说,先看效果~
310 0
😺我开发了一个Chrome插件,可以在掘金官网里撸猫!还可以实时和铲屎官们聊天
|
开发框架 架构师 程序员
还在“替人打工”?来试试做自己的产品吧! | 开发者必读(014期)
最炫的技术新知、最热门的大咖公开课、最有趣的开发者活动、最实用的工具干货,就在《开发者必读》!
868 0