跳到主要内容

11 篇博文 含有标签「JS」

查看所有标签

dart与js的互操作(一)

· 阅读需 1 分钟

https://dart.dev/interop/js-interop/past-js-interop


@js.JSExport()
class _MyAppState extends State<MyApp> {
final _streamController = StreamController<void>.broadcast();
DemoScreen _currentDemoScreen = DemoScreen.counter;
int _counterScreenCount = 0;

@override
void initState() {
super.initState();
final export = js.createJSInteropWrapper(this);
js.globalContext['_appState'] = export;
js.globalContext.callMethod('_stateSet'.toJS); // 调用js方法,将Dart实例化
}

JS 节流与防抖(附 React Hooks)

· 阅读需 10 分钟

在搜索框里敲「react」:r、re、rea、reac、react——如果每次敲键都发一次请求,一次输入就白白浪费 4 次网络请求,而且前 4 次的结果你根本来不及看,它们已经在回来的路上了。再往下想:滚动页面时 onScroll 一秒钟触发几十次,resize 拖拽时更是每帧一次。

这类问题有一个共同的名字:事件风暴——短时间内触发太多次,而真正需要执行的只有少数几次。

聊聊函数柯里化:来源、解决的问题与优缺点

· 阅读需 7 分钟

柯里化(Currying)是函数式编程里最常被提起、也最常被误解的概念之一。面试喜欢问,但很多人只背得住一句「把多参函数变成单参函数的链式调用」,说不清它从哪来、为什么存在、以及它到底划算不划算。

这篇文章把三件事讲透:它是谁发明的、它解决什么问题、它的代价是什么。

手写 JS 系列:从 apply 到 bind,最后手写一个 Promise

· 阅读需 12 分钟

手写系列的意义不是「记住答案」,而是把 API 背后那句被藏起来的话重新说出来:「改变 this」本质是什么?「异步」到底是怎么串起来的? 顺着 apply → call → bind → Promise 这条线写下来,你会发现它们是一脉相承的——前面三个解决的是一件事(函数调用时的 this 和参数),最后一个把「回调」正式升级成了「一等公民」。

编程日志(08)—vue实现plupload分片上传

· 阅读需 5 分钟
<!-- plupload封装 -->
<template>
<div class="supload">
<div class="clearfix list-picture" v-if="fileList.length>0&&listType=='picture'">
<div v-for="ff,index in fileList" class="pic-bx small">
<img :src="ff.showUrl">
<div class="cl-bx">
<i class="el-icon-close" @click="deleteFile(ff,index)"></i>
</div>
</div>
</div>
<div class="plupload clearfix" v-show="fileList.length<maxFile">
<template v-if="listType=='text'">
<div class="text_trigger">
<div :id="trigger_id" >
<i class="el-icon-document" ></i>
<span>{{triggerText}}(小于{{maxSize}}Mb)</span>
</div>
</div>
</template>
<template v-if="listType=='picture'">
<div class="fm-up" :id="trigger_id">
<div class="cc">
<i class="el-icon-circle-plus-outline"></i>
<p>点击选择</p>
<span>支持jpg/png格式</span>
<span>560px×400px</span>

</div>
</div>
</template>
</div>
<div class="pgs" v-if="progress>0&&listType=='text'">
<el-progress :text-inside="true" :stroke-width="20" :percentage="progress" status="success"></el-progress>
</div>

<div class="list-text" v-if="listType=='text'">
<template v-for="ff,index in fileList">
<div class="clearfix item-text">
<!-- <div class="progress" :style="{'width':ff.progress+'%'}"></div> -->
<div class="title">{{ff.name}}</div>
<div class="close" @click="deleteFile(ff,index)">删除</div>
</div>

</template>
</div>

</div>
</template>

<script>
/**
* 强制multi_selection为false使其只能逐个上传
*
*/
/**
* tip:
* 为了操作方便fileList以数组形式传入props,直接操作fileList可以实现数据双向绑定
* 并不建议这样去做,父子组件之间尽量保持单向数据流
* 因此可以暂不向外提供文件删除上传的回调入口
*/
/*
xlsx等文档可以在拓展过滤为zip的情况下可选的bug是因为xlsx本质是个压缩包,将xlsx拓展名改成zip再看看
*/
import plupload from 'plupload'
import {guid,getExtName} from '../../lib/util.js'

import config from '../../config/config.js'
export default {
data() {
return {
trigger_id:null, //触发按钮的ID属性
plup:null, // plupload实例对象
progress: 0, // 单文件上传进度
option: null
};
},
props: {
accept: {
type: String,
default: 'image/png,image/jpeg,audio/mp3'
},
// 支持的拓展名以逗号隔开jpg,gif,png,bmp,mp4
extensions:{
type: String,
default: 'mp4'
},
maxFile: {
type: Number,
default: 1
},
maxSize: {
type: Number,
default: 512 //mb
},
// 文件列表
fileList: {
default(){
return []
}
},
// text,picture 以picture形式呈现时,如果超过可上传数量,上传界面将消失
listType:{
default: 'text'
},
params:{
type:Object,
required:true
},
triggerText:{
default:'选择文件'
}
},
computed:{

},
components: {

},

methods: {
transGetUrl(url) {
return config.imgHost + url
},


deleteFile(ff,index){
this.fileList.splice(index,1)
},

},
watch:{
extensions(ne,olg){
this.option.filters.mime_types=[{
title: 'files', extensions: ne
}]

this.plup.destroy()
this.plup = new plupload.Uploader(this.option);
this.plup.init()

}

},
mounted(){
const $this = this;
this.option = {
runtimes: 'html5,flash,silverlight,html4',
url: config.downloadHost+'upload/pluploadUpload',
//url: '/preschool/upload/pluploadUpload',
browse_button: this.trigger_id,
chunk_size: '2048kb',
multi_selection:false,
filters: {
mime_types: [{ title: 'files', extensions: this.extensions }],
max_file_size: this.maxSize+'mb',
prevent_duplicates: true
},
multipart:true,
multipart_params:this.params,
init: {
FilesAdded: function(up, files) {
up.start();
},
UploadProgress: function(up, file) {
$this.progress = file.percent;
},
BeforeUpload: function(up,file) {},
FileUploaded: function(uploader,file,res){
// response,responseHeaders,status
if (res.status==200){
let result = JSON.parse(res.response);
if (result.code==0){
setTimeout(function(){
$this.progress = 0;
$this.fileList.push({
name:file.name,
// url: result.data.replace(/(.*)(pluploadDir)/g,config.imgHost),
url: result.data,
showUrl: $this.transGetUrl(result.data),
type: getExtName(result.data)
});
},500);
}
} else {
}
},
Error:function(up,err){},
Refresh: function(up){},
Destroy(up){},
OptionChanged:function(up,option_name,new_value,old_value){}
// Error: this.error
}
}
this.plup = new plupload.Uploader(this.option);
this.plup.init();
},
beforeMount(){
this.trigger_id = guid();
}
};
/**
* 额外参数传递:
* 1.设置multipart为true
* 为true时将以multipart/form-data的形式来上传文件,为false时则以二进制的格式来上传文件。
* 2. 设置multipart_params:{userId:1024}
* 方式二
* 设置init的BeforeUpload(up,file){up.setOption("multipart_params",{userId:1024})}
* 也可以up.setOption({'multipart_params':{userId:1030}});这样可以方便设置多个参数
* 像 up.setOption({'multipart':true,'multipart_params':{userId:1032}})
* 在某些情况下可能更方便
*/
</script>

pkg-node打包可执行文件工具

· 阅读需 6 分钟

前言​

最近在研发基于electron的桌面应用,其中涉及到外设交互部分需要使用dll实现,在经历了艰难的环境配置之后,最后由于electron内存管理问题导致应用崩溃使得electron+ffi实现动态链接库调用这条路无法走通。当时还剩下两种方案可以尝试:

