react怎样在html中引入js

JavaScript016

react怎样在html中引入js,第1张

<script src="react.js"></script>

<script src="react-dom.js"></script>

<script src="browser.min.js"></script>

react.js 是 React 的核心库

react-dom.js 是提供与 DOM 相关的功能,你以后创建的组件都是用它创建

Browser.js 的作用是将 JSX 语法转为 JavaScript 语法

众所周知,React更纯粹,Vue做的封装更多,所以大多数的难度都是集中在react的组件引用vue组件的过程中

请参考 https://github.com/devilwjp/vuereact-for-vuecli3-demo

请参考 https://github.com/devilwjp/vuereact-for-cra-demo

由于react hooks的取名规范是use开头,所以将use开头的方法全部修改成了apply开头,老的use开头方法仍然有效

在react组件中使用vue组件,如果要使用vue的sync修饰,使用 sync <Object>

在react组件中使用vue的组件

在react组件中,向vue组件传递具名插槽和作用域插槽,以及绑定自定义事件,以及v-model应用

react本身并不支持v-model,所以需要通过 model的value和setter也不需要变化

在react组件动态引用vue组件,类似vue的<component />

与react不同,vue有全局注册组件的功能,使每个组件不需要再单独引入

将vue全局组件的id作为参数传入applyVueInReact中,或者将id作为component属性的值传入VueContainer中

示例:在react中使用全局的vue版本element-ui的DatePicker

在Vue的组件中使用React组件

在Vue组件中,向React组件传递具名插槽和作用域插槽,以及绑定自定义事件

由于React没有插槽的概念,所有都是以属性存在,Vue的具名插槽和作用域插槽会被转化为React的属性,其中作用域插槽会转换成render props的方式

并且Vue组件的事件也会被转化成React的属性

比如react版本的antd的Card组件,在react中的使用示例如下

react版本的antd,在vue组件中使用的示例如下

作用:使得所有的Vue组件可以使用redux的状态管理

对工具包开启redux状态管理,这个场景一般存在于以React为主的项目中,为了使Vue组件也可以共享到redux,需要在项目的入口文件引入applyRedux方法(整个项目应该只引一次),将redux的store以及redux的context作为参数传入(或者至少在redux的Provider高阶组件引入的地方使用applyRedux方法)

React组件连接redux的方式这里就不再做介绍了,应该使用react-redux的connect方法

这里介绍Vue组件如何使用redux,工具包尽可能的实现了vue组件使用vuex的方式去使用redux,通过vm.$redux可以在组件实例里获取到redux状态管理

作用:使得所有的Redux组件可以使用Vuex的状态管理

对工具包开启vuex状态管理,这个场景一般存在于以Vue为主的项目中,为了使React组件也可以共享到vuex,需要在项目的入口文件引入applyVuex方法(整个项目应该只引一次),将vuex的store作为参数传入

类似react-redux的connect方法,在React组件中使用,由于vuex的关键字比redux多,所以将参数改成了对象,包含了mapStateToProps、mapCommitToProps、mapGettersToProps、mapDispatchToProps,每个都是一个纯函数,返回一个对象(和redux的connect使用方式完全一致)

在React的router里懒加载Vue组件

在Vue的router里懒加载React组件

每个通过applyVueInReact的的vue组件,以及通过applyReactInVue的react组件,都可以收到一个data-passed-props的属性,这个属性可以帮助你不做任何包装的,被之后再次使用applyVueInReact或applyReactInVue的组件收到全部的属性(由于是跨框架透传,原生的透传方式并不会自动做相应的封装和转换)

由于在每一次跨越一个框架进行组件引用时,都会出现一层包囊,这个包囊是以div呈现,并且会被特殊属性标注

React->Vue,会在vue组件的dom元素外包囊一层标识data-use-vue-component-wrap的div

Vue->React,会在react组件的dom元素外包囊一层标识__use_react_component_wrap的div

如果引发样式问题,可以全局对这些标识进行样式修正

1. 微信JSSDK使用步骤简介

我们既然是在做基于微信的开发,当然就离不开微信的开发文档了。开始之前希望大家能先去看下《微信JS-SDK说明文档》。那么我们怎么样才能用上微信的JSSDK呢?以下基本步骤就是基于该文档的。

需要注意的是,如果本人下面的描述你看的有点云里雾里的话,我建议你:

回头看下本系列《小白学react》的历史基础文章,特别是《小白学react之altjs的Action和Store》以及《小白学react之打通React Component任督二脉》,或/和:

直接跳过我的描述,在文章后面下载最新的源码,先阅读源码,碰到问题再反过来看文章的描述。

步骤一:绑定域名

先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。

备注:登录后可在“开发者中心”查看对应的接口权限。

这里绑定的时候需要注意不要带前面的http协议头。写法跟上一篇《小白学react之网页获取微信用户信息》中的网页回调域名设置的写法是一样的。

步骤二:引入JS文件

