百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

可能是史上最全的weex踩坑攻略

toyiye 2024-06-06 22:12 15 浏览 0 评论

> 这是一篇有故事的文章 --- 来自一个weex在生产环境中相爱相杀的小码畜..故事一: Build

虽然

weex

的口号是

一次撰写 多端运行

, 但其实

build

环节是有差异的,

native

端构建需要使用

weex-loader

, 而

web

端则是使用

vue-loader

,除此以外还有不少差异点, 所以

webpack

需要两套配置.

最佳实践

使用

webpack

生成两套

bundle

,一套是基于

vue-router

web spa

, 另一套是

native

端的多入口的

bundlejs

首先假设我们在

src/views

下开发了一堆页面

build web配置

web端的入口文件有

render.js

import weexVueRenderer from 'weex-vue-render'Vue.use(weexVueRenderer)

main.js

import App from './App.vue'import VueRouter from 'vue-router'import routes from './routes'Vue.use(VueRouter)

App.vue

<template>

webpack.prod.conf.js

入口

const webConfig = merge(getConfig('vue'), {

build native配置

native端的打包流程其实就是将

src/views

下的每个

.vue

文件导出为一个个单独的

vue

实例, 写一个

node

脚本即可以实现

// build-entry.js
// build-entry.js require('shelljs/global') const path = require('path') const fs = require('fs-extra') const srcPath = path.resolve(__dirname, '../src/views') // 每个.vue页面 const entryPath = path.resolve(__dirname, '../entry/') // 存放入口文件的文件夹 const FILE_TYPE = '.vue' const getEntryFileContent = path => { return `// 入口文件 import App from '${path}${FILE_TYPE}' /* eslint-disable no-new */ new Vue({ el: '#root', render: h => h(App) }) ` } // 导出方法 module.exports = _ => { // 删除原目录 rm('-rf', entryPath) // 写入每个文件的入口文件 fs.readdirSync(srcPath).forEach(file => { const fullpath = path.resolve(srcPath, file) const extname = path.extname(fullpath) const name = path.basename(file, extname) if (fs.statSync(fullpath).isFile() && extname === FILE_TYPE) { //写入vue渲染实例 fs.outputFileSync(path.resolve(entryPath, name + '.js'), getEntryFileContent('../src/views/' + name)) } }) const entry = {} // 放入多个entry fs.readdirSync(entryPath).forEach(file => { const name = path.basename(file, path.extname(path.resolve(entryPath, file))) entry[name] = path.resolve(entryPath, name + '.js') }) return entry }

webpack.build.conf.js

中生成并打包多入口

const buildEntry = require('./build_entry') // .. // weex配置 const weexConfig = merge(getConfig('weex'), { entry: buildEntry(), // 写入多入口 output: { path: path.resolve(distPath, './weex'), filename: 'js/[name].js' // weex环境无需使用hash名字 }, module: { rules: [ { test: /\.vue$/, loader: 'weex-loader' } ] } }) module.exports = [webConfig, weexConfig]

最终效果

故事二: 使用预处理器

vue

单文件中, 我们可以通过在

vue-loader

中配置预处理器, 代码如下

{ test: /\.vue$/, loader: 'vue-loader', options: { loaders: { scss: 'vue-style-loader!css-loader!sass-loader', // <style> sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax' // <style> } } }

weex

在native环境下其实将

css

处理成

json

加载到模块中, 所以...

  • 使用

    vue-loader

    配置的预处理器在web环境下正常显示, 在

    native

    中是无效的

  • native环境下不存在全局样式, 在js文件中

    import 'index.css'

    也是无效的

解决问题一

研究

weex-loader

源码后发现在

.vue

中是无需显示配置

loader

的, 只需要指定

<style>

并且安装

stylus stylus-loader

即可,

weex-loader

会根据

lang

去寻找对应的

loader

. 但因为

scss

使用

sass-loader

, 会报出

scss-loader not found

, 但因为

sass

默认会解析

scss

语法, 所以直接设置

lang="sass"

是可以写

scss

语法的, 但是

ide

就没有语法高亮了. 可以使用如下的写法

<style> @import './index.scss' </style>

语法高亮, 完美!

解决问题二

虽然没有全局样式的概念, 但是支持单独

import

样式文件

<style lang="sass">

故事三: 样式差异

这方面官方文档已经有比较详细的描述, 但还是有几点值得注意的

简写

weex

中的样式不支持简写, 所有类似

margin: 0 0 10px 10px

的都是不支持的

背景色

android

下的view是有白色的默认颜色的, 而iOS如果不设置是没有默认颜色的, 这点需要注意

浮点数误差

weex

默认使用

750px * 1334px

作为适配尺寸, 实际渲染时由于浮点数的误差可能会存在几

px

的误差, 出现细线等样式问题, 可以通过加减几个

px

来调试

嵌套写法

即使使用了预处理器,

css

嵌套的写法也是会导致样式失效的

故事四: 页面跳转

weex

下的页面跳转有三种形式

  • native -> weex

    :

    weex

    页面需要一个控制器作为容器, 此时就是

    native

    间的跳转

  • weex -> native

    : 需要通过module形式通过发送事件到native来实现跳转

  • weex -> weex

    : 使用navigator模块, 假设两个

    weex

    页面分别为

    a.js, b.js

    , 可以定义

    mixin

    方法

     function isWeex () { return process.env.COMPILE_ENV === 'weex' // 需要在webpack中自定义

    这样就组件里使用

    this.push(url), this.pop()

    来跳转

跳转配置

  1. iOS下页面跳转无需配置, 而

    android

    是需要的, 使用

    weexpack platform add android

    生成的项目是已配置的, 但官方的文档里并没有对于已存在的应用如何接入进行说明

  • 其实

    android

    中是通过

    intent-filter

    来拦截跳转的

     <activity
  • 然后我们新建一个

    WXPageActivity

    来代理所有

    weex

    页面的渲染, 核心的代码如下

     [@Override](/user/Override) protected void onCreate(Bundle saveInstanceState) { // ...

顺便说下...

weex

官方没有提供可定制的

nav

组件真的是很不方便..经常需要通过

module

桥接

native

来实现跳转需求

来自@荔枝我大哥 的补充

安卓和苹果方面可以在原生代码接管`navigator`这个模块,安卓方面只需要实现`IActivityNavBarSetter`,苹果方面好像是`WXNavigatorProtocol`,然后在app启动初始化weex时注册即可。

故事五: 页面间数据传递

  • native -> weex

    : 可以在

    native

    端调用

    render

    时传入的

    option

    中自定义字段, 例如

    NSDictary *option = @{@"params": @{}}

    , 在

    weex

    中使用

    weex.config.params

    取出数据

  • weex -> weex

    : 使用storage

  • weex -> native

    : 使用自定义module

故事六: 图片加载

官网有提到如何加载网络图片 但是加载本地图片的行为对于三端肯定是不一致的, 也就意味着我们得给

native

重新改一遍引用图片的路径再打包...

但是当然是有解决办法的啦

  • Step 1

    webpack

    设置将图片资源单独打包, 这个很easy, 此时

    bundleJs

    访问的图片路径就变成了

    /images/..

 {
  • Step 2 那么现在我们将同级目录下的js文件夹与images文件夹放入

    native

    中, iOS中一般放入

    mainBundle

    , Android一般放入

    src/main/assets

    , 接下来只要在

    imgloader

    接口中扩展替换本地资源路径的代码就ok了

iOS

代码如下:

- (id<WXImageOperationProtocol>)downloadImageWithURL:(NSString *)url imageFrame:(CGRect)imageFrame userInfo:(NSDictionary *)options completed:(void (^)(UIImage *, NSError *, BOOL))completedBlock{ if ([url hasPrefix:@"//"]) {

Android

代码如下:

 [@Override](/user/Override) public void setImage(final String url, final ImageView view,

故事七: 生产环境的实践

增量更新

方案一

可以使用google-diff-match-patch来实现, google-diff-match-patch拥有许多语言版本的实现, 思路如下:

  • 服务器端构建一套管理前端

    bundlejs

    的系统, 提供查询

    bundlejs

    版本与下载的api

  • 客户端第一次访问

    weex

    页面时去服务端下载

    bundlejs

    文件

  • 每次客户端初始化时静默访问服务器判断是否需要更新, 若需更新, 服务器端

    diff

    两个版本的差异, 并返回

    diff

    ,

    native

    端使用

    patch api

    生成新版本的

    bundlejs

方案二

来自 @荔枝我大哥的补充

 我们所有的jsBundle全部加载的线上文件,通过http头信息设置`E-Tag`结合`cache-control`来实现缓存策略,最终效果就是,A.vue -> A.js, app第一次加载A.js是从网络下载下来并且保存到本地,app第二次加载A.js是直接加载的保存到本地的 A.js文件,线上A.vue被修改,A.vue -> A.js, app第三次加载A.js时根据缓存策略会知道线上A.js 已经和本地A.js 有差异,于是重新下载A.js到本地并加载. (整个流程通过http缓存策略来实现,无需多余编码,参考https://developers.google.cn/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=zh-cn)

还可以参考很多ReactNative的成熟方案, 本质上都是js的热更新

降级处理

一般情况下, 我们会同时部署一套

web

端界面, 若线上环境的

weex

页面出现bug, 则使用webview加载

web

版, 推荐依赖服务端api来控制降级的切换

总结

weex

的优势: 依托于

vue

, 上手简单. 可以满足以

vue

为技术主导的公司给

native

双端提供简单/少底层交互/热更新需求的页面的需求

weex

的劣势: 在

native

端调整样式是我心中永远的痛.. 以及众所周知的生态问题, 维护组没有花太多精力解答社区问题, 官方文档错误太多, 导致我在看的时候就顺手提了几个PR(逃

对于文章中提到的没提到的问题, 欢迎来和笔者讨论, 或者参考我的weex-start-kit, 当然点个star也是极好的

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码