  1. 自己创建dll封装原生dll调用,感觉成功几率很低。
  2. 写node addons编译成node插件,需要较强c++功底,难度较大,且最后成功概率不高。

为什么坚持了两个星期还不放弃是因为node+ffi这条路已经走通了,证明第三方的dll是没有问题的。所以试着能不能解决electron中出现的问题。

当electron不能实现的事实逐渐明朗,我开始转移方向。首先想到的是nwjs+ffi的方案,随后迅速想到为什么不使用node自己实现呢?将此部分功能单独分割成为第三方应用,通过某种通信方式实现(写缓存、数据库、http等)。最不济的情况是我为每台终端部署node服务(此应用是B2B,需要实施,不需要自己安装,这一点帮了大忙)

最好的方式是不需要安装node等一堆东西,直接是可执行文件。因此我开始寻找node打包成可执行文件的方法。

编程日志(02)—同一浏览器多用户登录session冲突问题

· 阅读需 2 分钟

账号登录冲突​

在后端程序中,往往将session和成功登录的用户id进行绑定来保持登录状态,这样前后端交互时就不用显示传递用户ID来判断是哪个用户,并通过设置session过期时间来保障账户的安全。

session的值会被后端设置在cookie,前端无需做什么特别操作,正常请求接口即可。由于session就相当于用户id,当同一个浏览器存在多个标签页,A页是A用户,B页是B用户,那么session绑定的其实是后登陆的那一个用户的id,因为这种绑定是在登陆接口处理的。这样的话假如请求的数据(比如查看个人信息)是基于session拿用户id的,就会导致A用户拿到B用户的数据。

编程日志(01)--cocosCreator实现类似jQuery的ajax

· 阅读需 3 分钟

为什么在cocosCreator中不使用axios等工具​

cocosCreator版本:2.0.7

在游戏场景中少不了要使用网络交互,在以往的编程中,用jQuery实现或者axios实现并不是很难,从论坛的反馈来看,cocos对ES6的支持尤其是promise,经过长时间的更新似乎依然没有很好地完善,由于开发时间限制,这里就没有去体验这些说法直接使用回调函数避免兼容性问题原始实现ajax请求。