Flex是咋回事之三 谁用谁知道

本文全面解析Flex技术的优势与局限,从技术、开发者、企业和用户四个角度深入探讨,并提供优化建议。
Flex是咋回事之三 谁用谁知道
2010年09月21日
  一项技术,从概念提出到技术研发到商业发布,再到实际应用,最终将产品呈现在用户面前,这是一个漫长而复杂的过程。在这当中,很多有创意有生命力的技术因为各种原因小小遗憾地不幸夭折了。Flex能走到今天确实不易,下面让我们从不同的角度来看一下它是如何过关斩将,赢得众多青睐的。
  技术角度:
  (1)具备了RIA时代富客户端的优点(C/S+B/S)
  (2)支持多种服务器语言(JAVA、.NET、PHP)及主流框架(Spring、Hibernate)
  (3)与Java结合后相当强大,能充分利用Java的资源背景
  (4)拥有丰富的组件和第三方组件,对企业级的数据汇总和业务流程展现力较强悍
  (5)借助开源的力量,拥有众多民间组织和牛人支持
  (6)Adobe公司(还有MM多年积累)的强大背景
  (7)源于Flash的天生丽质,轻松使用多媒体资源,动态交互性强
  (8)借助FlashPlayer的安装普及度,轻松实现跨浏览器跨平台
  (9)良好的架构设计和制作精良的文档示例(明年FLEX4同步推出中文版)
  (10)借助于插件丰富的Eclipse开发平台并拥有独立的IDE
  (11)框架设计重用性高,有利于模块化设计
  (12)近几年发展态势良好,获得了广泛认可,产品和技术也越发成熟
  开发者角度:
  (1)开源,透明(国人没有不喜欢开源的,哈哈)
  (2)基于Eclipse开发平台,易上手,且插件丰富(巨人的肩膀啊~)
  (3)基于Eclipse平台,开发调试方便(FB4中的条件断点)
  (4)ActionScript语言与Java的融合度和相似度较高,易学易用
  (5)MXML标签与XML相似,逻辑清晰可读性强
  (6)架构设计良好,耦合度低,有利于组件重用
  (7)无需针对不同浏览器编写代码,摆脱编写和调试的噩梦(针对JS说的)
  (8)类似VB的可视化拖拽组件,快速创建界面
  (9)方便定制及使用第三方的皮肤和样式,无需美工也有好效果
  (10)支持多媒体资源,轻易开发动态交互性强的界面
  (11)众多的RPC组件保障对后台数据访问的安全性和效率
  (12)文档示例丰富,通过网络可以获取大量的学习资源
  (13)近两年发展态势良好,前景光明
  企业角度:
  (1)开源,免费(其实很多时候还是直接用破解的。。。)
  (2)具备了RIA时代富客户端的优点(C/S+B/S)(潮流啊~!)
  (3)项目和组件的重用性高,易于资源积累和快速构建
  (4)Flex提供了与其他语言的结合,能广泛利用已有的资源
  (5)界面华丽,客户认可度高
  (6)学习曲线一般,培训成本低
  用户角度:
  (1)部署和更新方便
  (2)界面漂亮,交互性强
  (3)安全
  说了这么多好话,再来综合说一下缺点。鉴于我着迷于Flex的光环效应,没有看到的缺点还请诸位多多提出。
  缺点:
  (1)不擅长处理复杂的业务流程,主要还是适合展现(Flex不是万能的)
  (2)继承了Flash的诸多优点,却唯独丢掉了Flash的小巧轻盈(减肥是永恒的话题)
  (3)目前尚没有比较好的减肥策略,带宽较好时这不是问题(不是一般的卡。。。)
  (4)对服务器和客户端的硬件设备都有一定要求(CPU和内存占用很生猛。。。)
  (5)运行期内存泄露状况严重,尽管可以通过一定手段改善(这个很崩溃)
  (6)对一些较专业的领域涉及较少,需要第三方组件支持(比如地质方面的)
  (7)Adobe公司对中国分部的支持不够(感觉宣讲和文档都做得不够)
  (8)搜索引擎对swf文件的支持不够(Adobe一直在努力)
  (9)与以往浏览习惯不同,比如右键被屏蔽,图片无法保存(可以改善)
  鉴于Flex生成的swf文件太肥是其主要缺点(加载慢,运行慢,内存占用多),我就主要从减肥和优化的角度来说一下使用心得。
  使用心得:
  (1)Flex只是前台展现,需要搭配强大的后台(注意前后台的均衡和优化)
  (2)考虑异步加载(比如分步加载外部资源)
  (3)界面推荐使用相对布局,合理组合,避免多余嵌套 (4)界面加载图片推荐使用外部加载方式,尽可能多使用矢量图形
  (5)规范CSS样式表,尤其注意使用的外部字体大小
  (6)使用额外的皮肤和特效时需要综合考虑生成的文件大小和执行效率
  (7)适当地考虑延时加载策略,主界面只显示必要的内容
  (8)规范编码,提高执行效率,避免内存泄露
  (9)使用RSL和Module和其他有效方式努力减肥
  (10)尽可能重写一些继承底层类的组件,执行效率更好
  (11)慎重使用重量级组件(比如DataGrid,AdvancedDataGrid)