在需要调用JS接口的页面引入如下JS文件,(支持https):

请注意,如果你的页面启用了https,务必引入 :

,否则将无法在iOS9.0以上系统中成功使用JSSDK

因为我们的index.html是通过ejs模版生成的,所以我们只需要在我们的index.ejs中的body部分末尾加入相应的微信jssdk库的引用就好了。

   <% for (var chunk in htmlWebpackPlugin.files.chunks) { %>     <script src="<%= htmlWebpackPlugin.files.chunks[chunk].entry %>"></script>

     <script src="jweixin-1.0.0.js"></script>

   <% } %>

步骤三:通过config接口注入权限验证配置

所有需要使用JS-SDK的页面必须先注入配置信息,否则将无法调用(同一个url仅需调用一次,对于变化url的SPA的web app可在每次url变化时进行调用,目前Android微信客户端不支持pushState的H5新特性,所以使用pushState来实现web app的页面会导致签名失败,此问题会在Android6.2中修复)。

wx.config({

   debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。

   appId: '', // 必填,公众号的唯一标识

   timestamp: , // 必填,生成签名的时间戳

   nonceStr: '', // 必填,生成签名的随机串

   signature: '',// 必填,签名,见附录1

   jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2})

这一步的关键是如何生成正确的签名。这里微信jssdk文档中有给出不同语言版本的签名算法示例大家可以参考。往下我们也会就github上的一个签名算法的封装进行学习。

在我们的实战过程中,签名会在服务器端发生。

react客户端会像之前的获取微信用户信息一样,通过一个restfulApi调用服务器端的api,然后由服务器来生成对应的签名,然后将签名信息返回给客户端。

客户端获取到上面wx.config示例代码中的签名相关信息后,就会调用一个Alt的Action,来触发将获取回来的信息保存到一个跟该Action绑定的jssdk状态管理的Store里面。然后就可以调用wx.config来配置我们需要用到的JS接口列表了。

注意这里的wx这个对象是通过上一步的JS文件引入进来的。我们在react的客户端代码中可以直接通过window.wx对其进行引用:

window.wx.config({

 ...

})

步骤四:通过ready接口处理成功验证

