• JS构建多端应用


    JS构建多端应用

    一,需求与介绍

     1.1,介绍

    1,Taro 是一套遵循 React 语法规范的 多端开发 解决方案。现如今市面上端的形态多种多样,Web、React-Native、微信小程序等各种端大行其道,当业务要求同时在不同的端都要求有所表现的时候,针对不同的端去编写多套代码的成本显然非常高,这时候只编写一套代码就能够适配到多端的能力就显得极为需要。

    使用 Taro,我们可以只书写一套代码,再通过 Taro 的编译工具,将源代码分别编译出可以在不同端(微信/百度/支付宝/字节跳动小程序、H5、React-Native 等)运行的代码。

    2,Taro UI 是一款基于 Taro 框架开发的多端 UI 组件库

     1.2,需求

         一套代码,多端使用,减少开发成本

    二,搭建项目

    第一步:全局安装Taro 开发工具 @tarojs/cli

    1 npm/cnpm install -g @tarojs/cli

    第二步:创建项目

    1 taro init YingQi

     在创建完项目之后,Taro 会默认开始安装项目所需要的依赖,安装使用的工具按照 yarn>cnpm>npm 顺序进行检测。如果安装失败,可以使用如下命令安装

    1 npm/cnpm install

    第三步:运行项目

    以运行H5为例,输入如下命令

    如果看到如下界面,表示运行成功

    1.H5

    H5预览项目

    1 # npm script
    2 $ npm run dev:h5
    3 # 仅限全局安装
    4 $ taro build --type h5 --watch
    5 # npx 用户也可以使用
    6 $ npx taro build --type h5 --watch

    H5打包项目

    1 # npm script
    2 $ npm run build:h5
    3 # 仅限全局安装
    4 $ taro build --type h5
    5 # npx 用户也可以使用
    6 $ npx taro build --type h5

    2.微信小程序

    微信小程序预览项目

    1 # npm script
    2 $ npm run dev:weapp
    3 # 仅限全局安装
    4 $ taro build --type weapp --watch
    5 # npx 用户也可以使用
    6 $ npx taro build --type weapp --watch

    微信小程序打包项目

    1 # npm script
    2 $ npm run build:weapp
    3 # 仅限全局安装
    4 $ taro build --type weapp 
    5 # npx 用户也可以使用
    6 $ npx taro build --type weapp

    注意:去掉 --watch 将不会监听文件修改,并会对代码进行压缩打包

    其他端的预览/打包项目与H5的类似,只需把H5替换为其他的即可,如下:

    1. 百度只能小程序:swan
    2. 支付宝小程序:alipay
    3. React-Native:rn
    4. 头条/字节跳动小程序:tt

    三,配置项目架构

     3.1,配置dva

    第一步:安装所需的依赖

    1 npm/cnpm install --save dva-loading dva-core redux-logger

    第二步:配置dva入口

     1 import Taro from '@tarojs/taro';
     2 import { create } from 'dva-core';
     3 // import { createLogger } from 'redux-logger';
     4 import createLoading from 'dva-loading';
     5 
     6 let app;
     7 let store;
     8 let dispatch;
     9 
    10 function createApp(opt) {
    11   // redux日志
    12   // opt.onAction = [createLogger()];
    13   app = create(opt);
    14   app.use(createLoading({}));
    15 
    16   // 适配支付宝小程序
    17   if (Taro.getEnv() === Taro.ENV_TYPE.ALIPAY) {
    18     global = {};
    19   }
    20 
    21   //注册models
    22   if (!global.registered) opt.models.forEach(model => app.model(model));
    23   global.registered = true;
    24   app.start();//启动
    25 
    26   store = app._store;
    27   app.getStore = () => store;
    28 
    29   dispatch = store.dispatch;
    30 
    31   app.dispatch = dispatch;
    32   return app;
    33 }
    34 
    35 export default {
    36   createApp,
    37   getDispatch() {
    38     return app.dispatch;
    39   },
    40 };

    第三步:配置models文件-home

     1 import {STATUSSUCCESS} from '../utils/const';
     2 import {
     3     Home as namespace,
     4   } from '../utils/namespace';
     5 import {
     6   getSingleDataById,
     7 } from '../services/home';
     8 
     9 export default {
    10   namespace: namespace,//'home',
    11   state: {
    12     singleId:'',
    13     tableName:'',
    14   },
    15   effects: {
    16     *getSingleData(_, { call, put,select }) {
    17       const { singleId, tableName } = yield select(state => state[namespace]);
    18       console.log('singleId===',singleId)
    19       const { status, data } = yield call(getSingleDataById, {
    20         singleId,
    21         tableName,
    22       });
    23       if (status ==STATUSSUCCESS) {
    24         yield put({
    25           type: 'save',
    26           payload: {
    27             banner: data.banner,
    28             brands: data.brands,
    29           },
    30         });
    31       }
    32     },
    33   },
    34   reducers: {
    35     save(state, { payload }) {
    36       return { ...state, ...payload };
    37     },
    38   },
    39 };

    第四步:配置models的统一入口

    1 import home from './home';
    2 
    3 export default [ home];

    第五步:引入到项目入口文件

    1 import dva from './entries';
    2 import models from './models';

    第六步:在项目入口文件配置

     1 ...
     2 
     3 import { Provider } from '@tarojs/redux';
     4 
     5 ...
     6 
     7 const dvaApp = dva.createApp({
     8   initialState: {},
     9   models: models,
    10 });
    11 const store = dvaApp.getStore();
    12 
    13 ...
    14 
    15  render() {
    16     return (
    17       <Provider store={store}>
    18        ...
    19       </Provider>
    20     );
    21   }
    22 
    23 ...

     3.2,配置服务请求

     第一步:配置请求方式与返回状态

    1 export const GET = 'GET';
    2 export const POST = 'POST';
    3 export const PUT = 'PUT';
    4 export const PATCH = 'PATCH';
    5 export const DELETE = 'DELETE';
    6 export const UPDATE = 'UPDATE';
    7 
    8 export const STATUSSUCCESS = 1;//成功返回状态

    第二步:配置请求基础地址与日志是否打印

    1 import Taro from '@tarojs/taro';
    2 // 请求连接前缀
    3 export const baseUrl = Taro.getEnv() === Taro.ENV_TYPE.WEB?'':'http://localhost:8880';//web端使用代理服务,小程序端使用服务前缀
    4 
    5 // 开发环境输出日志信息
    6 export const noConsole = (process.env.NODE_ENV === 'development');

    第三步:封装request

     1 import Taro from '@tarojs/taro';
     2 import {STATUSSUCCESS} from './const';
     3 import { baseUrl, noConsole } from '../config';
     4 
     5 function checkHttpStatus(response) {
     6  
     7   if (!!noConsole) {
     8     console.log('response===',response)
     9   }
    10   if (response.statusCode >= 200 && response.statusCode < 300) {
    11     return response.data;
    12   }
    13   const error = new Error(response.statusText);
    14   error.response = response;
    15   error.code = response.status;
    16   throw error;
    17 }
    18 
    19 function getResult(json) {
    20   // const {dispatch} = store;
    21   if (json.status ==STATUSSUCCESS) {
    22     return json;
    23   }
    24   else {
    25     const error = new Error(json.message || json.msg || '数据加载错误!');
    26     error.code = json.code;
    27     error.data = json;
    28     throw error;
    29   }
    30 }
    31 
    32 export default (url = '', options = {},) => {
    33   let data;
    34   let contentType;
    35   data = options.data;
    36   delete options.data;
    37   contentType = options.contentType;
    38   delete options.contentType;
    39   const opts = {
    40     url: baseUrl + url,
    41     method: 'POST',
    42     ...options
    43   };
    44   opts.header = {
    45     ...opts.header,
    46   };
    47   
    48 // 请求连接前缀
    49   if (opts.method === 'GET') {
    50      url = url.split('?');
    51      url = url[0] + '?' + QueryString.stringify(url[1] ? {...QueryString.parse(url[1]), ...data} : data);
    52      opts.headers['Content-type'] = contentType ? contentType : 'application/x-www-form-urlencoded'; //
    53 
    54   } else {
    55     opts.header['Content-Type'] = contentType ? contentType : 'application/x-www-form-urlencoded'; //
    56     opts.data = contentType === 'application/json' ? JSON.stringify(data) : serialize(data);
    57   }
    58   if (!!noConsole) {
    59     console.log(
    60       `${new Date().toLocaleString()}【 request  ${url} 】DATA=${JSON.stringify(
    61         data
    62       )}`
    63     );
    64   }
    65   return Taro.request(opts)
    66   .then(checkHttpStatus)
    67   .then(getResult)
    68   .catch(err => ({err}));
    69 };

    第四步:请求服务

    1 import request from '../utils/request';
    2 import {PUT, POST} from '../utils/const';
    3 
    4 /*
    5 ***获取单个登录数据***
    6 */
    7 export async function getSingleDataById(data) {
    8   return request('/api/v1/yingqi/user/getSingleDataById', {data, method: PUT, contentType: 'application/json'});
    9 }

     3.3,配置UI组件

     第一步:安装UI组件taro-ui

    1 npm/cnpm install taro-ui --save

    第二步:配置需要额外编译的源码模块

    由于引用 `node_modules` 的模块,默认不会编译,所以需要额外给 H5 配置 `esnextModules`,在 taro 项目的 `config/index.js` 中新增如下配置项:

    1 h5: {
    2   esnextModules: ['taro-ui']
    3 }

    第三步:使用taro-ui

    1 // page.js
    2 import { AtButton } from 'taro-ui'
    3 // 除了引入所需的组件,还需要手动引入组件样式
    4 // app.js
    5 import 'taro-ui/dist/style/index.scss' // 全局引入一次即可
    1  <AtButton
    2         onClick={this.handleChange.bind(this)}>
    3         底部关闭幕帘
    4       </AtButton>

    3.4,配置iconfont图标

     第一步:iconfont上创建项目

    第二步:上传图标并生成代码

    第三步:在项目中配置

     1 @font-face {
     2   font-family: 'iconfont';  /* project id 1076290 */
     3   src: url('http://at.alicdn.com/t/font_1076290_m2xyh7ml7qi.eot');
     4   src: url('http://at.alicdn.com/t/font_1076290_m2xyh7ml7qi.eot?#iefix') format('embedded-opentype'),
     5   url('http://at.alicdn.com/t/font_1076290_m2xyh7ml7qi.woff2') format('woff2'),
     6   url('http://at.alicdn.com/t/font_1076290_m2xyh7ml7qi.woff') format('woff'),
     7   url('http://at.alicdn.com/t/font_1076290_m2xyh7ml7qi.ttf') format('truetype'),
     8   url('http://at.alicdn.com/t/font_1076290_m2xyh7ml7qi.svg#iconfont') format('svg');
     9 }
    10 
    11 .iconfont {
    12   font-family: 'iconfont' !important;
    13   font-size: 32px;
    14   font-style: normal;
    15   -webkit-font-smoothing: antialiased;
    16   -moz-osx-font-smoothing: grayscale;
    17 }
    18 
    19 .icon-more:before {
    20   content: 'e605';
    21 }

    第四步:使用

    1 <View className="iconfont icon-more arrow" />

    效果如下:

    四,常见问题

    1,问题:使用inconfont图标时,web端没有显示图标

    解决办法:在每一行//at.alicdn.com/t/font_1076290_m2xyh7ml7qi.eot前加“https:”

    2,问题:Taro发起请求参数无法识别content-type类型

    原因:由于常用的axios/fetch请求参数的头部是headers,而taro的是header,如果继续使用headers会引发content-type设置失效,变成默认的类型。

    解决办法:headers->header

    1  opts.header = {
    2     ...opts.header,
    3   };
  • 相关阅读:
    C++ 抽象类二(抽象类的基本语法)
    C++ 抽象类一(多继承与赋值兼容性原则)
    C++ 类的多态五(多态的语法本质分析)
    C++ 类的多态四(虚析构函数的重要性)
    C++ 类的多态三(多态的原理--虚函数指针--子类虚函数指针初始化)
    MEF等Ioc框架引起内存泄露-PartCreationPolicy
    MEF部件的生命周期(PartCreationPolicy)
    wpf prism IRegionManager 和IRegionViewRegistry
    silverlight开发实例(Prism+MVVM+RIA)(二)--创建shell及用户登录
    Prism框架 如何在主程序中合理的弹出子窗体
  • 原文地址:https://www.cnblogs.com/jackson-yqj/p/10566052.html
Copyright © 2020-2023  润新知