<template> <div class="classification-container"> <div class="config-panel"> <el-form class="classification-form" :model="form" label-width="120px"> <!-- Task Selection --> <el-form-item size="large" label="分类任务"> <el-select v-model="form.taskSelection" placeholder="请选择分类任务" clearable @change="handleTaskSelectionChange" > <el-option label="传统分类" value="传统分类" /> <el-option label="小样本分类" value="小样本分类" /> </el-select> </el-form-item> <!-- Traditional Classification Section --> <template v-if="form.taskSelection === '传统分类'"> <el-form-item size="large" label="分类模型"> <el-select v-model="form.model" placeholder="请选择分类模型"> <el-option v-for="item in modelList" :key="item.value" :label="item.label" :value="item.value" /> </el-select> </el-form-item> <el-form-item size="large" label="图片上传"> <el-upload class="image-uploader" action="#" :auto-upload="false" :on-change="handleTraditionalUpload" :file-list="traditionalFileList" multiple accept="image/*" list-type="picture-card" > <div class="upload-content"> <i class="el-icon-picture-outline upload-icon"></i> <div class="upload-text">点击选择文件上传</div> </div> </el-upload> </el-form-item> <el-form-item class="action-buttons"> <el-button type="primary" size="large" @click="sendFormDataToBackend"> 开始分类 </el-button> <el-button size="large" @click="handleRemoveAll"> 取消 </el-button> </el-form-item> </template> <!-- Few-shot Classification Section --> <template v-if="form.taskSelection === '小样本分类'"> <el-form-item size="large" label="分类模型"> <el-select v-model="form.model" placeholder="请选择分类模型"> <el-option v-for="item in fewmodelList" :key="item.value" :label="item.label" :value="item.value" /> </el-select> </el-form-item> <el-form-item size="large" label="小样本任务"> <el-select v-model="form.fewShotSelectionArray" placeholder="请选择小样本任务" clearable > <el-option label="3way-1shot" value="[3,1]" /> <el-option label="3way-5shot" value="[3,5]" /> <el-option label="5way-1shot" value="[5,1]" /> <el-option label="5way-5shot" value="[5,5]" /> </el-select> </el-form-item> <el-form-item label="支持集类别"> <div class="category-input"> <el-input v-model="newSupportCategory" placeholder="请输入支持集类别" size="large" /> <el-button type="primary" size="large" @click="addSupportCategory" > 添加 </el-button> </div> </el-form-item> <div class="category-tags"> <el-tag v-for="(category, index) in form.supportCategories" :key="index" closable @close="removeSupportCategory(index)" > {{ category }} </el-tag> </div> <el-form-item size="large" label="支持集图片"> <el-upload class="image-uploader" action="#" :auto-upload="false" :on-change="(file, fileList) => handleFewShotUpload(file, fileList, 'support')" :file-list="supportFileList" multiple accept="image/*" list-type="picture-card" > <div class="upload-content"> <i class="el-icon-picture-outline upload-icon"></i> <div class="upload-text">点击选择支持集文件</div> </div> </el-upload> </el-form-item> <el-form-item size="large" label="查询集图片"> <el-upload class="image-uploader" action="#" :auto-upload="false" :on-change="(file, fileList) => handleFewShotUpload(file, fileList, 'query')" :file-list="queryFileList" multiple accept="image/*" list-type="picture-card" > <div class="upload-content"> <i class="el-icon-picture-outline upload-icon"></i> <div class="upload-text">点击选择查询集文件</div> </div> </el-upload> </el-form-item> <el-form-item class="action-buttons"> <el-button type="primary" size="large" @click="sendFormDataToBackend"> 开始分类 </el-button> <el-button size="large" @click="handleRemoveAll"> 取消 </el-button> </el-form-item> </template> </el-form> </div> <div class="result-panel"> <el-table :data="resultData" border stripe style="width: 100%" height="100%" :header-cell-style="tableHeaderColor" > <el-table-column type="index" label="序号" width="80" align="center" /> <el-table-column prop="name" label="图片名称" align="center" /> <el-table-column label="图片预览" align="center" > <template slot-scope="scope"> <img :src="scope.row.preview" alt="图片预览" class="preview-image" @click="previewImage(scope.row.preview)" /> </template> </el-table-column> <el-table-column prop="prediction" label="分类结果" align="center" /> </el-table> </div> </div> </template> <script> import axios from "axios"; export default { data() { return { form: { taskSelection: '', model: '', fewShotSelectionArray: '', supportCategories: [], images: [], supportImages: [], queryImages: [] }, modelList: [ { label: 'ResNet18', value: 'resnet18' }, { label: 'ResNet34', value: 'resnet34' }, { label: 'ResNet50', value: 'resnet50' }, { label: 'ViT-B/16', value: 'vit_b_16' }, { label: 'ViT-L/16', value: 'vit_l_16' } ], fewmodelList: [ { label: 'CERE', value: 'CERE' } ], traditionalFileList: [], supportFileList: [], queryFileList: [], resultData: [], newSupportCategory: '' } }, methods: { /* 修改表头颜色 */ tableHeaderColor({ rowIndex }) { if (rowIndex === 0) { return 'background-color: #00A8A0;color: #fff;font-weight: 500;' } }, handleTaskSelectionChange(value) { this.resetForm(); if (value === '传统分类') { this.form.fewShotSelectionArray = ''; this.form.model = ''; } else if (value === '小样本分类') { this.form.model = ''; } }, handleTraditionalUpload(file, fileList) { this.traditionalFileList = fileList; this.form.images = fileList.map(f => f.raw); this.updateResultData(); }, handleFewShotUpload(file, fileList, type) { if (type === 'support') { this.supportFileList = fileList; this.form.supportImages = fileList.map(f => f.raw); } else { this.queryFileList = fileList; this.form.queryImages = fileList.map(f => f.raw); } this.updateResultData(); }, updateResultData() { if (this.form.taskSelection === '传统分类') { this.resultData = this.traditionalFileList.map(file => ({ name: file.name, preview: URL.createObjectURL(file.raw), prediction: '' })); } else { this.resultData = this.queryFileList.map(file => ({ name: file.name, preview: URL.createObjectURL(file.raw), prediction: '' })); } }, addSupportCategory() { const trimmedCategory = this.newSupportCategory.trim(); if (trimmedCategory && !this.form.supportCategories.includes(trimmedCategory)) { this.form.supportCategories.push(trimmedCategory); this.newSupportCategory = ''; } }, removeSupportCategory(index) { this.form.supportCategories.splice(index, 1); }, previewImage(imgPath) { this.$viewerApi({ images: [imgPath] }); }, resetForm() { this.traditionalFileList = []; this.supportFileList = []; this.queryFileList = []; this.form.images = []; this.form.supportImages = []; this.form.queryImages = []; this.form.supportCategories = []; this.resultData = []; }, handleRemoveAll() { this.resetForm(); }, async sendFormDataToBackend() { if (!this.form.model) { this.$message.error('请选择分类模型'); return; } if ((this.form.taskSelection === '小样本分类' && this.queryFileList.length === 0) || (this.form.taskSelection === '传统分类' && this.traditionalFileList.length === 0)) { this.$message.error('请上传图片'); return; } if (this.form.taskSelection === '小样本分类' && this.form.supportCategories.length === 0) { this.$message.error('请添加支持集类别'); return; } const formData = new FormData(); formData.append('model', this.form.model); formData.append('task_type', this.form.taskSelection); if (this.form.taskSelection === '传统分类') { this.traditionalFileList.forEach((file) => { formData.append('images', file.raw); }); } else { this.queryFileList.forEach((file) => { formData.append('query_images', file.raw); }); this.supportFileList.forEach((file) => { formData.append('support_images', file.raw); }); if (this.form.fewShotSelectionArray) { const [way, shot] = JSON.parse(this.form.fewShotSelectionArray); formData.append('way', way); formData.append('shot', shot); } formData.append('categories', JSON.stringify(this.form.supportCategories)); } try { const loading = this.$loading({ lock: true, text: '正在分类中...', spinner: 'el-icon-loading', background: 'rgba(0, 0, 0, 0.7)' }); const response = await axios.post( 'http://192.168.200.60:5010/classification/classify', formData, { headers: { 'Content-Type': 'multipart/form-data' } } ); if (response.data) { this.resultData = this.resultData.map(item => { const classificationResult = response.data[item.name]; return { ...item, prediction: classificationResult || '未知' }; }); } this.$message.success('分类成功'); loading.close(); } catch (error) { console.error('分类失败:', error); let errorMessage = '分类失败'; if (error.response) { errorMessage += ': ' + ( error.response.data.message || error.response.data.error || error.response.statusText ); } else if (error.message) { errorMessage += ': ' + error.message; } this.$message.error(errorMessage); } finally { if (this.$loading) { this.$loading().close(); } } } }, beforeDestroy() { this.resultData.forEach(item => { if (item.preview) { URL.revokeObjectURL(item.preview); } }); } } </script> <style lang="scss" scoped> .classification-container { display: grid; grid-template-columns: 1fr 2fr; gap: 20px; height: 100%; padding: 20px; box-sizing: border-box; background-color: #f5f7fa; } .config-panel { padding: 20px; background-color: white; border-radius: 8px; box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1); overflow: auto; } .result-panel { padding: 20px; background-color: white; border-radius: 8px; box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1); display: flex; flex-direction: column; } .classification-form { max-width: 600px; margin: 0 auto; .el-select { width: 100%; } } .category-input { display: flex; gap: 10px; .el-input { flex: 1; } } .category-tags { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0 20px 120px; } .image-uploader { ::v-deep .el-upload { width: 100%; height: 150px; display: flex; justify-content: center; align-items: center; border: 2px dashed #00A8A0; border-radius: 8px; background-color: rgba(0, 168, 160, 0.03); transition: all 0.3s ease; &:hover { border-color: #009688; background-color: rgba(0, 168, 160, 0.05); } } ::v-deep .el-upload-list--picture-card { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 15px; .el-upload-list__item { width: 100px; height: 100px; } } } .upload-content { display: flex; flex-direction: column; align-items: center; justify-content: center; color: #00A8A0; .upload-icon { font-size: 40px; margin-bottom: 10px; } .upload-text { font-size: 16px; line-height: 1.5; } } .action-buttons { display: flex; justify-content: space-between; .el-button { flex: 1; &:first-child { margin-right: 10px; } } } .preview-image { max-width: 100px; max-height: 100px; cursor: pointer; display: block; margin: 0 auto; object-fit: contain; &:hover { transform: scale(1.05); transition: transform 0.2s ease; } } @media (max-width: 992px) { .classification-container { grid-template-columns: 1fr; } } @media (max-width: 768px) { .classification-form { padding: 10px; } .image-uploader { ::v-deep .el-upload-list--picture-card .el-upload-list__item { width: 80px; height: 80px; } } .category-tags { margin-left: 0; } } </style> if (this.form.taskSelection === '传统分类') { this.traditionalFileList.forEach((file) => { formData.append('images', file.raw); }); }有多个图片传入 图片键名相同,后端接收到只有一个图片咋回事
07-31
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值