搭建我的开发环境

通过react native开发vision os应用 因为我是一个前端,所以一开始决定还是使用一个自己比较熟悉的平台进行第一次开发 那么最优解当然还是react native了 好在react-native目前有一个startkits是支持visionos的 https://github.com/callstack/react-native-visionos 练手项目打算做一个简单的翻译工具 初始化 npx @callstack/react-native-visionos@latest init YourApp https://callstack.github.io/react-native-visionos-docs/

June 30, 2024 · 1 min · 15 words · 水华

opencv 编译

为啥要编译opencv 因为 opencv 是频域水印需要的一个功能 但是本体这个包实在是太大了 所以打算编译一个最多 2m 的包出来 编译参考 url: https://docs.opencv.org/4.x/d4/da1/tutorial_js_setup.html title: "OpenCV: Build OpenCV.js" host: docs.opencv.org 环境搭建 首先还得是安装 emsdk 通过万能的 homebrew 进行安装 brew install emscripten url: https://www.cnblogs.com/Wayou/p/webassembly_quick_start.html title: "WebAssembly 上手 - 刘哇勇 - 博客园" description: "安装 Mac 上最便捷的安装方式当然是通过 Homebrew: $ brew install emscripten 安装好之后讲道理就已经自动配置好一切,然后 emcc 命令便可用了。 下面看非 Homebrew 安装的方式。 通过官方 WebAssembly Developer’s Guide 提" host: www.cnblogs.com 构建基础版的 opencv 跟着教程 首先得复制一份到本地 git clone git clone https://github.com/opencv/opencv.git cd opencv emcmake python ./opencv/platforms/js/build_js.py build_wasm --build_wasm

May 5, 2024 · 1 min · 73 words · 水华

vue-cli项目如何同时打包一个express项目

