功能详解
-
大幅降低逻辑层和视图层的通讯损耗,提供高性能视图交互能力 逻辑层和视图层分离有很多好处,但也有一个副作用是在造成了两层之间通信阻塞。尤其是小程序和App的Android端阻塞问题影响了高性能应用的制作。
-
renderjs运行在视图层,可以直接操作视图层的元素,避免通信折损。
-
在视图层操作dom,运行for web的js库 官方不建议在uni-app里操作dom,但如果你不开发小程序,想使用一些操作了dom、window的库,其实可以使用renderjs来解决。 在app-vue环境下,视图层由webview渲染,而renderjs运行在视图层,自然可以操作dom和window。
注意事项
- 可以使用 dom、bom API 不可直接访问逻辑层数据
- 视图层和逻辑层通讯方式与 WXS 一致
- 观测更新的数据在 view 层可以直接访问到
- 不要直接引用大型类库,推荐通过动态创建 script 方式引用
- view 层的页面引用资源的路径相对于根目录计算,例如:./static/test.js
- 目前仅支持内联使用
- prop不能传递函数,故如f2等用到函数传递的不能封装成公共组件
<view :prop="serviceProp" :change:prop="echarts.updateEcharts" :id="id" class="echarts"></view>
/**
:prop 逻辑层传递给视图层数据,必须与 :change:prop 连用
也可以:xx ="" :chang:xx="viewMethod"
主要作用是,当逻辑层数据xx发生改变后,视图层js做出响应
*/
实践
app 选择本地文件,图片、视频、文档、等文件。
- 通常解决方案都是下载收费的原生插件。而且有的还不能支持同时支持ios端。而有了renderjs就不用原生插件也能实现文件上传
android 有个吭
当运行环境targetSdkVersion版本设置过高时。华为低端手机上会获取不到文件路径。
<template>
<view class="">
<view :prop="option" :change:prop="inputfile.updateEcharts" @click="inputfile.onClick"><slot>文件上传</slot></view>
</view>
</template>
<script>
export default {
inheritAttrs: false,
name: '',
props: {},
components: {},
watch: {},
created() {},
computed: {},
mounted() {},
data() {
return {
option: {
API: $globalConfig.baseUrl + `/upload/uploadFiles`,
token: uni.getStorageSync('token') ? uni.getStorageSync('token') : ''
}
};
},
methods: {
onViewClick(files) {
this.$emit('files', files);
},
loading(status = true) {
if (status) this.$utils.uni.showLoading('文件上传中……');
else this.$utils.uni.hideLoading();
},
errorMsg(msg = 'msg') {
this.$utils.uni.toast.error(msg);
}
}
};
</script>
<script module="inputfile" lang="renderjs">
import axiosConfig from './axiosConfig'
export default {
mixins:[axiosConfig],
data(){
return {myOwnerInstance:null}
},
mounted() {
this.createInputDom()
},
computed: {
fileId() {
return this.getUUID()
}
},
methods: {
createInputDom(){
let _this=this
let inputDom = document.createElement("input");
inputDom.setAttribute("type","file");
inputDom.setAttribute("id",this.fileId);
inputDom.setAttribute("hidden",true);
inputDom.setAttribute("multiple",'multiple');
// inputDom.setAttribute("capture",'capture');
inputDom.addEventListener('change',async function(e){
_this.myOwnerInstance.callMethod('loading')
let files= await _this.uploadFile(inputDom.files)
_this.myOwnerInstance.callMethod('loading',false)
_this.myOwnerInstance.callMethod('onViewClick', files)
//_this.excuteVmMethods('onViewClick',files)
})
document.body.appendChild(inputDom);
},
async uploadFile(files){
let _this=this
let formData = new FormData()
let keys=Object.keys(files)
let fileList=keys.map(key=>{
formData.append('files',files[key])
return files[key]
})
try{
return await axios({
method: 'post',
url:this.option.API,
headers:{
'Content-Type':'multipart/form-data'
},
data : formData
})
}catch(e){
_this.myOwnerInstance.callMethod('errorMsg',e.data?e.data.msg:'文件上传失败')
return []
}
},
getUUID() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
return (c === 'x' ? (Math.random() * 16) | 0 : 'r&0x3' | '0x8').toString(16);
});
},
updateEcharts(newValue, oldValue, ownerInstance, instance) {
console.log('updateEcharts');
},
onClick(event, ownerInstance) {
//将服务层的实例控制对象
this.myOwnerInstance=ownerInstance;
document.getElementById(this.fileId).click()
},
//执行service 层中的方法 ,只适用与App
excuteVmMethods(method,args){
// #ifdef APP-VUE
UniViewJSBridge.publishHandler('onWxsInvokeCallMethod', {
cid: this._$id,
//方法名
method,
//参数
args
})
// #endif
}
}
};
</script>
<style lang="scss" scoped></style>
直接用echarts 渲染图表
<template>
<view class="content">
<!-- #ifdef APP-PLUS || H5 -->
<view :prop="viewProp" :change:prop="echarts.updateEcharts" :id="id" class="echarts" @click="echarts.onClick"></view>
<!-- #endif -->
</view>
</template>
<script>
export default {
props: {
option: {
type: Object,
required: true
}
},
data() {
return {
id: this.getUUID()
};
},
onLoad() {},
computed: {
viewProp() {
return {
option: this.option,
id: this.id
};
}
},
methods: {
getUUID() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
return (c === 'x' ? (Math.random() * 16) | 0 : 'r&0x3' | '0x8').toString(16);
});
}
}
};
</script>
<script module="echarts" lang="renderjs">
let myChart;
export default {
mounted() {
if (typeof window.echarts === 'function') {
this.initEcharts();
} else {
// 动态引入较大类库避免影响页面展示
const script = document.createElement('script');
// view 层的页面运行在 www 根目录,其相对路径相对于 www 计算
script.src = 'static/js/echarts.js';
script.onload = this.initEcharts.bind(this);
document.head.appendChild(script);
}
},
methods: {
initEcharts() {
myChart = echarts.init(document.getElementById(this.viewProp.id));
// 观测更新的数据在 view 层可以直接访问到
myChart.setOption(this.viewProp.option);
},
updateEcharts(newValue, oldValue, ownerInstance, instance) {
console.log(JSON.stringify('change'));
// 监听 service 层数据变更
myChart.setOption(newValue.option);
},
onClick(event, ownerInstance) {
// 调用 service 层的方法
ownerInstance.callMethod('onViewClick', {
test: 'test'
})
},
//执行service 层 中的方法
excuteVmMethods(){
UniViewJSBridge.publishHandler('onWxsInvokeCallMethod', {
cid: this._$id,
//方法名
method:'onRenderJSEvent',
//参数
args:{test:'test'}
})
}
}
};
</script>
<style scoped lang="scss">
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.echarts {
width: 100%;
height: 300px;
}
}
</style>