在开发app过程中,我们会遇到很多SDK不支持uniapp或者只支持Android、ios和web。那像用uniapp开发app的工程师就会选择renderjs来调用web的sdk中的api。
比如常见的echarts库等,这次我们遇到的是视频播放需求。云端的视频播放资源来自腾讯云点播。如果想要了解这方面功能的可以自行百度,这里就不放链接了,防止广告嫌疑。如果对于renderjs不熟悉的可以移步uniapp的官方文档,虽然官方文档对于renderjs的描述也是寥寥数语,但是结合我下面的代码你就会明白的。
首先,renderjs是运行在vue框架中是涂层的js代码。在这里我们可以用所有h5中的语法,需要注意的是renderjs中不能运行uni的api,也就是不能用uni.的方式处理相关逻辑。这里就要结合plus的api使用。因为这是一篇稍微有点深的文章所以大家多查资料(大佬不需要),如果按照这个思路看完,相信你就对于h5开发夸段app就有更深入的了解,独立开发app不成问题了。
下面就是renderjs的代码和讲解:
<template>
<view>
<view :msg="msg" :change:msg="renderScript.receiveMsg" class="renderjs" id="renderjs-view">
{{msg}}
</view>
<button @click="renderScript.emitData">直接调用renderjs中的emitData的方法</button>
<button @click="changeMsg" class="app-view">改变msg的值,直接调用renderjs中receiveMsg的值</button>
<button @click="renderScript.renferMsg">通过renderjs改变msg的值,同时调用renderjs中的emitData的方法</button>
</view>
</template>
<script>
export default {
data() {
return {
msg: '我是service层原来的msg',
};
},
methods: {
// 触发逻辑层出入renderjs数据改变
changeMsg() {
this.msg = "msg值改变了";
},
// 接收renderjs发回的数据
receiveRenderData(val) {
console.log('renderjs返回的值-->', val);
},
//接收renderjs发回的数据,同时触发:change:msg,调用enderjs中的emitData的方法
serviceClick(e){
this.msg=e
}
}
};
</script>
<script module="renderScript" lang="renderjs">
export default {
data() {
return {
name: '我是renderjs数据'
}
},
methods: {
renferMsg(event, ownerInstance) {
// 调用 service层的serviceClick方法,传值
ownerInstance.callMethod('serviceClick', {
test: '这是点击renderjs的区域,向service层传递变量'
})
},
// 接收逻辑层发送的数据
receiveMsg(newValue, oldValue, ownerVm, vm) {
console.log('msg变化了newValue', newValue)
console.log('msg变化了oldValue', oldValue)
console.log('msg变化了ownerVm', ownerVm)
console.log('msg变化了vm', vm)
},
// 发送数据到逻辑层
emitData(e, ownerVm) {
ownerVm.callMethod('receiveRenderData', this.name)
}
}
};
</script>
上边是renderjs的通信逻辑,这里可以理解为先把罗基层js的数据双向绑定到是涂层元素上,在通过:change绑定这个值,只要这个值变动则调用视图层里的方法,类似做了一个监听。而视图层的数据想传递出来,就需要通过点击事件了。这里提一下,如果想通过vuex来实现共享是行不通的,具体的坑是在vue的this指向的实例化对象问题,只能获取到原始数据而无法获取到更新后数据,这里就不展开了。
接下来就是通过renderjs动态引入类库,比如echarts,我们这次用的是腾讯云点播。
具体方法如下:
<script lang="renderjs" module='id_test_video'>
export default {
methods: {
init() {
if (typeof window.TCPlayer === 'function' &&
typeof window.Hls === 'function') {
this.initPlayer()
} else {
// 动态引入较大类库避免影响页面展示
const Hls = document.createElement('script')
// Hls.src = 'https://imgcache.qq.com/open/qcloud/video/tcplayer/libs/hls.min.0.13.2m.js'
Hls.src = './static/tcplayer/hls.min.0.13.2m.js'
//以上代码需要做加载成功的判断
const TcPlayer = document.createElement('script')
// TcPlayer.src = 'https://web.sdk.qcloud.com/player/tcplayer/release/v4.5.2/tcplayer.v4.5.2.min.js'
//库文件存于本地,方便将报错部分进行修改。如果出现影响功能bug建议解开上边在线库。
TcPlayer.src = './static/tcplayer/tcplayer.v4.5.2.min.js'
document.head.appendChild(Hls)
document.head.appendChild(TcPlayer)
//加载完成执
TcPlayer.onload = this.initPlayer.bind(this)
}
},
}
}
在钩子函数中调用init方法完成类库引入和播放器对象的实例化。这样动态引入第三方类库,一方面是解决app利用webapi实现需求,另一方面避免引入大型类库造成的性能问题。这样就可以随意使用h5的各种方法而不受到限制,比如通过document操作dom。
在引入类库并实例化了播放器操作对象后,最重要的是将盛放播放器的dom创建并渲染到页面中,然后才能调用播放器的api实现手势操作等。这里先告诉大家,直接把元素写到页面结构中的方法是行不通的,具体原因后面分析,用到的仍然是vue的render函数,也就是操作虚拟dom,由于篇幅有限,下面的内容将写到下一节中。 持续更新