vue-cli项目一般只会生成一个纯前端的vue项目,不过有时候,如果我们想开发一个express项目同时又想用vue作为前端该怎么搞呢? 几个解决方案 两个项目分别开发 mono-repo 其他方案 vue/express一个项目一次打包 其实因为怕打包麻烦,所以我是希望一个项目内,可以同时开发express/vue打包的时候又能只打包输出到一个文件夹下 所以我选择在vue-cli生产的项目内,增加一个server文件夹,用来开发express相关的代码,只有在最后打包的时候,变为一个express项目 改造的要点 前后端独立的hmr 前后端最终成果打包在一起 改造过程 独立热更同时前端可调用express服务 首先,我们在文件目录下建立server文件夹,将express服务器的开发,src下为原先前端相关的代码 其次,安装nodemon用来做express项目的开发启动 package.json添加命令"start:be": "nodemon ./server/index.js" 添加vue.config.js, 加入 module.exports = { devServer: { proxy: { '/{express服务的路径,例如api}': { target: 'http://127.0.0.1:{express端口}, ws: true, }, } } } 这样,启动npm run serve的时候同时启动start: be即可同时开启前后端 打包让express应用调用vue结果 express有static功能,假定用的是public 文件夹 package.json添加命令"build:be": "cp package.json ./dist/ && cp server/* ./dist/" 这样来打包express应用 同时express内添加一行,app.use(express.static('./public')) 接着,来改造vue.config.js module.exports = { outputDir: "./dist/public" } 之后build命令运行完,运行build:fe即可 ...

June 18, 2022 · 1 min · 68 words · 水华

如何实现表格的列拖拽的

因为使用el-table实现,所以一些抓取dom的class类通过el-table内置的类实现,实际如果是简单表格的话,可以自行增加class来实现 底层框架/原理 sortablejs 核心的拖拽原理,我们通过使用sortablejs提供的dom拖拽方案,实现 我们通过让sortablejs的el参数指定到el-table的header上 const query = ".el-table__header-wrapper thead tr" const el docuemnt.querySelector(query) // this.$el.querySelector(query) 那么表头的那一行的所有th就变为拖拽目标了,之后根据index的顺序变化,可以反推到列的切换上 核心代码 const sortable = new Sortable(el, { onEnd(evt) { let { newIndex, oldIndex, item } = evt; // 通知上级交换column位置 } }) 其他一些实现 跨表格实现 跨表格实现思路在于,通过在window上建立一个桥接用的map 缓存table的dom => vue实例对应关系 const sortable = new Sortable(el, { onEnd(evt) { const { to, from, pullMode } = evt; const toContext = window.bridge.get(to) const fromContext = window.bridge.get(from) let { newIndex, oldIndex, item } = evt; // 通知from和to对应的数据进行切换即可 } }) 拖拽优化 虽然核心代码很简单,但是不够完美,拖拽的时候只有表头可以进行拖动,实际上整列是没有跟着一起拖动的 所以我们需要进行样式上的优化,主要有两点 拖拽时候的影子 该列所有td跟随表头拖动 ...

December 11, 2021 · 5 min · 875 words · 水华

el-table拖拽开发实践

当前使用的 element-ui-el-table-draggable 提供了对element-ui内el-table的行进行拖拽排序的能力 不足之处 element-ui-el-table-draggable 只能配置两个参数,不支持列拖拽,不支持类似group等参数 改进和开发记录 基本属于重写了, 根据核心原理做了一个出来, 也就是,dom结构使用.el-table__body-wrapper tbody,然后直接交换el-table这个data对应index的数据 重点提示,需要给el-table增加row-key,保证交换之后重新渲染的数据正确!!! const elTableContext = this.$children[0] // 因为是通过slot引入 const container = elTableContext.$el.querySelector('.el-table__body-wrapper tbody') Sortable.create(container, { onEnd(evt) { let { newIndex, oldIndex, } = evt // 交换elTableContext.data里的位置,不展开了 exchange(oldIndex, newIndex) this.$emit('sort') } }) 之后我们解决几个核心问题 不能使用sortable.js的配置(例如group属性来多列表之间拖拽) 跨表格数据更新 支持列拖拽 expanded的row特殊处理 空处理 sortable.js配置 这个好解决,一方面是可以配置props, 另一方面,我们可以使用$attrs这个属性,将未在props内定义的属性直接获取 Sortable.create(container, { ...this.$attrs, // sortable的onXXX事件转为vue的事件格式emit掉 ...Object.keys(this.$listeners).reduce((events, key) => { const handler = this.$listeners[key] // 首字母大写 const eventName = `on${key.replace(/\b(\w)(\w*)/g, function($0, $1, $2) { return $1.toUpperCase() + $2.toLowerCase() })}` events[eventName] = (...args) => handler(...args) return events }, {}), onEnd(evt) { // 之前的处理代码 this.$emit('end', evt) }, }) 同时增加一个监听,自动更新对应的参数 ...

August 2, 2021 · 2 min · 295 words · 水华

借助Blazor在浏览器运行dotnet代码

借助Blazor在浏览器运行dotnet代码 本文重点,想看步骤的请直接移步正文 如何精简Blazor的代码,移除界面部分 如何和c#部分交互 如何访问FS部分 打包构建 因为工作上的需要,需要在网页上进行usm格式的视频,但是usm的视频格式并没有相关的说明,导致也没办法和之前一样直接通过读取二进制流的方式解码然后转mp4流喂给<video> 不过业内也都是使用CriDemuxer来对usm视频格式进行解交织的,而且CriDemuxer有开源,只不过代码是基于C#的,所以最后问题变成了,怎么在网页中运行C#代码 碎碎念结束 BLAZOR 目前将c#运行在浏览器端主要靠编译成wasm运行,在net5之前,想让dotnet多端运行就得借助mono进行编译,然后mono有推出过一个mono-wasm0.1的包,可以将编译为wasm可以因为维护的原因,已经下不到了 不过好在微软官方有一个借助mono-wasm的项目 Blazor 来实现用 C# 来构建网页,虽然用不上他的页面功能,但是四舍五入一下,却可以用它来实现在浏览器端运行 C# 代码 实现步骤 安装环境 根据官方教程即可 https://dotnet.microsoft.com/apps/aspnet/web-apps/blazor 创建项目 我们创建一个基于wasm的app dotnet new blazorwasm -o BlazorApp --no-https 然后项目就创建完了,记住和官方教程不一样,是blazorwasm dev cd BlazorApp dotnet watch run 一个基础项目就起来了,之后开始进行改造 移除页面相关文件 目录 pages Shared 文件 App.razor _Imports.razor 修改 Program.cs移除` builder.RootComponents.Add("#app"); `这行 这个时候运行,页面上应该就只有一个Loading...了,如果觉得难受,可以修改wwwroot下的index.html文件 编写代码 之后整个项目其实就是一个标准的dotnet项目了,可以直接将编写的代码移动进来,比如我这里就直接把CriDemuxerCore的代码直接移动进来 编写调用代码 在Program.cs内注入相关的js入口即可 这样的话,在浏览器内就能调用c#的代码了 using Microsoft.JSInterop; [JSInvokable] public static async Task<string> Demux(string filePath) { if (File.Exists(filePath)) { MpegStream.DemuxOptionsStruct demuxOptions = new MpegStream.DemuxOptionsStruct(); demuxOptions.ExtractVideo = true; return await Task.Run(() => { Console.WriteLine("Start"); CriUsmStream criUsmStream = new CriUsmStream(filePath); return criUsmStream.DemultiplexStreams(demuxOptions)[0]; }); } else { throw new Exception(filePath + " Not exists"); } } 在浏览器中的调用方法 ...

May 10, 2021 · 1 min · 134 words · 水华

用JS去读取【MMD】中vmd文件的那些事

未来能用js编写的软件,都会用js编写 前言 MikuMikuDance,简称MMD,如果是b站用户的话,应该都看到过一个专门的mmd分区,里面是各类舞蹈视频,这个是早期(真的很久了)给v家角色制作舞蹈动画的一个软件,当然除了v家6人以外,崩坏3,元神各类角色相关的宅舞投稿都有 mmd其实本质上还是一款三维动画制作软件,包含 模型 动作 关键帧等一系列相关的概念,模型的话,TGA式,大妈式,很多都有相关的配布,模型和镜头也有相关的发布,其实相关产业已经很完善了,但是这一次,我打算对mmd中保存动作,镜头,表情和关键帧的VMD(Vocaload Mation Data)文件下手了,当然主要还是因为。。。 mmd不支持mac!我不想装windows啊,作为前端工程师的我,如果想实现类似的渲染,那么,一方面是需要搞定模型的渲染**(Tree.js永远的神)**,另一方面就是能够编辑解析其中的vmd文件了 当然,为了解决动作的问题, 一方面,mmd提供了kinect进行捕捉,另一方面,我也想试试用posenet来解析动作,不过在这之前,先得吧vmd搞定 顺便,练习一下用js读取二进制流嘛 几个概念 二进制流 文件其实就是一堆 0,1 组成的二进制码流,在javascript的世界中,这种文件叫做ArrayBuffer, 虽然我们不能直接操作,但是做相应的读取还是没用问题的 你不能直接操作 ArrayBuffer 的内容,而是要通过类型数组对象或 DataView 对象来操作,它们会将缓冲区中的数据表示为特定的格式,并通过这些格式来读写缓冲区的内容。 用js获取二进制流有几种办法,最常用的就是从file直接转过来,这里我们通过FileReader即可 FileReader 接口提供的 readAsArrayBuffer() 方法用于启动读取指定的 Blob 或 File 内容。当读取操作完成时,readyState 变成 DONE(已完成),并触发 loadend 事件,同时 result 属性中将包含一个 ArrayBuffer 对象以表示所读取文件的数据。 当然啦,还有很多种办法,比如把请求头设置成arrayBuffer等等,这里请查阅相关的文档吧 TypedArray 在真实的使用场景(比如其他语言体系,例如c)其实对bytes有很多种不同的编码方案,用来表示不同的类型,int型一般2个字节这种,在js中也有相对应的TypedArrays 只要参考对照表,其实读取方面就比较简单了 VMD文件的格式 光有文件流,还需要一套相应的读取方案才行,感谢国内两位大佬的相关文章,解惑了 ...

December 6, 2020 · 2 min · 235 words · 水华

前端工程师该如何愉快的用Excel画画

虽然微软推出的Excel是一个强大的表格工具,但是世界上总有那么些人可以把一些常见的东西玩出花来就像日本老人用Excel画画一样 当然,作为一个程序员,当然还是靠程序自动来画啦 需要了解的知识 canvas html5新增加的一种html元素,平时都是把它当作画布使用,但是正因为有了操纵像素的能力 其也能用在播放视频,截图,压缩图片等操作上,当然啦,这一次,我们主要用到它的像素分析能力 getContext canvas最常用的api,获取一个用来画画的上下文,图片一般都是2d格式,所以我们通常用getContext(2d) drawImage 将图片绘制到canvas上,这样才能获取到每个点的信息 getImageData 获取到canvas的图像信息,不过返回值中的data是个被打平的一位数组 每四个值代表了一组rgba input 这里我们靠input来获取输入值 accept属性 image/*来限定只能选择图片,不过某些浏览器上因为要从国外获取mime的原因,推荐还是写成image/png,image/jpg 获取选中的图片 onchange 如果选择了图片,会触发change这个事件,我们对此监听即可,e.target为触发事件的input,我们取他的files[0]拿到图片对象 注意如果再点击选择同一图片的话,是不会触发事件的,所以每次获取之后推荐e.target.value = “”来清空掉已选择的文件 fileReader 我们获取到的图片仅仅只是个file是没办法直接转换成一个图片元素来获取宽高和放置在canvas内的,所以我们需要借助fileReader的力量 新建一个const fileReader = new FileReader() 然后在fileReader的onload回调中获取e.result作为url 那么如何开始读取?用fileReader.readAsDataURL(file)就行,之后再将这个url生成一个image就可以使用上文提到的drawImage方法了 image 和fileReader有点类似,需要const image = new Image(), image.src = url之后在onload回调中继续 exceljs 本次的导出框架,控制了每个excel格子的背景之后生成Array Buffer 开始工作 既然有了知识储备,就开始规划一下步骤吧 做一个<input type=“file” accept=“image/*”>的按钮 在其change事件中获取file file转image 新建一个canvas元素,将image绘制上去,同时控制canvas宽高和image一致 用getImageData获取每个像素信息 像素信息我们再根据图片宽高转一个二维数组 用二维数组在excel中改变对应格子的背景色 导出excel 具体实现代码在https://github.com/mizuka-wu/image2excel上 可改进的点 图片太大会崩溃 规定最大大小,因为excel只能缩放到10% 自动压缩 图片大小检测 进度条 转移到webworker上做一部分工作 想直接使用?访问我做好的demo吧

May 14, 2020 · 1 min · 65 words · 水华

关于element-ui 自适应高度的问题以及解决思路

起因 还是接手了之前同事的代码,之前他的代码遗留了一个历史问题,一个element-ui的表格高度只有500 当然,在开发用的mac电脑上看还是很正常的,但是在实际的业务场景中,会有一些使用人使用的是一些大号的屏幕,实际效果上表格只占了页面的一小部分,又因为表格的内容很多,所以空了一大块页面,但是浏览数据却需要不停的滚轮 改进过程 分析要做什么 首先分析了一波造成这样现象的原因,发现是element-ui table的高度被钉死了,但是又由于是历史项目,页面被包裹在一个iframe里,同时element-ui不支持使用auto属性 综上所述,为了一个顺溜的滚动条体验,只能让table自动填满剩余高度了,盘算了一下需要做 监听页面大小变化 防抖,省的卡顿 获取剩余高度 设定一个最小高度 做好各类检测,防止报错 开写 监听问题 window.addEventListener(‘resize’, handler) 记得也要在对应时间销毁 防抖 这里直接上debounce 高度 首先获取页面高度window.innerHeight 然后获取table距离顶部的高度el.getBoundingClientRect().top 这里有个小问题,就是定义的高度是body的高度,但是剩余区域是包括head的所以我们获取对应的高度el.querySelector(‘.el-table__header-wrapper’).offsetHeight 空余高度计算Math.max(innerHeight - offsetTop - tableHeaderHeight - OFFSET_BUTTON, MIN_TABLE_MAX_HEIGHT) 这个是考虑了一个最小高度和空余页面底部距离的算式 整合 const TABLE_OFFSET_BOTTOM = 10 const MIN_TABLE_MAX_HEIGHT = 500 window.addEventListener(‘resize’, _.debounce(function() { const innerHeight = window.innerHeight const table = document.getElementById(‘table’) if (!table) { return } const offsetTop = table.getBoundingClientRect().top const tableHeaderHeight = table.querySelector(‘.el-table__header-wrapper’).offsetHeight const maxTableHeight = Math.max(innerHeight - offsetTop - tableHeaderHeight - TABLE_OFFSET_BOTTOM, MIN_TABLE_MAX_HEIGHT) // 改变element的参数即可 },300)) 结果 很完美,哎嘿 ...

April 9, 2020 · 1 min · 82 words · 水华

给你的vuepress站点加个live2d吧

很早以前,个人博客站点用的是hexo构建的,当时因为好玩给自己的站点加了一个live2d挂件,现在倒是将博客迁移到了vuepress上,可是找了半天没有一个vuepress的插件可以让我使用自定义的live2d模型,没办法只能自己封装了一个 如何使用 基于pixi-live2d-display我封装了一个vuepress插件,叫vuepress-plugin-pixi-live2d-display,可以自定义传入model的地址 不过只支持model3之后的模型版本 安装 npm i vuepress-plugin-pixi-live2d-display or yarn add vuepress-plugin-pixi-live2d-display 上传模型 可以上传到第三方平台比如oss, 或者在vuepress的.vuepress/public文件夹下 拿到对应的model3.json文件地址 添加配置 在.vuepress.config.js中添加 module.exports = { plugins: [ ['vuepress-plugin-pixi-live2d-display', { model: "你的模型地址" }] ] } 就可以使用啦 当然,因为底层依赖包是通过script引入的,本身存在时间差,所以live2d加载一开始会比较慢,也有可能会因为依赖库未加载完成报错 其他还有一些配置参数可以参考组件配置https://www.npmjs.com/package/vuepress-plugin-pixi-live2d-display

March 9, 2020 · 1 min · 33 words · 水华