wx.ready(function(){    // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。})

随后,react客户端负责jssdk状态管理的store会调用wx.ready来监听config配置是否成功,如果成功的话,就会将该store的一个ready状态设置成true。

这样的话,通过AltContainer绑定了该store的相应的Component组件就能知道响应的jssdk的api是否已经准备就绪,可以进行调用了。

步骤五:通过error接口处理失败验证

wx.error(function(res){    // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。})

同理,如果如果配置失败的话,那么就在wx.error这个监听接口中将ready状态设置成false。

2. 生成签名

如前面所述,我们需要用到jssdk的页面必须要要注入调用到的api的配置信息。

wx.config({

   debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。

   appId: '', // 必填,公众号的唯一标识

   timestamp: , // 必填,生成签名的时间戳

   nonceStr: '', // 必填,生成签名的随机串

   signature: '',// 必填,签名,见附录1

   jsApiList: [] // 必填,需要使用的JS接口列表

而注入JS接口到页面时,我们可以看到,还需要使用到其他一些信息。其中appId我们可以从公众号管理后台获得。signature是跟所访问页面的url关联的一个签名,它有专门的一套算法来生成。另外两个参数nonceStr和signature都是在签名的过程中生成的。

这里通过wx.config传进去这些参数,主要是为了让微信去判断我们生成的签名和微信通过这些信息生成的签名是否一致,如果不一致的话,那么注入到该页面的jsApiListj就失败。

那么我们在服务器这边的签名算法是如何的呢?根据微信开发文档我们需要提供以下4个参数,然后通过sha1算发来生成对应的签名:

noncestr:一个随机字符串,我们随便填写

jsapi_ticket:jsapi_ticket是公众号用于调用微信JS接口的临时票据

timestamp: 签名时间戳。注意这个时间戳需要和上面传入wx.config的时间戳一致

url: 调用JS接口页面的完整URL。我们可以从react客户端通过location.href获得,并传给服务器端

那么这里主要需要解决的就是如何获得jsapi_ticket这个临时票据了。

根据文档的描述,我们可以通过以下这个接口获得:

cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi

从中可以看到,我们调用这个接口首先要获得一个access_token。这里微信也有相应的api来处理。

cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

这里需要用到我们的微信公众号的appId和secret,这些我们都是已知的,所以好办。

那么,也就是说,我们其实只需要提供我们的微信公众号的appId和secret,就能获取到access_token,从而就会获得我们需要的jsapi_ticket。

这里我们参考下github上一个示例(wechat-sdk-demo )的签名的实现。其传入的参数有两个,其中:

url:  react客户端传进来的需要注入jsapi的页面url

callback: 一个回调函数,接受一个json格式的参数。主要是用来将生成的签名信息等回传给上层调用函数。

const config = {    grant_type: 'client_credential',    appid: 'xxxx',    secret: "xxxxx",    noncestr:'Wm3WZYTPz0wzccnW',    accessTokenUrlin.qq.com/cgi-bin/token',    ticketUrl:'com/cgi-bin/ticket/getticket',

}

exports.sign = function (url,callback) {  var noncestr = config.noncestr,

       timestamp = Math.floor(Date.now()/1000), //精确到秒

   ...

       request(config.accessTokenUrl + '?grant_type=' + config.grant_type + '&appid=' + config.appid + '&secret=' + config.secret ,function(error, response, body){            if (!error &&response.statusCode == 200) {                var tokenMap = JSON.parse(body)

               request(config.ticketUrl + '?access_token=' + tokenMap.access_token + '&type=jsapi', function(error, resp, json){                    if (!error &&response.statusCode == 200) {                        var ticketMap = JSON.parse(json)

                       cache.put('ticket',ticketMap.ticket,config.cache_duration) //加入缓存

                       callback({                            noncestr:noncestr,                            timestamp:timestamp,                            url:url,                            jsapi_ticket:ticketMap.ticket,                            signature:sha1('jsapi_ticket=' + ticketMap.ticket + '&noncestr=' + noncestr + '&timestamp=' + timestamp + '&url=' + url)

                       })

                   }

               })

           }

       })

   }

}

这里的流程和我们刚才描述的并无二致。首先是通过appId和secret获得调用获取jsapi_ticket的access_token,然后通过该access_token获得我们签名需要用到的jsapi_ticket。noncestr我们是提前随便填写好的。timestamp的算法也比较简单。

最后就是通过sha1这个库提供的方法,将jsapi_ticket,noncestr,timestamp和页面url进行sha1签名,然后将以上这些信息通过callback返回给上层调用函数。

那么我们往下看下我们的上层调用函数。其实就是我们的express路由:

app.get("/api/signature", function(req,res) {    const url = req.query.url.split('#')[0]

   signature.sign(url,function(signatureMap){

       signatureMap.appId = wechat_cfg.appid

       res.send(signatureMap)

   })

})

根据微信开发文档需求,我们首先需要将传进来的url的锚点后面的数据给去掉,保留前面的有效部分。

然后就是调用上面的sign方法来生成签名。上面的签名方法最后传进来的json数据就是这里的signatureMap。我们最终会将这些数据发送回react客户端。

同时,通过上面的wx.config的示例,我们知道还需要用到微信公众号的appId。所以这里一并将其放到signatureMap中进行返回。

那么到此为止,react客户端调用服务端的"/api/signature"返回的数据示例如下:

{

 noncestr: 'Wm3WZYTPz0wzccnW',

 timestamp: 1476873698,

 url: 'com/?code=001kGsd30xcm7F1PAFf305Uud30kGsdr&state=',

 jsapi_ticket: 'sM4AOVdWfPE4DxkXGEs8VBqyVbs-TKGYp4d_ZSQa0Q5WvvMUPNQ6XGpyEcgKOD_xID_GrMCaalSmIF9JbrGaOg',

 signature: '9268ffaf4b9eb0d296fcfefe3d2724118aa05e3c'

}

3.  客户端获取签名信息

3.1 获取签名信息并注入jssdk

和之前的获取微信用户信息一样,我们这里会建立一个新的Source文件WechatSdkSource.js来调用远程服务器的"/api/signature"接口:

var WechatSdkSource = {

 fetchSignatureMap() {    return {

     remote(state,url) {        return co(function *() {          let signatureMap = null         const getSignatureMapUrl = `/api/signature`         try {            let result = yield request.get(getSignatureMapUrl).query({url:url})

           signatureMap = result.body

         } catch (e) {

           signatureMap = null

         }          //console.log("userInfo:", userInfo)

         return signatureMap

       })

     },

     local() {        // Never check locally, always fetch remotely.

       return null

     },      success: WechatSdkActions.updateSignatureMap,      error: WechatSdkActions.getSignatureMapFailed,      loading: WechatSdkActions.getSignatureMap,

   }

 }

}

这里传进来的url由下面将要谈及的上层函数所生成。整个流程就没有什么好说的了,说白了就是通过相应的库发送一个带有url的query参数的请求到服务器端来请求签名信息,相信有跟着这个系列文章的朋友都是很清楚的了。

最终请求成功返回的时候就会调用WechatSdkActions的updateSignatureMap这个Action。

var alt = require('../alt')module.exports  = alt.generateActions(    'updateSignatureMap',    'getSignatureMap',    'getSignatureMapFailed',

)

而这个action就会触发所监听的WechatSdkStore的onUpdateSignatureMap这个回调。

class WechatSdkStore {  constructor() {    this.signatureMap = []   this.errorMessage = null   this.ready = false   this.bindActions(WechatSdkActions)   this.exportAsync(WechatSdkSource)