目录
搞明白前端开发人员在企业中的占比,你才可以在学校或者即将毕业的时候选择出自己将要深入学习的开发语言。很多学校既要教C语言,又教单片机,既教java,也教前端开发知识,但老师的课是有限的,给留了作业,也许都不检查,下一课老师就要继续往下讲,因为这是他的工作,老师们也有生活,不可能围着某些人转,学不会就不往下开课了。
而搞懂前端开发在企业中的占比呢,能够更好的让你觉得如果自己比较平凡,得到什么等级可以卷得过别人,可以在这么多职位中占有一席之地。
很可喜的是,目前传统行业已经信息化改造完成,不管他们是内部系统,或者外部联合系统,都需要前端开发;我们每天看见大街上跑的汽车企业,某些电子企业,手机厂商,都需要前端开发的职位;更别提电商,直播这些我们生活所不可缺少的行业。但你还需要知道的是,如果你想学的一门服务端语言,java phython .net 或者其他,很可能这家公司就不会用,无形中给自己减少了很多工作机会。
以上的图,是从过去几年一直到今年(2022)年的各大公司的占比,毕竟是大厂嘛,对用户体验,前端接触到浏览器,最接近用户的要求肯定会高一些。
但是通过对多家中小公司的逐步了解发现,出去UI , 项目,产品,DBA, 运维等职位外,服务端开发与前端开发的比例几乎是1:1 ,甚至有的外包性质的公司,他们一旦产品成型后,新的客户换皮肤,更换界面的需求会更多,所以前端开发会需求更多一些。
此前有人戏称,是开发语言受欢迎,并非你受欢迎。但不得不说,某个开发语言受欢迎程度如果更加靠前,说明市场需求更大,更受欢迎,而将来准备从事某一种开发语言,也是非常关键的信息来源。
通过以上往年到今年的开发语言受欢迎程度发现,javascript这门前端必备的开发语言名列前茅,甚至在众多服务端开发语言中也不甘示弱,当然这之中并没有表明HTML CSS是一门开发语言,如果是的话,HTML CSS 也必将榜上有名,因为各行各业都不要网页对外公式自己的产品,但服务端开发语言五花八门,而前端必备javascript。
从web1.0时代,页面简单的只读时代,到web2.0时代,不断的交互,前端开发这个职位也在不断的进步。那么在未来的web3.0时代,很多人疑惑,可能PC的网页用处会越来越少,甚至不客气的说H5的页面也会少很多,据推测APP也会减少,未来将会有更多的数据整合产品出现。那么未来前端还会大有可为吗?
答案是肯定的,伟大的《红宝书》开头便说:javascript能做所有的事情,如果他能。而且nodejs的流行,也使前端可以更多的渗透到服务端开发,flutter的最新发布,WPA的使用,也使APP得到了更大的挑战,CSS3的不断进步,前端游戏引擎的盛行,也使前端有了更大的发展前景与选择,那么即便未来的元宇宙世界,相信前端javascript也一定能够勇往直前
如果这只是当下技术领域的一个缩影,可见比较活跃的的开发语言有java phython c mysql 然后才是javascript。从开发开发技术职位区分还是服务端和前端,但前端活跃度却比较靠后,不管是提问,回答,数量等维度上
说明什么问题呢?从事前端开发人数少吗?前端开发在学习,工作中没有问题吗?前端开发比较懒惰,不愿意上社区来参与活动吗?
我们知道nodejs可以做服务端开发,但是有多少企业敢于让从开始就搭上node serve的架子,不断让前端同学去尝试,不断在node领域发光发热,为整个行业添砖加瓦呢,很少吧。而几乎大部分公司,还是比较守旧的,从最开始的jSP时代,甚至不需要前端,服务端写完服务端代码,然后开始写JSP。JSP里再套java代码,顺带着添加一些javascript事件,样式怎么办,那个时候extjs jquery还非常盛行,easyui jqueryui 等,可以让服务端开发人员快速生产页面。
但随着提升用户体验的欲望越来越强烈,《国富论》开篇也讲分工带来的好处,前端才逐渐有了一席之地,甚至在一些大公司,前端的话语权可以超越服务端,他们通过技术驱动业务向前。
按照比例学可知,一旦某些事物达到一个数量后,某些细节世界也可以大体展现整体的宏观判断。那么我的理解是,在众多开发语言中,尽管javascript那么受欢迎,目前企业中前端占比还算不错,但总的来说,跟其他服务端开发语言总和来比,前端人员还是少。如果服务端语言像前端一样仅有javascript的话,我相信csdn问答模块这个业界缩影将不会是这种状态,甚至会大有不同。
其实很多老师,很多培训机构的老师教前端,大家各有各自的工作,各有各自的生活, 他知道来了一批学生,这是自己分内的工作,其实很多学生也只是停留在前端开发做网页的意识上,未来我想找到一份共走,可以养活自己。这无可厚非
其实日产工作还真就是做网页,做了C端做B端,做了PC做H5,嵌套到webview里,嵌套的APP的壳子里,这些都是工作。
小程序,各种各样的小程序;各种手机屏幕尺寸的适配;各种APP内部的嵌套;
做完了前端,开发点node层的工作吧,卷一卷,棒服务端同学减轻点工作压力;
再来点代码优化吧,如果将自己的代码调的代码量更少,如何不写注释也可以清晰明了,如何不得不写注释,可以写的更清楚;
来一点性能优化吧,现在出去面试,没做过性能优化都不好意思说自己做过工作。没办法,整体的需求缠身,但你却很少从中吸取知识,日复一日,到找工作那天发现,自己做的工作,其实都是劳动力。如何驱动自己,再寻求解决方案,再将性能指标不断提升。
卷一卷,读书破万卷。将自己的点子,自己的做法不断形成方法论,对内输出,乃至对外输出,提升影响力。
还要啥理想,向公共组件团队渗透,向技术栈所在团队渗透?
小插曲:这里加一个小插曲,promise解决了什么问题?这道题是不是必考题,千篇一律的答案是什么?解决了回调地狱?异步的工作我们当同步的来执行?
这算不算进步?这算不算创新?那么我就问问你,有回调地狱你的项目跑步起来了?用同步的写法来搞异步的事情降本增效了?
那么我就问问你,是你把之前的写法用上现在的promise节省的时间多,还是你每天摸鱼的时间多。说白了异步是一个需要花费时间的事情,因为有了异步,有了时间差,才使我们的工作出现了更多的可能性,不确定性。你更应该解决的是不是这个问题。
个人观点啊,没说promise不好,挺好的。
不管是在校或者迷茫的即将离校,一旦决定要学,不管是学哪种开发语言,都要坚定信心,切记不可三天打鱼,两天晒网;
这要看个人家庭的生活水平,一个家庭攻读出一个大学生实属不易,毕业后念培训班需要一定的资本支持。但对于很多人来说,没有学习方向,念培训班也是个选择,至少可以入个门;但大部分的培训课程对于目前的就业形势掌握不足,就像杨过刚去钟南山一样,练不够基本功,词汇一大堆,实战没多少,最后说啥名词都是666,一干活就挠头;
其实我根据自己的经验,也在筹备规划一套更卷,更适合入门到守门再到卸门的课程,我的目标就是更实用,更卷,更有助于大多数想学习的同学们,你需要的只是一句:我想学习,我要学习,我能学习,而不是马内。
现在网络上文章多的是,虽然很多不够系统,但正好够大家巩固当日知识点所用。学一定要用,用后一定要巩固,巩固后一定要举一反三形成自己的知识点,方法论,记录个博客啦,笔记啦,分享到身边的人,这样足可巩固无忧
知识点掌握的好不叫好,可以把知识点贯穿起来,做出一个市面上的东西,这算超越自我,切记不可自满,学完知识点就说自己精通,那只会在面试或者在工作的时候让自己更加烦恼,掉头发,熬夜。
做为初级开发,最重要的就是对于解决问题,有自己的一套手段,这样至少可以保证快速的完成需求。但如果想继续往上走,必须得有一些别人所没有的东西。这里说到举一反三,记得当时学习的时候,学完js基础需要写一个99乘法表,当时本来上课就少,硬生生把js的嵌套循环99乘法表写出来。晚上睡觉的时候想,如果纯用HTML CSS 是不是也能写出来,就这样,HTML的倒是好写,但CSS的又憋了很久,总算是写出来了。你就说,这样下去,谁能有我卷。现在我总结出了怎么利用纯HTML CSS JS 写出3版99乘法表,并且总结出了自己的文章,希望可以让初学者能够更快的入门。
分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务、UI设计公司、界面设计公司、UI设计服务公司、数据可视化设计公司、UI交互设计公司、高端网站设计公司、UI咨询、用户体验公司、软件界面设计公司
Web 开发是指在互联网上创建网站或 Web 应用程序。它涉及一系列任务,从开发网站的整体结构和设计到编写使网站栩栩如生的代码。Web 开发可能是一个复杂的过程,它通常涉及使用各种不同的技术,包括 HTML、CSS 和 JavaScript,以及服务器端语言,如 PHP、Ruby、Nodejs 和 Python。Web 开发人员可能在前端工作网站的一部分,这是用户与之交互的部分,或者在后端,这是处理网站幕后功能的部分。Web 开发是一个快速发展的领域,Web 开发人员需要跟上最新的技术和最佳实践,才能创建有效且引人入胜的网站和 Web 应用程序。
可以肯定地说,Web 开发将继续是一个重要且充满活力的领域。随着 Internet 的不断发展和演变,对 Web 开发人员的需求也可能会增加。Web 开发中使用的技术和工具也将继续发展和改进,这将使 Web 开发人员能够创建更先进、更复杂的网站和应用程序。此外,人工智能、虚拟现实和增强现实以及物联网等新技术的兴起可能会为网络开发人员带来新的机遇和挑战。Web 开发的未来看起来一片光明,对于那些对技术充满热情的人来说,它将继续是一个令人兴奋和有益的领域。
Web 开发是一个快速发展和动态的领域,由于 Web 应用程序开发的复杂性和多样性不断增加,因此对 Web 开发人员的需求量很大。
Web 开发人员有什么好的工作机会吗?答案是肯定的。互联网改变了我们的生活方式。如果您想加入一个令人兴奋的新行业来开发新技术,我们建议您这样做并成为一名网络开发人员。该技术不仅“防 covid”,而且相对抗衰退。
人们每天都越来越多地参与网络,并使用他们的智能手机和平板电脑访问互联网,因此对于网络开发人员来说,创建针对这些智能设备优化的网站和网络应用程序非常重要。
对于网站和应用程序而言,提供用户会喜欢的令人难忘的用户体验将变得更加重要。具有提供引人入胜的用户体验天赋的开发人员应该研究这些趋势带来的机会。
总之,每项 Web 技术的背后都有一支经验丰富、才华横溢的开发人员团队,他们负责更新、开发和维护它。技术每天都在发展,因此有才华的 Web 开发人员始终可用并存在非常重要。
网页开发和网页设计是两个经常混淆的独立领域。虽然它们是相关的,但它们是具有不同重点和目标的不同学科。
网页设计侧重于网站的美学和功能方面,涉及用户界面和用户体验的规划和创建。网页设计师负责网站的布局、配色方案和整体外观,以及网站的导航和用户流程。
另一方面,Web 开发侧重于构建网站的技术方面。这包括编写代码来创建网站的各种组件,例如前端和后端,并将它们集成以创建功能强大且可用的网站。Web 开发人员负责网站的实施和维护,并且可能会使用各种编程技能和框架来实现。
Web 开发人员是专门开发可通过 Web 浏览器访问 Internet 的应用程序和服务的程序员。Web 开发人员使用各种技术和语言(例如 HTML、CSS 和 JavaScript)来创建网站或 Web 应用程序的结构、布局和设计。
Web 开发人员负责构建和维护 Web 应用程序的各种组件,包括用户界面、服务器端逻辑和数据库。他们还可能负责将 Web 应用程序与其他系统和 API 集成,并负责实现增强用户体验的特性和功能。
总之,网页设计关注网站的视觉和面向用户的方面,而网页开发则关注网站的技术实现和功能。
前端开发人员是专门从事 Web 开发客户端的 Web 开发人员。他们负责构建和维护 Web 应用程序的用户界面和用户体验,包括布局、设计和交互性。
前端开发人员通常精通前端技术和语言,例如 HTML、CSS 和 JavaScript。他们负责实施 Web 应用程序的视觉设计,包括布局、排版和配色方案。他们还可能负责实现交互元素,例如按钮、表单和菜单,以及将 Web 应用程序与后端系统和 API 集成。
除了技术技能,前端开发人员还需要对用户体验和设计原则有深刻的理解。他们应该能够创建直观、用户友好且美观的 Web 应用程序。
前端开发是 Web 开发的重要组成部分,前端开发人员在创建 Web 应用程序的外观方面发挥着关键作用。
后端开发人员是专门从事 Web 开发服务器端的 Web 开发人员。他们负责构建和维护 Web 应用程序的底层逻辑和基础设施,包括服务器端逻辑、数据库和 API。
后端开发人员通常具有服务器端语言和技术方面的专业知识,例如 PHP、Python、Ruby 和 Node.js。他们负责实现 Web 应用程序的服务器端逻辑,包括业务规则、数据验证和用户身份验证。他们还可能负责设计和实施数据库模式,以及将 Web 应用程序与其他系统和 API 集成。
除了技术技能,后端开发人员还需要具备强大的问题解决、沟通和协作能力。他们应该能够批判性和逻辑性地思考,并能够设计和实施可扩展、可维护且高效的解决方案。
后端开发是 Web 开发的重要组成部分,后端开发人员在构建和维护 Web 应用程序的功能和性能方面发挥着关键作用。
全栈开发人员是在前端和后端开发方面都具有专业知识的 Web 开发人员。他们负责构建和维护整个 Web 应用程序,从用户界面和用户体验到底层服务器端逻辑和数据库。
全栈开发人员通常对用于构建 Web 应用程序的技术和语言有深入的了解,包括 HTML、CSS、JavaScript 和服务器端语言(如 PHP、Python 和 Ruby)。他们能够处理 Web 应用程序的所有层,从用户界面和用户体验到数据库和服务器端逻辑。
除了技术技能,全栈开发人员还需要具备强大的问题解决、沟通和协作能力。他们应该能够创造性和批判性地思考,并能够适应不断变化的技术和要求。
全栈开发是一个充满挑战和回报的领域,由于 Web 应用程序的复杂性和多样性不断增加,对全栈开发人员的需求量很大。
网站管理员负责构建、维护和更新网站。他们还可能负责将网站与其他系统或云服务集成,例如数据库和内容管理系统 (CMS),以及实施增强用户体验的特性和功能。
网站管理员通常与开发团队的其他成员(包括图形设计师、内容创建者和项目经理)密切合作,以创建和维护满足企业或组织需求的网站。他们还可以与客户合作以了解他们的要求并提供满足他们需求的解决方案。
如果你是 Web 开发的新手并且想知道从哪里开始以及第一步是什么,这里有一些建议:
学习 HTML 和 CSS 等 Web 开发基础知识——这些是 Web 的核心技术,良好的这些语言基础对于任何 Web 开发人员来说都是必不可少的。您可以从学习 HTML 和 CSS 的基础知识开始,例如网页的结构、如何添加内容和样式以及如何创建简单的静态网页。
选择开发环境——开发环境是一组用于构建和测试 Web 应用程序的工具和资源。这通常包括用于编写代码的文本编辑器或集成开发环境 (IDE)、用于测试网页的 Web 浏览器以及用于运行 Web 应用程序的本地 Web 服务器。带有大量插件的 vscode 编辑器肯定需要引起您的注意。
构建一个简单的网页——学习了 HTML 和 CSS 的基础知识后,尝试构建一个包含一些文本、图像和基本样式的简单网页。这将使您有机会练习所学的技能,并了解不同技术如何协同工作。然后更进一步,开始复制一些最流行的网络应用程序,然后 memic 尝试重新创建它,我指的只是这里的设计。
探索 Web 开发框架和库– 有许多可用的 Web 开发框架和库可以更轻松地构建 Web 应用程序。一些流行的选项包括 React、Angular、Vue.js 和 Django。一旦你确定了一个框架,立即开始学习它并坚持下去直到你掌握它。
HTML或超文本标记语言是一种用于创建和构建网页内容的编程语言。HTML使用一系列元素或标签来定义网页的结构和布局,包括标题、段落、列表和链接。HTML 还允许开发人员向网页添加图像、视频和其他多媒体内容,使其成为构建 Web 应用程序的强大且通用的语言。
定义带有标题、段落和图像的简单网页的 HTML 代码:
<!DOCTYPE html> <html> <head> <title>我的 Web 页面</title> </head> <body> <h1>Hello, World!</h1> <p>这是我的第一个 Web 页面</p> <img src="https://www.example.com/image.jpg" alt="A beautiful landscape"> </body> </html>
在此示例中,<html>和<body>标签定义了网页的结构,而<h1>、<p>和<img>标签定义了页面的内容。<img>标签的src属性指定要显示的图像的 URL,而alt属性为无法看到图像的用户提供图像的文本描述。所以你需要了解 HTML 标签和它们的属性。
CSS或层叠样式表是一种样式表语言,用于描述以标记语言编写的文档的外观和格式。在 Web 开发环境中,CSS 用于控制以 HTML 或其他标记语言编写的网页的外观和布局。CSS 允许开发人员为网页上的内容定义颜色、字体、大小和其他样式,使其成为构建现代响应式 Web 应用程序的重要组成部分。
可用于设置上述网页内容样式的 CSS 代码:
body { font-family: Arial, sans-serif; background-color: #f1f1f1; } h1 { color: #333; text-align: center; margin: 30px 0; } p { color: #777; font-size: 18px; line-height: 1.5; padding: 0 20px; } img { width: 100%; height: auto; }![]()
在此示例中,body选择器将样式应用于网页的<body>元素, h1选择器将样式应用于所有<h1>元素,p和img选择器将样式应用于所有<p>和<img>元素, 分别。此 CSS 代码中定义的样式指定页面及其元素的字体系列、背景颜色、文本对齐方式和其他属性。显示此示例演示了选择 HTML 元素的重要性以及需要使用哪些属性来设置它的样式。因此,了解所有类型的选择器以及它们需要的属性。
你可以使用 CSS 框架让您的生活更轻松。最受欢迎的是Bootstrap和Tailwind CSS,它们都是用于构建响应式、移动优先的 Web 应用程序的前端框架。这两个框架都提供了一组预定义的 CSS 类和组件,可以轻松地将它们合并到网页中,以创建一致的、具有专业外观的设计。Bootstrap 和 Tailwind CSS 是构建现代响应式 Web 应用程序的强大工具。这两个框架之间的选择将取决于您的个人喜好和项目的具体需求。
有许多不同的框架可用于 Web 开发,每个框架的流行程度取决于项目的具体需求以及开发人员、团队或公司的偏好。一些最流行的 Web 开发框架包括:
React: React 是用于构建用户界面的最多的javascript 框架之一。 许多公司都在使用它,并且拥有庞大的开发人员社区。
Angular: Angular 是一个基于 TypeScript 的开源 Web 应用程序框架,由 Google 的 Angular 团队以及个人和公司社区领导。
Vue.js: Vue.js 是一个用于构建用户界面的渐进式 JavaScript 框架。它旨在逐步采用并可以集成到现有项目中。
Ember.js: Ember.js 是一个用于构建大型 Web 应用程序的开源 JavaScript Web 框架。它以其约定优于配置方法和强调开发人员生产力而闻名。
以下编程语言列表可帮助您了解在成为 Web 开发人员的过程中您想要学习和追求的语言。大多数时候,选择将取决于您选择的框架或其他方式:
JavaScript——让我们从显而易见的最流行的 Web 开发编程语言开始,它是 JavaScript,它是一种用于构建前端 Web 应用程序的通用语言。它是一种客户端语言,这意味着它在用户的网络浏览器中运行,并允许开发人员创建交互式和动态网页。JavaScript 还通过 Node.js 等技术用于服务器端开发,它允许开发人员构建可扩展的高性能 Web 应用程序。
Python – Python 是一种高级解释型编程语言,广泛用于 Web 开发。它具有简单易学的语法,是初学者的绝佳选择。Python 还以其强大的库和框架而闻名,例如 Flask 和 Django,这使得快速构建复杂的 Web 应用程序变得容易。
Java – Java 是一种流行的面向对象的编程语言,广泛用于构建可扩展的高性能 Web 应用程序。它是一种通用语言,可用于为各种平台(包括桌面、移动和 Web)构建 Web 应用程序。
Ruby – Ruby 是一种高级解释型编程语言,通常用于 Web 开发。它以简单和优雅着称,使其成为想要快速轻松地构建 Web 应用程序的开发人员的热门选择。
PHP – PHP 是一种流行的脚本语言,广泛用于构建动态网站和 Web 应用程序。它是一种服务器端语言,这意味着它在网络服务器上运行并生成发送到用户网络浏览器的 HTML 页面。
C# – C# 是一种流行的面向对象的编程语言,通常用于构建 Web 应用程序。它是一种通用语言,可用于为各种平台(包括桌面、移动和 Web)构建 Web 应用程序。
Swift – Swift 是一种现代的编译型编程语言,通常用于构建 Web 应用程序。它是一种功能强大的语言,以其安全性和性能着称,使其成为构建需要处理大量数据或执行复杂计算的 Web 应用程序的绝佳选择。
Go – Go 是一种现代的编译型编程语言,通常用于构建 Web 应用程序。它是一种快速、高效的语言,以并发性和可扩展性着称,使其成为构建需要处理大量流量或数据的 Web 应用程序的绝佳选择。
TypeScript – TypeScript 是一种流行的类型化编程语言,通常用于构建大型、复杂的 Web 应用程序。它是 JavaScript 的超集,这意味着它包含 JavaScript 的所有功能,以及可以更轻松地构建大型、可维护的 Web 应用程序的附加功能。
Kotlin – Kotlin 是一种现代的编译型编程语言,通常用于构建 Web 应用程序。它是一种简洁、强大的语言,以其安全性和与 Java 的互操作性而著称,使其成为构建需要与现有 Java 代码集成的 Web 应用程序的绝佳选择。
追求网络开发职业道路可能是一个不错的选择,原因有很多。Web 开发职业的一些好处包括:
对 Web 开发人员的高需求:对 Web 开发人员的需求一直很高,并且预计在未来几年将继续增长。这意味着那些拥有技能和经验的人将有很多机会在这个领域取得成功。
高薪: Web 开发人员的薪水很高,薪水因经验、地点和其他因素而异。总的来说,Web 开发人员可以期望获得丰厚的薪水,并且成长和进步的潜力很大。
灵活性: Web 开发可以在工作地点和日程安排方面提供很大的灵活性。许多 Web 开发人员远程工作,并且能够设置自己的时间并按照灵活的时间表工作。
学习和成长的机会: Web 开发是一个不断变化的领域,新技术和工具不断涌现。这意味着作为 Web 开发人员,始终有学习和成长的机会,并保持在行业的前沿。
创造有形事物的满足感:作为一名 Web 开发人员,您将有机会创造有形且有用的事物。这可以令人难以置信地满足,并且可以为您的工作提供成就感和自豪感。
Web 开发的未来看起来一片光明,许多激动人心的发展和趋势即将出现。一些可能影响 Web 开发未来的最新 Web 开发趋势包括:
人工智能和机器学习的兴起:人工智能和机器学习在网络开发中变得越来越重要,出现了许多新的工具和框架来帮助开发人员构建人工智能驱动的应用程序。
物联网的发展:物联网 (IoT) 是一个由可以收集和共享数据的连接设备组成的网络,预计在未来几年将显着增长。这将为网络开发人员创造新的机会来构建可以连接这些设备并与之交互的应用程序。
移动设备的重要性日益增加:随着越来越多的人使用智能手机和其他移动设备访问网络,网络开发人员创建适合移动设备的应用程序和网站将变得越来越重要。
渐进式 Web 应用程序的兴起:渐进式 Web 应用程序 (PWA) 是外观和感觉都像本机移动应用程序的 Web 应用程序,并且有望在未来变得更加流行。这将为 Web 开发人员创造新的机会来构建可跨不同设备和平台提供无缝用户体验的 PWA。
云计算的发展:云计算在网络开发中变得越来越重要,许多公司将他们的应用程序和数据转移到云中。这将为 Web 开发人员创造新的机会来构建云原生应用程序并将它们与现有的云服务集成。
Web 开发仍然值得学习,因为它是构建和维护作为现代 Internet 支柱的网站和 Web 应用程序的基本技能。随着世界变得越来越紧密,对 Web 开发人员的需求不断增长,对于那些拥有构建和维护未来 Web 应用程序的技能和专业知识的人来说,有许多激动人心的机会。
Web 开发也是一个回报丰厚且具有挑战性的领域,它允许开发人员利用他们的创造力和解决问题的技能来构建供全球数百万人使用的应用程序。有了合适的工具和资源,任何人都可以学习 Web 开发并开始构建自己的 Web 应用程序,从而打开一个充满可能性和机遇的世界。
分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务、UI设计公司、界面设计公司、UI设计服务公司、数据可视化设计公司、UI交互设计公司、高端网站设计公司、UI咨询、用户体验公司、软件界面设计公司
Vuex 和 Pinia 是用于管理 Vue.js 应用程序状态的标准 Vue.js 库。让我们比较一下他们的代码、语言、功能和社区支持。
如果没有合适的库,开发人员管理应用程序的状态可能会很困难。Vuex 和 Pinia 是标准的 Vue.js 库,用于处理应用程序中的条件。这两个库都非常适合状态管理,但是由于它们出色的特性和功能,选择哪个库用于你的项目需要时间并且令人沮丧。好吧,我们将在本文中看看为什么一个是最好的。
在本文中,我们将通过实际代码示例查看代码比较、它们的变体、功能,以及推荐使用哪一个来管理你的状态应用程序,以便更好地理解。我们还将考虑每个产品的语言、功能和社区支持。
我将简要总结 Vuex 和 Pinia。如果你想要更详尽的解释,我建议阅读Vuex 文档和Pinia 文档。
Pinia是一个新的状态管理库,可帮助你在 Vue.js 应用程序中跨组件管理和存储响应数据和状态。Pinia 由 Vue 核心团队成员之一 Eduardo San Martin Morote 创建。
Pinia 使用新的反应系统来构建一个直观且完全类型化的状态管理系统。
库中引入的新特性是促成 Pinia 推荐的因素之一。总体而言,Pinia 显得轻巧、简单且易于掌握。它拥有可以使 Vue 3 和 Vue 2 中的编程变得通用的一切。因此,这是试用 Pinia 的理想机会。
Vuex是一种状态管理模式和库,构建为集中式存储,可帮助你维护 Vue 应用程序中存在的所有组件的状态。Vuex 遵循确保你的状态突变为预测标准的规则。
使 Vuex 更强大的一个因素是组件从 Vuex store 中获取它们的状态,并且可以快速有效地响应 store 状态的变化。
Vuex虽然是维护你store的状态管理库,但建议你熟悉或搭建过大型SPA。如果你没有经验,Vuex 可能会冗长且令人生畏。
如果你的应用程序很广泛,你需要管理复杂的数据流,并且你有嵌套的组件,你可以使用 Vuex。查看官方文档以获取有关何时使用 Vuex 的更多信息。
Pinia 和 Vuex 之间的区别之一是 Pinia 是“模块化设计”,换句话说,它被构建为拥有多个商店,而 Vuex 只有一个商店。在这些商店中,您可以拥有子模块。除此之外,Pinia 允许将这些模块中的每一个从他们的商店直接导入到需要的组件中。
如果您是一名 Vue 开发人员并且曾使用 Vuex 管理应用程序的状态,您会注意到 Vuex 只有一个商店。在该商店中,您可以在其中包含多个模块。使用 Pinia,您可以将这些模块中的每一个都存储在一个地方,并在需要时将它们直接导入到组件中。
此方法允许捆绑器自动对它们进行代码拆分,并提供更好的 TypeScript 推理。
Pinia 提供开发工具支持,以帮助您使用该库构建和轻松调试。当我们安装 Pinia 时,它会自动挂接到我们的 Vue.js 开发工具,并让我们跟踪对我们的商店所做的更改,这让我们在 Vue.js 版本(Vue 2 和 Vue3)中获得流畅的开发人员体验。
Pinia 提供了一个简单的 API,使您的商店的编写变得简单且井井有条,就像创建组件一样。这意味着与 Vuex 解决方案相比,需要掌握的样板文件和概念更少。
Pinia 还提供了一个完整的插件系统,具有交易和本地存储同步等功能,适用于 Pinia 默认行为不足的情况。
Pinia 提供比 Vuex 更好的 TypeScript 支持,具有 Javascript 自动完成功能,这使得开发过程变得简单。
Pinia 的重量只有 1 KB,因此很容易融入您的项目。这可能会提高您的应用程序性能。
当您的应用程序扩展时,遍历变得很困难。但是,使用 Vuex 模块,您可以根据领域功能将您的商店拆分为多个文件,并从该特定命名空间中的模块访问状态循环。
Vue devtools 中的 Vuex 选项卡允许我们查看状态并跟踪我们的变化。这使我们能够快速评估我们的程序如何执行和调试错误。
Vuex支持热重载功能,它使用 webpack 的热模块替换 API,可以在您开发时快速重载您的 mutations、modules、action 和 getters。
如果你想编写一个 TypeScript 存储定义,Vuex 可以提供它的类型并且更容易实现。它有一个默认的 TypeScript 配置,不需要额外的设置。
Pinia 是一个轻量级库,可帮助您管理整个应用程序的反应状态。与 Vuex 相比,Pinia API 易于学习,使您的代码更易于阅读。
让我们看一下使用 Pinia 和 Vuex 管理我们的状态的代码比较:
Vuex
在此示例中,我们将查看一个简单的 Vuex 存储,它跟踪待办事项列表项的状态:
import { createStore } from 'vuex' const TodoListstore = createStore({ state() { return { todoListItems: [] } }, actions: { addNewList({ commit }, item) { { commit('createNewItem', item) } }, mutations: { createNewItem(state, item) { state.todoListItems.push(item) } } })![]()
如果你看上面的代码,你可以看到 Vuex 存储中的三个动作:状态、 动作和突变。状态返回当前的todoListItems,动作提交一个突变来创建一个新项目,最后,突变创建新项目并将其添加到列表中。当你构建一个更大的应用程序时,你可能会意识到动作和突变相对相似,导致冗余代码,因为每个状态变化都需要一个样板。
Pinia
使用 Pinia 简单 API,您可以消除突变和冗余代码。让我们查看一个代码示例,了解当您使用 Pinia 实现之前的代码时的样子:
import { defineStore } from 'pinia' Export const useListStore = defineStore('list', { state() => ({ return { todoListItems: [] } }), actions: { addNewList() { this.todoListItems.push(item) } }})
上面的示例是 Pinia API 在管理应用程序状态时如何工作的简单代码。使用 Pinia,我们删除了突变并将其直接更新到我们的动作中。
注意:在上面的代码示例中,当我们将项目直接提交给我们的操作时,我们不需要跟踪我们的项目。
Pinia 和 Vuex 是控制应用程序状态的优秀工具,但其中一个必须具有另一个所没有的某些功能。让我们来看看它们是什么。
好吧,这就是它变得更具挑战性的地方,因为仍然有一些项目需要使用 Vuex 来处理状态应用程序,即使 Pinia 是新推荐的状态管理库。它有几个 Vuex 没有的有价值的功能。
Vuex 仍然是构建大型 SPA 的理想解决方案,因为对于构建中小型应用程序的人来说,它相当冗长。
Pinia 也一样。尽管如此,如果你需要所有列出的功能,例如 devtool 支持、TypeScript 支持和状态应用程序的轻松管理,那么 Pinia 是最好的解决方案——它为你提供流畅的开发体验。
如果你正在构建一个不太复杂的应用程序,无论是中等到广泛的应用程序,你都可以使用 Pinia,因为它的重量约为 1 KB。
由于功能多样,在管理应用程序状态时,在 Vuex 和 Pinia 之间进行选择可能会造成混淆。不过,这两个框架都非常适合管理状态应用程序。本文简要比较了它们的特性、功能和对代码的影响。读完这篇文章后,也许你将能够找到适合你的库。
分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务、UI设计公司、界面设计公司、UI设计服务公司、数据可视化设计公司、UI交互设计公司、高端网站设计公司、UI咨询、用户体验公司、软件界面设计公司
本文转载至 : Mac解压压缩 rar文件
RAR 5.60 for Mac OS Xwww.rarlab.com
cd ~/Downloads/rar
sudo install -c -o $USER rar /usr/local/bin/
sudo install -c -o $USER unrar /usr/local/bin
1,解压命令
//解压到当前目录
unrar x a.rar //解压到指定目录
unrar x a.rar ~/Downloads //解压文件到当前目录
unrar e test.rar //查看rar中的文件
unrar l test.rar //更详细Ï
unrar v test.rar //测试是否可以成功解压
unrar t test.rar
2,压缩命令
// 将file文件压缩到text.rar
rar a text.rar file
分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务、UI设计公司、界面设计公司、UI设计服务公司、数据可视化设计公司、UI交互设计公司、高端网站设计公司、UI咨询、用户体验公司、软件界面设计公司
我们会看到很多页面带有水印,但是怎么实现呢?当然可以有多种实现方式,本文主要讲解在vue项目中基于DOM或者Cavans实现水印效果,当然还有其他的实现方式,比如在原图片的基础上加上水印生成新的图片,但是这需要后端处理。因为要在vue项目中使用,所以我使用自定义指令可以直接对挂载的dom实现水印效果。
本文实现水印的项目环境为:vue + vite + ts
前面专门有一篇讲解vue2.x与vue3.x中自定义指令详解
将水印的指令放到标签上,设置标签的宽高。水印可以放大div标签上,也可以是img标签上。注意:img才有onload方法,div标签么有。
<script setup lang="ts"> import { ref } from "vue"; </script> <template> <div class="index-content" > <div class="watermaker" v-watermark ></div> <!-- <img v-watermark style="width:400px;height:400px" src="../assets/vue.svg" alt=""> --> </div> </template> <style scoped> .watermaker { width: 400px; height: 400px; } .index-content{ width: 100%; height: 100%; } </style>![]()
directives文件
在directives文件下创建waterMark.ts 文件,具体内容实现如下:
import waterImg from "@/assets/vue.svg" const directives: any = { mounted(el: HTMLElement) { //如果el元素是img,则可以用el.onload将下面包裹 const { clientWidth, clientHeight, parentElement } = el; console.log(parentElement, 'parentElement') const waterMark: HTMLElement = document.createElement('div'); const waterBg: HTMLElement = document.createElement('div'); //设置waterMark的class和style waterMark.className = `water-mark`; waterMark.setAttribute('style', ` display: inline-block; overflow: hidden; position: relative; width: ${clientWidth}px; height: ${clientHeight}px;`); // 创建waterBg的class和style waterBg.className = `water-mark-bg`;// 方便自定义展示结果 waterBg.setAttribute('style', ` position: absolute; pointer-events: none;`在这里插入代码片` transform: rotate(45deg); width: 100%; height: 100%; opacity: 0.2; background-image: url(${waterImg}); background-repeat: repeat; `); // 水印元素waterBg放到waterMark元素中 waterMark.appendChild(waterBg); //waterMark插入到el之前,即插入到绑定元素之前 parentElement?.insertBefore(waterMark, el); // 绑定元素移入到包裹水印的盒子 waterMark.appendChild(el); } } export default { name: 'watermark', directives }![]()
directives文件下创建 index.ts文件
import type { App } from 'vue' import watermark from './waterMark' export default function installDirective(app: App) { app.directive(watermark.name, watermark.directives); }
main.ts中全局引入
import { createApp } from 'vue' import App from './App.vue' import directives from './directives' const app = createApp(App); app.use(directives); app.mount('#app');
MutationObserver对水印元素进行监听,删除时,我们再立即生成一个水印元素就可以了,具体方面在下面讲解。
position:relative
position:absolute ,实现这个水印元素覆盖到原始元素的上层,以实现水印的效果。
通过将图片绘制在cavans中,然后通过cavans的toDataURL方法,将图片转为base64编码。
// 全局保存 canvas 和 div ,避免重复创建(单例模式) const globalCanvas = null; const globalWaterMark = null; // 获取 toDataURL 的结果 const getDataUrl = ( // font = "16px normal", // fillStyle = "rgba(180, 180, 180, 0.3)", // textAlign, // textBaseline, // text = "请勿外传", ) => { const rotate = -10; const canvas = globalCanvas || document.createElement("canvas"); const ctx = canvas.getContext("2d"); // 获取画布上下文 ctx.rotate((rotate * Math.PI) / 180); ctx.font = "16px normal"; ctx.fillStyle = "rgba(180, 180, 180, 0.3)"; ctx.textAlign = "left"; ctx.textBaseline = "middle"; ctx.fillText('请勿外传', canvas.width / 3, canvas.height / 2); return canvas.toDataURL("image/png"); };![]()
使用MutationObserver监听dom变化,MutationObserver详细用法之前已经讲过了,详细可见作为前端你还不懂MutationObserver?那Out了
具体监听逻辑如下:
// watermark 样式 let style = ` display: block; overflow: hidden; position: absolute; left: 0; top: 0; width: 100%; height: 100%; background-repeat: repeat; pointer-events: none;`; //设置水印 const setWaterMark = (el: HTMLElement, binding: any) => { const { parentElement } = el; // 获取对应的 canvas 画布相关的 base64 url const url = getDataUrl(binding); // 创建 waterMark 父元素 const waterMark = globalWaterMark || document.createElement("div"); waterMark.className = `water-mark`; // 方便自定义展示结果 style = `${style}background-image: url(${url});`; waterMark.setAttribute("style", style); // 将对应图片的父容器作为定位元素 parentElement.setAttribute("style", "position: relative;"); // 将图片元素移动到 waterMark 中 parentElement.appendChild(waterMark); }; // 监听 DOM 变化 const createObserver = (el: HTMLElement, binding: any) => { console.log(el, 'el') console.log(style, 'style') // console.log(el.parentElement.querySelector('.water-mark'),'el.parentElement') const waterMarkEl = el.parentElement.querySelector(".water-mark"); const observer = new MutationObserver((mutationsList) => { console.log(mutationsList, 'mutationsList') if (mutationsList.length) { const { removedNodes, type, target } = mutationsList[0]; const currStyle = waterMarkEl.getAttribute("style"); // console.log(currStyle, 'currStyle') // 证明被删除了 // (1)直接删除dom // 1.先获取设置水印的dom // 2.监听到被删除元素的dom // 如果他两相等的话就停止观察,初始化(设置水印+启动监控) // (2) 删除style中的属性 // 1 判断删除的是否是标签的属性 (type === "attributes") // 2.判断删除的标签属性是否是在设置水印的标签上 // 3.判断修改过的style和之前的style对比,不等的话,重新赋值 if (removedNodes[0] === waterMarkEl) { console.log(removedNodes[0]) // 停止观察。调用该方法后,DOM 再发生变动,也不会触发观察器。 observer.disconnect(); //初始化(设置水印,启动监控) init(el, binding); } else if ( type === "attributes" && target === waterMarkEl && currStyle !== style ) { console.log(currStyle, 'currStyle') console.log(style, 'style') waterMarkEl.setAttribute("style", style); } } }); observer.observe(el.parentElement, { childList: true, attributes: true, subtree: true, }); }; // 初始化 const init = (el: HTMLElement, binding: any = {}) => { // 设置水印 setWaterMark(el, binding.value); // 启动监控 createObserver(el, binding.value); }; const directives: any = { mounted(el: HTMLElement, binding: any) { //注意img有onload的方法,如果自定义指令注册在html标签的话,只需要init(el, binding.value) el.onload = init.bind(null, el, binding.value); }, };![]()
删除水印标签依然还在,除非删除水印注册的标签才能删除水印,但是这样做毫无意义,因为这样做内容也会全部删除掉。
toDataURL(type, encoderOptions),接收两个参数:
image/png、image/jpeg、image/webp等等,默认为image/png格式
分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务、UI设计公司、界面设计公司、UI设计服务公司、数据可视化设计公司、UI交互设计公司、高端网站设计公司、UI咨询、用户体验公司、软件界面设计公司
1. <!-- 弹出框 --> <el-dialog :title="titleMap[dialogStatus]" :visible.sync="dialogFormVisible"> <el-form :model="form" :rules="rules" ref="form"> <el-form-item label="商品名称" prop='goodsName' style="width:40%"> <el-input v-model="form.goodsName" auto-complete="off" placeholder="请输入商品名称" size="medium"></el-input> </el-form-item> <el-form-item label="商品图片" prop='goodsImg'> <el-upload action="uploadAction" list-type="picture-card" :on-preview="handlePictureCardPreview" :on-remove="handleRemove" :limit="1" :show-file-list="true" name="img" ref="upload" :data="form" accept="image/png,image/gif,image/jpg,image/jpeg" :headers="headers" :on-exceed="handleExceed" :auto-upload="false" :on-error="uploadError" :before-upload="handleBeforeUpload" :on-change="changeFile"> <i class="el-icon-plus"></i> </el-upload> <el-dialog :visible.sync="dialogVisible"> <img width="50px" :src="dialogImageUrl" alt=""> </el-dialog> </el-form-item> <el-form-item label="商品对应积分" prop='goodsIntegral'> <el-input v-model="form.goodsIntegral" auto-complete="off" placeholder="请输入积分" size="medium" type="number"></el-input> </el-form-item> </el-form> <div slot="footer" class="dialog-footer"> <el-button @click="cancel">取 消</el-button> <el-button type="primary" @click="uploadFileFun('form')">确 定</el-button> "注意uploadFileFun('form') 括号内记得带引号不然可能会报validate is not defined" </div> </el-dialog>
2.data部分
data() { return { //新增和编辑弹框标题 titleMap: { addStore: '新增商品', editStore: "修改商品" }, dialogStatus: "", //新增编辑弹出框 dialogFormVisible: false, dialogVisible: false, //表格数据 tableData: [], form: { id: '', goodsName: '', goodsImg: '', goodsIntegral: '', }, rules: { goodsName: [{ required: true, message: '请输入商品名称', trigger: 'blur' }], goodsIntegral: [{ required: true, message: '请输入商品积分', trigger: 'blur' }], }, headers: { Authorization: 'Bearer ' + window.localStorage.getItem("token") }, dialogImageUrl: '', //图片回显 uploadFiles: '', //formData img 文件 goodsId: '', //判断是新增还是编辑 },
// 上传文件之前的钩子 handleBeforeUpload(file) { console.log('按钮', this.titleMap) if (!(file.type === 'image/png' || file.type === 'image/gif' || file.type === 'image/jpg' || file.type === 'image/jpeg')) { this.$notify.warning({ title: '警告', message: '请上传格式为image/png, image/gif, image/jpg, image/jpeg的图片' }) } let size = file.size / 1024 / 1024 / 2 if (size > 2) { this.$notify.warning({ title: '警告', message: '图片大小必须小于2M' }) } }, //图片上传超过数量限制 handleExceed(files, fileList) { this.$message.error("上传图片不能超过1张!"); }, handleRemove(file, fileList) { this.$message.error("删除成功!"); }, // 图片上传失败时 uploadError() { this.$message.error("图片上传失败!"); }, //预览图片 handlePictureCardPreview(file) { this.dialogImageUrl = file.url; this.dialogVisible = true; }, //文件改变时 on-change方法 ,fileList[0].raw 就是传给后端的值 //filelist这个对象里面有很多属性,我们上传文件时,实际上传的是filelist列表中每一项的raw,只有raw可以正常上传, 获取到文件后,需要定义变量保存文件。所以需要获取filelist中的raw进行保存。 //这里我用的formdata上传多文件,console打印formdata,文件在控制台中显示的格式为binary。 changeFile(file, fileList) { this.uploadFiles = fileList[0].raw }, uploadFileFun(formName) { this.$refs[formName].validate((valid) => { let fd = new FormData(); fd.append('id', this.form.id); fd.append('goodsName', this.form.goodsName); fd.append('goodsIntegral', this.form.goodsIntegral); fd.append('img', this.uploadFiles); let config = { headers: { 'Content-Type': 'multipart/form-data' } } 根据goodsID判断是编辑提交还是新增提交,主要针对新增编辑使用同一个弹框 if (valid && !this.goodsId) { this.$axios.post("接口地址", fd, config).then(res => { if (res.data.success == true) { this.dialogFormVisible = false this.$message({ message: res.data.msg, type: 'success' }); //新增完清空表单内容 setTimeout(() => { this.$refs.form.resetFields(); }, 200) this.reload() } else { this.$message.error(res.data.msg); } }).catch(res => { console.log(res) }) } else { this.$axios.post("接口地址", fd, config).then(res => { if (res.data.success == true) { this.dialogFormVisible = false this.$message({ message: res.data.msg, type: 'success' }); //编辑完清空表单内容 setTimeout(() => { this.$refs.form.resetFields(); }, 200) this.reload() } else { this.$message.error(res.data.msg); } }).catch(res => { console.log(res) }) } }) }, add() { this.dialogStatus = "addStore" this.dialogFormVisible = true this.goodsId = "" //新增商品是商品ID为空 }, // 取消 cancel() { this.dialogFormVisible = false this.$refs[formName].resetFields() }, //编辑 handleEdit(index, row) { this.form = this.tableData[index] this.dialogStatus = "editStore" this.goodsId = row.id this.currentIndex = index this.dialogFormVisible = true },
分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务、UI设计公司、界面设计公司、UI设计服务公司、数据可视化设计公司、UI交互设计公司、高端网站设计公司、UI咨询、用户体验公司、软件界面设计公司
在我上一篇写的Node.js实现简单的POST请求
里面POST请求接受参数需要写两个事件,这难免有些不太方便
如果我们用formidable来接受参数的话,会变得特别方便。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <form class="upload" action="shangchuan" enctype="multipart/form-data" method="post"><!-- 上传接口是/shangchuan --> <p> 请上传一个头像 <input type="file" name="wenjian"> </p> <p> <input type="submit" value="提交"> </p> </form> </body> </html>![]()
安装依赖,执行下面这三句npm语句
npm install finalhandler --save
npm install serve-static --save
npm install formidable --save
之后会自动生成下面这个package.json文件
{
"dependencies": {
"finalhandler": "^1.1.1",
"formidable": "^1.2.1",
"serve-static": "^1.13.2"
}
}
var finalhandler = require('finalhandler') var http = require('http') var serveStatic = require('serve-static') var url = require('url') var fs = require('fs') var querystring = require('querystring') var formidable = require('formidable') var path = require('path') // Serve up public/ftp folder //配置静态资源服务器,将public文件夹静态化出来 var serve = serveStatic('public', {'index': ['index.html', 'index.htm']}) // Create server var server = http.createServer(function onRequest (req, res) { //路由 var pathname = url.parse(req.url).pathname; if(pathname == '/shangchuan'){ //创建一个表单的实例,formidable var form = new formidable.IncomingForm(); //设置上传的文件存放在哪里 form.uploadDir = './uploads'; //处理表单 form.parse(req,(err,fields,files) => { //fields 表示普通控件 //files 表示文件控件 if(!files.wenjian){ return; } if(!files.wenjian.name){ return; } var extname = path.extname(files.wenjian.name);获取文件的扩展名,便于下面修改上传后的文件名字 //改名 fs.rename(files.wenjian.path, files.wenjian.path + extname,() => { res.end('上传成功') }) // console.log(fields); }) return; } serve(req, res, finalhandler(req, res)) }) // Listen server.listen(3000); console.log('服务已经启动在3000端口');![]()
会看到这个页面
然后选择任意文件点击提交
会发现在很短的时间内你的文件会提交成功在你的uploads文件夹下。
分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务、UI设计公司、界面设计公司、UI设计服务公司、数据可视化设计公司、UI交互设计公司、高端网站设计公司、UI咨询、用户体验公司、软件界面设计公司
model : 绑定整个表单model值
rules : 整个表单校验规则
ref :获取该表单form组件
prop : 绑定每个表单的规则,写在el-form-item上
validate : 对整个表单进行校验的方法
valid : 每个必填表单项都提交为true,否则为false
//使用element-ui 页面组件 <el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm"> <el-form-item label="活动名称" prop="name"> <el-input v-model="ruleForm.name"></el-input> </el-form-item> <el-form-item label="活动区域" prop="region"> <el-select v-model="ruleForm.region" placeholder="请选择活动区域"> <el-option label="区域一" value="shanghai"></el-option> <el-option label="区域二" value="beijing"></el-option> </el-select> </el-form-item> </el-form> <el-form-item> <el-button type="primary" @click="submitForm('ruleForm')">立即创建</el-button> </el-form-item> //data中定义form表单中每项表单model值、和每个表单校验的规则 <script> export default { data() { return { ruleForm: { name: '', region: '', }, rules: { name: [ { required: true, message: '请输入活动名称', trigger: 'blur' }, { min: 3, max: 5, message: '长度在 3 到 5 个字符', trigger: 'blur' } ], region: [ { required: true, message: '请选择活动区域', trigger: 'change' } ], }; }, //定义表单提交方法 methods: { submitForm(formName) { this.$refs[formName].validate((valid) => { if (valid) { alert('submit!'); } else { console.log('error submit!!'); return false; } }); }, } }
<el-form v-if="fromHtmlList.deviceInfo.sitsb.length" :model="fasj" :rules="rules" label-position="left" label-width="125px" ref='sitsb'> <el-form-item label-width="100%" > <div slot="label" class="titleInfo">局端设备</div> </el-form-item> <el-form-item v-for="(item, i) in fromHtmlList.deviceInfo.sitsb" :key="`F_key_${i}`" :label="`${item.label}:`" :class="item.class" :label-width="item.labelWidth" :prop="`${item.rule ? 'deviceInfo.sitsb.'+item.rule : ''}`"> <el-select v-if="item.el === 'slt'" v-model="fasj.deviceInfo.sitsb[item.model]" placeholder="请选择" style="width:200px;" clearable> <el-option v-for="(op, n) in options[item.option]" :key="`vop_key_${n}`" :label="op.label" :value="op.value"> </el-option> </el-select> <el-input v-if="item.el === 'ipt'" v-model="fasj.deviceInfo.sitsb[item.model]" @focus="()=>{ item.focus && handleFocus('sitsb', item.model)}" :placeholder="`${item.placeholder ? item.placeholder : '请输入'}`" style="width:200px;"></el-input> <span v-if="item.el === 'txt'">{{fasj.base[item.model]}}</span> </el-form-item> </el-form> <div class="btn-list"> <el-button type="primary" @click="checkRequired">提 交</el-button> </div> <script> export default { data() { return { fasj: { base: {}, // 基本信息 deviceInfo: {}, }, //定义 页面表单结构 fromHtmlList: { baseInfo: [], deviceInfo: { ywzsb: [], sitsb: [] } }, //定义 表单校验规则 rules: { 'deviceInfo.sitsb.IPType': [ { required: true, message: '请输入', trigger: 'blur' } ], 'deviceInfo.sitsb.IPAddr': [ { required: true, message: '请输入', trigger: 'blur' } ], 'deviceInfo.sitsb.netmask': [ { required: true, message: '请输入', trigger: 'blur' } ], 'deviceInfo.sitsb.vlanId': [ { required: true, message: '请输入', trigger: 'blur' } ], }, options: { IPType: [ {label: 'ipv4', value: 'ipv4'}, {label: 'ipv6', value: 'ipv6'} ], rmSite: [], room: [], }, } }, created(){ const orderType = '业务开通' ;//页面初始加载用到的变量值,可通过组件传值获取 //created中初始定义页面表单结构 this.fromHtmlList = { baseInfo: orderType === '业务开通' ? [ {label: '接入方式', labelWidth: '100px', rule: '' , model: 'serviceType', option: '', el: 'txt', class: 'w2'}, {label: '标准九级地址', labelWidth: '120px', rule: '', model: 'aendAdreesName', option: '', el: 'txt', class: 'w2'}, {label: '城乡类型', labelWidth: '100px', rule: 'cityType', model: 'cityType', option: 'cityType', el: 'slt', class: 'w2'}, {label: '方案设计附件', labelWidth: '120px', rule: '', model: 'fileId', option: '', el: 'btn', class: 'w2'}, ] : orderType === '移机' ? [ {label: '接入方式', labelWidth: '100px', rule: '' , model: 'serviceType', option: '', el: 'txt', class: 'w2'}, {label: '标准九级地址', labelWidth: '120px', rule: '', model: 'aendAdreesName', option: '', el: 'txt', class: 'w2'}, {label: '城乡类型', labelWidth: '100px', rule: 'cityType', model: 'cityType', option: 'cityType', el: 'slt', class: 'w2'}, {label: '方案设计附件', labelWidth: '120px', rule: '', model: 'fileId', option: '', el: 'btn', class: 'w2'}, {label: '移机场景', labelWidth: '100px', rule: 'moveScene', model: 'moveScene', option: 'moveScene', el: 'slt', class: 'w2'}, {label: '是否需要网络调整', labelWidth: '', rule: 'netChange', model: 'netChange', option: 'netChange', el: 'slt', class: 'w2'} ] : [ {label: '接入方式', labelWidth: '100px', rule: '' , model: 'serviceType', option: '', el: 'txt', class: 'w2'}, {label: '标准九级地址', labelWidth: '120px', rule: '', model: 'aendAdreesName', option: '', el: 'txt', class: 'w2'}, {label: '城乡类型', labelWidth: '100px', rule: 'cityType', model: 'cityType', option: 'cityType', el: 'slt', class: 'w2'}, {label: '方案设计附件', labelWidth: '120px', rule: '', model: 'fileId', option: '', el: 'btn', class: 'w2'}, {label: '是否需要网络调整', labelWidth: '', rule: 'netChange', model: 'netChange', option: 'netChange', el: 'slt', class: 'w2'}, {label: '是否更换末端设备', labelWidth: '', rule: 'devChange', model: 'devChange', option: 'devChange', el: 'slt', class: 'w2'} ], deviceInfo: { ywzsb: serviceType === 'PON' ? [ // 默认PON {label: '机房', labelWidth: '90px', rule: '' , model: 'siteRoom', option: '', el: 'ipt', class: 'w2', focus: true, placeholder: '点击查询'}, {label: '设备名称', labelWidth: '90px', rule: '', model: 'deviceName', option: '', el: 'ipt', class: 'w2', focus: true, placeholder: '点击查询'}, {label: '设备端口', labelWidth: '90px', rule: '', model: 'devicePort', option: '', el: 'ipt', class: 'w2', focus: true, placeholder: '点击查询'}, {label: '延伸设备', labelWidth: '90px', rule: '', model: 'deviceExtend', option: '', el: 'ipt', class: 'w2', focus: true, placeholder: '点击查询'} ] : [ // 裸光纤、传输下沉、传输延伸(ywzsb) {label: '机房', labelWidth: '', rule: '' , model: 'siteRoom', option: '', el: 'ipt', class: 'w2', focus: true, placeholder: '点击查询'}, {label: '站点', labelWidth: '', rule: '', model: 'site', option: '', el: 'ipt', class: 'w2'}, {label: '设备名称', labelWidth: '', rule: '', model: 'deviceName', option: '', el: 'ipt', class: 'w2', focus: true, placeholder: '点击查询'}, {label: '设备端口', labelWidth: '', rule: '', model: 'devicePort', option: '', el: 'ipt', class: 'w2', focus: true, placeholder: '点击查询'}, ], sitsb: serviceType === 'PON' ? [ {label: '机房名称', labelWidth: '', rule: '' , model: 'siteRoom', option: '', el: 'ipt', class: 'w2'}, {label: '站点名称', labelWidth: '', rule: '', model: 'site', option: '', el: 'ipt', class: 'w2'}, {label: '汇聚交换机', labelWidth: '', rule: '', model: 'switch', option: '', el: 'ipt', class: 'w2'}, {label: '汇聚交换机端口', labelWidth: '', rule: '', model: 'switchPort', option: '', el: 'ipt', class: 'w2'}, {label: 'SR/BARS', labelWidth: '', rule: '' , model: 'srbars', option: '', el: 'ipt', class: 'w2'}, {label: 'SR/BARS端口', labelWidth: '', rule: '', model: 'srbarsPort', option: '', el: 'ipt', class: 'w2'}, {label: 'IP地址类型', labelWidth: '', rule: 'IPType', model: 'IPType', option: 'IPType', el: 'slt', class: 'w2'}, {label: 'IP地址', labelWidth: '', rule: 'IPAddr', model: 'IPAddr', option: '', el: 'ipt', class: 'w2'}, {label: '子网掩码', labelWidth: '', rule: 'netmask', model: 'netmask', option: '', el: 'ipt', class: 'w2'}, {label: 'VLAN ID', labelWidth: '', rule: 'vlanId', model: 'vlanId', option: '', el: 'ipt', class: 'w2'} ] : serviceType === '裸光纤' ? [ // 裸光纤 {label: '机房名称', labelWidth: '', rule: '' , model: 'siteRoom', option: '', el: 'ipt', class: 'w2', focus: true, placeholder: '点击查询'}, {label: '站点名称', labelWidth: '', rule: '', model: 'site', option: '', el: 'ipt', class: 'w2'}, {label: 'SR', labelWidth: '', rule: '', model: 'SR', option: '', el: 'ipt', class: 'w2', focus: true, placeholder: '点击查询'}, {label: 'SR端口', labelWidth: '', rule: '', model: 'SRPort', option: '', el: 'ipt', class: 'w2', focus: true, placeholder: '点击查询'}, {label: 'BARS', labelWidth: '', rule: '' , model: 'BARS', option: '', el: 'ipt', class: 'w2', focus: true, placeholder: '点击查询'}, {label: 'BARS端口', labelWidth: '', rule: '', model: 'BARSPort', option: '', el: 'ipt', class: 'w2', focus: true, placeholder: '点击查询'}, ] : [ // 传输下沉、传输延伸 ] } } }, methods:{ async checkRequired() { let checkName = ['base','sitsb'];//表单校验定义ref let text; for(let key of checkName){ if(this.$refs[key]){ this.$refs[key].validate((valid) => { if(!valid){ text = '请检查必填项'; }else { return false; } }); } } if(text){ this.$message.warning(text); return false; } let _res_ = await this.saveFasjData('', true);//页面表单要保存后才能提交 if(!!_res_ && _res_.code === 200){ this.commit(_param, _url);//保存表单再提交 }else{ this.$message.error(_res_.msg) } }, async commit(param, url) { this.loadings.body = true; let _res = await postDataRequest(url, param); this.loadings.body = false; if (_res && _res.code === 200) { this.$message.success("提交成功"); this.$router.go(-1); } } } } </script>
分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务、UI设计公司、界面设计公司、UI设计服务公司、数据可视化设计公司、UI交互设计公司、高端网站设计公司、UI咨询、用户体验公司、软件界面设计公司
Vite 是 vue 的作者尤雨溪在开发 vue3.0 的时候开发的一个 web 开发构建工具。由于其原生 ES 模块导入方式,可以实现闪电般的冷服务器启动。
Vite 优势:
Vite 劣势:
其他区别:
1. 打包原理的区别


2. 项目入口文件的区别
项目根目录的 index.html 是 Vite 项目的入口文件,而 webpack 的入口文件是 webpack 配置 entry 中指定的 js 文件。
Esbuild 是一款基于 Go 语言开发的 javascript 打包工具,最大的一个特征就是快。
通过官网提供的一张图,我们可以清晰的看到 Esbuild 的表现是多么优秀:
Esbuild 之所以能这么快,主要原因有两个:
Go 语言开发,可以多线程打包,代码直接编译成机器码;
Webpack 一直被人诟病构建速度慢,主要原因是在打包构建过程中,存在大量的 resolve、load、transform、parse 操作(详见 为什么有人说 vite 快,有人却说 vite 慢?- 快速的冷启动 ),而这些操作通常是通过 javascript 代码来执行的。要知道,javascript 并不是什么高效的语言,在执行过程中要先编译后执行,还是单线程并且不能利用多核 cpu 优势,和 Go 语言相比,效率很低。
可充分利用多核 cpu 优势;
关键 API - transfrom & build
Esbuild 并不复杂,它对外提供了两个 API:transform 和 build,使用起来非常简单。
transfrom,转换的意思,将 ts、jsx、tsx 等格式的内容转化为 js。 transfrom 只负责文件内容转换,并不会生成一个新的文件。
build,构建的意思,根据指定的单个或者多个入口,分析依赖,并使用 loader 将不同格式的内容转化为 js 内容,生成一个或多个 bundle 文件。
我们来看看Vite 是怎么利用 Esbuild 来做预构建和内容转换的。
预构建
为什么要做预构建?原因有两点:
将非 ESM 规范的代码转换为符合 ESM 规范的代码;
将第三方依赖内部的多个文件合并为一个,减少 http 请求数量;
middlewares 中内容转换
Vite 中源文件的转换是在 dev server 启动以后通过 middlewares 实现的。
当浏览器发起请求以后,dev sever 会通过相应的 middlewares 对请求做处理,然后将处理以后的内容返回给浏览器。
middlewares 对源文件的处理,分为 resolve、load、transform、parser 四个过程:
resolve - 解析 url,找到源文件的绝对路径;
load - 加载源文件。如果是第三方依赖,直接将预构建内容返回给浏览器;如果是业务代码,继续 transform、parser。
transfrom - 对源文件内容做转换,即 ts -> js, less -> css 等。转换完成的内容可以直接返回给浏览器了。
parser - 对转换以后的内容做分析,找到依赖模块,对依赖模块做预转换 - pre transform 操作,即重复 1 - 4。
pre transform 是 Vite 做的一个优化点。预转换的内容会先做缓存,等浏览器发起请求以后,如果已经完成转换,直接将缓存的内容返回给浏览器。
Vite 在处理步骤 3 时,是通过 esbuild.transform 实现的,对比 Webpack 使用各个 loader 处理源文件,那是非常简单、快捷的。
经验法则:对于应用使用 webpack,对于类库使用 Rollup。
如果你需要代码拆分(Code Splitting),或者你有很多静态资源需要处理,再或者你构建的项目需要引入很多CommonJS模块的依赖,那么 webpack 是个很不错的选择。
如果您的代码库是基于 ES2015 模块的,而且希望你写的代码能够被其他人直接使用,你需要的打包工具可能是 Rollup 。
分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务、UI设计公司、界面设计公司、UI设计服务公司、数据可视化设计公司、UI交互设计公司、高端网站设计公司、UI咨询、用户体验公司、软件界面设计公司
-
<div class="add">
-
<p>商品名称: <input type="text" class="productName"></p>
-
<p>商品价格: <input type="number" class="price" ></p>
-
<!-- multiple: 允许同时上传多张图片 -->
-
<!-- <p>商品图片: <input type="file" class="file" multiple="multiple"></p> -->
-
<p>商品图片: <input type="file" class="file"></p>
-
<p><button class="add-btn">添加商品</button></p>
-
</div>
-
<script src="js/axios.js"></script>
-
<script src="js/util.js"></script>
-
<script src="js/upload.js"></script>
-
// 新建表单数据对象,用来存储上传的文件及上传的其它数据
-
let param = new FormData()
-
-
$(".file").onchange = function(){
-
//获取图片信息
-
let file = this.files[0]
-
//"file"为前后端约定vb的属性名
-
param.append("file",file)
-
}
-
$(".add-btn").onclick = function(){
-
let productName = $(".productName").value;
-
let price = $(".price").value;
-
param.append("productName",productName)
-
param.append("price",price)
-
-
axios.post("/product",param,{
-
headers: {
-
// 默认提交的类型
-
// "content-type": "application/json"
-
// 复杂的表单数据(只要上传文件,就必须是下面的类型)
-
"content-type": "multipart/form-data"
-
}
-
})
-
.then((res)=>{
-
console.log(res.data);
-
})
-
}
下载
npm i multer -S
引入
-
const multer = require("multer")
-
const path = require("path")
配置
注意: 该文件在/router文件夹中,而uploads存放上传图片文件夹在根目录
-
var storage = multer.diskStorage({
-
// 配置文件上传后存储的路径
-
destination: function (req, file, cb) {
-
// NodeJS的两个全局变量
-
// console.log(__dirname); //获取当前文件在服务器上的完整目录
-
// console.log(__filename); //获取当前文件在服务器上的完整路径
-
cb(null, path.join(__dirname,'../uploads'))
-
},
-
// 配置文件上传后存储的路径和文件名
-
filename: function (req, file, cb) {
-
console.log('file',file);
-
cb(null, Date.now() + path.extname(file.originalname))
-
}
-
})
-
var upload = multer({ storage: storage })
在路由中使用
-
//添加商品
-
router.post("/product",upload.single("file1"),(req,res)=>{
-
//接收普通文本参数
-
let {productName,price} = req.body;
-
、接收上传文件数据 -->
-
let imgUrl = req.file.filename;
-
let sql = "insert into product (productName,price,imgUrl) values (?,?,?)"
-
conn.query(sql,[productName, price , imgUrl],(err,result)=>{
-
if (err){
-
console.log('增加失败');
-
return;
-
}
-
let data;
-
if (result.affectedRows === 1){
-
data = {
-
code: 0,
-
msg: '添加成功'
-
}
-
}else{
-
data = {
-
code: 1,
-
msg: '添加失败'
-
}
-
}
-
res.send(data)
-
})
-
})
如果抽离路由模块中的处理函数upload.single("file1")写在Router模块
实现写在抽取的模块
如果req.body为空,可以用nodejs后台文件上传模块connect-multiparty
使用方法如下:
1. 安装模块
npm install connect-multiparty --save
2. 引入模块
var multipart = require('connect-multiparty');
var multipartMiddleware = multipart();
3. 使用模块
const express = require('express')
const router = express.Router()
router.post('/formdata',multipartMiddleware, function (req,res) {
console.log(req.query)
//分别返回body,文件属性,以及文件存放地址
});
————————————————
原文链接:https://blog.csdn.net/zjwengyidong/article/details/51407903
分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务、UI设计公司、界面设计公司、UI设计服务公司、数据可视化设计公司、UI交互设计公司、高端网站设计公司、UI咨询、用户体验公司、软件界面设计公司
蓝蓝设计的小编 http://www.lanlanwork.com