首页

2023年前端开发趋势未来可期

前端达人

目录

一、企业内前端开发比重

        1、目前学校教课的种类多样

        2、目前服务端语言多样

        3、企业中前端开发占比

二、目前业内更受欢迎的开发语言

        1、过去一直到今年的开发语言排名

        2、那么未来呢

三、近期CSDN问答的前端活跃度

        1、近期CSDN问答模块活跃度

        2、活跃度能说明什么

四、前端开发都做什么?

        1、这个问题需要想吗?

        2、日常工作是什么?

        3、还做什么?

        4、想想,还能做什么?

        5、有点理想好不好

五、给初学者的建议

        1、坚定信心

        2、是否要去培训机构

        3、学习之余的巩固

        4、赢在实战

         5、知识点的举一反三


一、企业内前端开发比重

        1、目前学校教课的种类多样

        搞明白前端开发人员在企业中的占比,你才可以在学校或者即将毕业的时候选择出自己将要深入学习的开发语言。很多学校既要教C语言,又教单片机,既教java,也教前端开发知识,但老师的课是有限的,给留了作业,也许都不检查,下一课老师就要继续往下讲,因为这是他的工作,老师们也有生活,不可能围着某些人转,学不会就不往下开课了。

        而搞懂前端开发在企业中的占比呢,能够更好的让你觉得如果自己比较平凡,得到什么等级可以卷得过别人,可以在这么多职位中占有一席之地。

        2、目前服务端语言多样

        很可喜的是,目前传统行业已经信息化改造完成,不管他们是内部系统,或者外部联合系统,都需要前端开发;我们每天看见大街上跑的汽车企业,某些电子企业,手机厂商,都需要前端开发的职位;更别提电商,直播这些我们生活所不可缺少的行业。但你还需要知道的是,如果你想学的一门服务端语言,java phython .net 或者其他,很可能这家公司就不会用,无形中给自己减少了很多工作机会。

        3、企业中前端开发占比

        22461dbde9ea4dc498d3d9891179c32b.png

         0f9b7c29c5c843f1a21abaed4cb8a62d.png

 6d52958d5b544d1b96016c2ff16d461c.png

         以上的图,是从过去几年一直到今年(2022)年的各大公司的占比,毕竟是大厂嘛,对用户体验,前端接触到浏览器,最接近用户的要求肯定会高一些。

        但是通过对多家中小公司的逐步了解发现,出去UI , 项目,产品,DBA, 运维等职位外,服务端开发与前端开发的比例几乎是1:1 ,甚至有的外包性质的公司,他们一旦产品成型后,新的客户换皮肤,更换界面的需求会更多,所以前端开发会需求更多一些。

        

二、目前业内更受欢迎的开发语言

        此前有人戏称,是开发语言受欢迎,并非你受欢迎。但不得不说,某个开发语言受欢迎程度如果更加靠前,说明市场需求更大,更受欢迎,而将来准备从事某一种开发语言,也是非常关键的信息来源。

        1、过去一直到今年的开发语言排名

        e783b4646959444288fc376d85c26ade.png

           5d6915e57ffa4373b9cb338d060d1189.png

                 b43001039ca947cebc1490386fee2d6d.png

                 21f4406245374b54af5292de10b73370.png

 21a7ead82dc844afac42a26d86b44875.png

        通过以上往年到今年的开发语言受欢迎程度发现,javascript这门前端必备的开发语言名列前茅,甚至在众多服务端开发语言中也不甘示弱,当然这之中并没有表明HTML CSS是一门开发语言,如果是的话,HTML CSS 也必将榜上有名,因为各行各业都不要网页对外公式自己的产品,但服务端开发语言五花八门,而前端必备javascript。

        2、那么未来呢

        从web1.0时代,页面简单的只读时代,到web2.0时代,不断的交互,前端开发这个职位也在不断的进步。那么在未来的web3.0时代,很多人疑惑,可能PC的网页用处会越来越少,甚至不客气的说H5的页面也会少很多,据推测APP也会减少,未来将会有更多的数据整合产品出现。那么未来前端还会大有可为吗?

        答案是肯定的,伟大的《红宝书》开头便说:javascript能做所有的事情,如果他能。而且nodejs的流行,也使前端可以更多的渗透到服务端开发,flutter的最新发布,WPA的使用,也使APP得到了更大的挑战,CSS3的不断进步,前端游戏引擎的盛行,也使前端有了更大的发展前景与选择,那么即便未来的元宇宙世界,相信前端javascript也一定能够勇往直前

三、近期CSDN问答的前端活跃度

        1、近期CSDN问答模块活跃度

9f27329550154ebbb6b12739237dad6a.png

be63ffd41bef4ec782c645b847b5fdc4.png

         如果这只是当下技术领域的一个缩影,可见比较活跃的的开发语言有java phython c mysql 然后才是javascript。从开发开发技术职位区分还是服务端和前端,但前端活跃度却比较靠后,不管是提问,回答,数量等维度上

        2、活跃度能说明什么

        说明什么问题呢?从事前端开发人数少吗?前端开发在学习,工作中没有问题吗?前端开发比较懒惰,不愿意上社区来参与活动吗?

        我们知道nodejs可以做服务端开发,但是有多少企业敢于让从开始就搭上node serve的架子,不断让前端同学去尝试,不断在node领域发光发热,为整个行业添砖加瓦呢,很少吧。而几乎大部分公司,还是比较守旧的,从最开始的jSP时代,甚至不需要前端,服务端写完服务端代码,然后开始写JSP。JSP里再套java代码,顺带着添加一些javascript事件,样式怎么办,那个时候extjs jquery还非常盛行,easyui jqueryui 等,可以让服务端开发人员快速生产页面。

        但随着提升用户体验的欲望越来越强烈,《国富论》开篇也讲分工带来的好处,前端才逐渐有了一席之地,甚至在一些大公司,前端的话语权可以超越服务端,他们通过技术驱动业务向前。

        按照比例学可知,一旦某些事物达到一个数量后,某些细节世界也可以大体展现整体的宏观判断。那么我的理解是,在众多开发语言中,尽管javascript那么受欢迎,目前企业中前端占比还算不错,但总的来说,跟其他服务端开发语言总和来比,前端人员还是少。如果服务端语言像前端一样仅有javascript的话,我相信csdn问答模块这个业界缩影将不会是这种状态,甚至会大有不同。

四、前端开发都做什么?

        1、这个问题需要想吗?

         其实很多老师,很多培训机构的老师教前端,大家各有各自的工作,各有各自的生活, 他知道来了一批学生,这是自己分内的工作,其实很多学生也只是停留在前端开发做网页的意识上,未来我想找到一份共走,可以养活自己。这无可厚非

        2、日常工作是什么?

        其实日产工作还真就是做网页,做了C端做B端,做了PC做H5,嵌套到webview里,嵌套的APP的壳子里,这些都是工作。

        小程序,各种各样的小程序;各种手机屏幕尺寸的适配;各种APP内部的嵌套;

        做完了前端,开发点node层的工作吧,卷一卷,棒服务端同学减轻点工作压力;

        3、还做什么?

        再来点代码优化吧,如果将自己的代码调的代码量更少,如何不写注释也可以清晰明了,如何不得不写注释,可以写的更清楚;

        来一点性能优化吧,现在出去面试,没做过性能优化都不好意思说自己做过工作。没办法,整体的需求缠身,但你却很少从中吸取知识,日复一日,到找工作那天发现,自己做的工作,其实都是劳动力。如何驱动自己,再寻求解决方案,再将性能指标不断提升。

        4、想想,还能做什么?

        卷一卷,读书破万卷。将自己的点子,自己的做法不断形成方法论,对内输出,乃至对外输出,提升影响力。

        5、有点理想好不好

          还要啥理想,向公共组件团队渗透,向技术栈所在团队渗透?

       

        小插曲:这里加一个小插曲,promise解决了什么问题?这道题是不是必考题,千篇一律的答案是什么?解决了回调地狱?异步的工作我们当同步的来执行?

        这算不算进步?这算不算创新?那么我就问问你,有回调地狱你的项目跑步起来了?用同步的写法来搞异步的事情降本增效了?

        那么我就问问你,是你把之前的写法用上现在的promise节省的时间多,还是你每天摸鱼的时间多。说白了异步是一个需要花费时间的事情,因为有了异步,有了时间差,才使我们的工作出现了更多的可能性,不确定性。你更应该解决的是不是这个问题。

        个人观点啊,没说promise不好,挺好的。

五、给初学者的建议

        1、坚定信心

        不管是在校或者迷茫的即将离校,一旦决定要学,不管是学哪种开发语言,都要坚定信心,切记不可三天打鱼,两天晒网;

        2、是否要去培训机构

        这要看个人家庭的生活水平,一个家庭攻读出一个大学生实属不易,毕业后念培训班需要一定的资本支持。但对于很多人来说,没有学习方向,念培训班也是个选择,至少可以入个门;但大部分的培训课程对于目前的就业形势掌握不足,就像杨过刚去钟南山一样,练不够基本功,词汇一大堆,实战没多少,最后说啥名词都是666,一干活就挠头;

        其实我根据自己的经验,也在筹备规划一套更卷,更适合入门到守门再到卸门的课程,我的目标就是更实用,更卷,更有助于大多数想学习的同学们,你需要的只是一句:我想学习,我要学习,我能学习,而不是马内。

        3、学习之余的巩固

        现在网络上文章多的是,虽然很多不够系统,但正好够大家巩固当日知识点所用。学一定要用,用后一定要巩固,巩固后一定要举一反三形成自己的知识点,方法论,记录个博客啦,笔记啦,分享到身边的人,这样足可巩固无忧

        4、赢在实战

        知识点掌握的好不叫好,可以把知识点贯穿起来,做出一个市面上的东西,这算超越自我,切记不可自满,学完知识点就说自己精通,那只会在面试或者在工作的时候让自己更加烦恼,掉头发,熬夜。

         5、知识点的举一反三

        做为初级开发,最重要的就是对于解决问题,有自己的一套手段,这样至少可以保证快速的完成需求。但如果想继续往上走,必须得有一些别人所没有的东西。这里说到举一反三,记得当时学习的时候,学完js基础需要写一个99乘法表,当时本来上课就少,硬生生把js的嵌套循环99乘法表写出来。晚上睡觉的时候想,如果纯用HTML CSS 是不是也能写出来,就这样,HTML的倒是好写,但CSS的又憋了很久,总算是写出来了。你就说,这样下去,谁能有我卷。现在我总结出了怎么利用纯HTML CSS JS 写出3版99乘法表,并且总结出了自己的文章,希望可以让初学者能够更快的入门。




蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请加蓝小助,微信号:ben_lanlan,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系01063334945。


分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。


蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务UI设计公司、界面设计公司、UI设计服务公司、数据可视化设计公司、UI交互设计公司、高端网站设计公司、UI咨询、用户体验公司、软件界面设计公司

是什么让学习 Web 开发在未来几年变得有价值?

前端达人

什么是网页开发?

Web 开发是指在互联网上创建网站或 Web 应用程序。它涉及一系列任务,从开发网站的整体结构和设计到编写使网站栩栩如生的代码。Web 开发可能是一个复杂的过程,它通常涉及使用各种不同的技术,包括 HTML、CSS 和 JavaScript,以及服务器端语言,如 PHP、Ruby、Nodejs 和 Python。Web 开发人员可能在前端工作网站的一部分,这是用户与之交互的部分,或者在后端,这是处理网站幕后功能的部分。Web 开发是一个快速发展的领域,Web 开发人员需要跟上最新的技术和最佳实践,才能创建有效且引人入胜的网站和 Web 应用程序。

在这里插入图片描述

Web 开发领域的未来是什么样的?

可以肯定地说,Web 开发将继续是一个重要且充满活力的领域。随着 Internet 的不断发展和演变,对 Web 开发人员的需求也可能会增加。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> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在此示例中,<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; } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

在此示例中,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 框架。它以其约定优于配置方法和强调开发人员生产力而闻名。

10 种最流行的 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 开发的未来看起来一片光明,许多激动人心的发展和趋势即将出现。一些可能影响 Web 开发未来的最新 Web 开发趋势包括:

  • 人工智能和机器学习的兴起:人工智能和机器学习在网络开发中变得越来越重要,出现了许多新的工具和框架来帮助开发人员构建人工智能驱动的应用程序。

  • 物联网的发展:物联网 (IoT) 是一个由可以收集和共享数据的连接设备组成的网络,预计在未来几年将显着增长。这将为网络开发人员创造新的机会来构建可以连接这些设备并与之交互的应用程序。

  • 移动设备的重要性日益增加:随着越来越多的人使用智能手机和其他移动设备访问网络,网络开发人员创建适合移动设备的应用程序和网站将变得越来越重要。

  • 渐进式 Web 应用程序的兴起:渐进式 Web 应用程序 (PWA) 是外观和感觉都像本机移动应用程序的 Web 应用程序,并且有望在未来变得更加流行。这将为 Web 开发人员创造新的机会来构建可跨不同设备和平台提供无缝用户体验的 PWA。

  • 云计算的发展:云计算在网络开发中变得越来越重要,许多公司将他们的应用程序和数据转移到云中。这将为 Web 开发人员创造新的机会来构建云原生应用程序并将它们与现有的云服务集成。

结论:

Web 开发仍然值得学习,因为它是构建和维护作为现代 Internet 支柱的网站和 Web 应用程序的基本技能。随着世界变得越来越紧密,对 Web 开发人员的需求不断增长,对于那些拥有构建和维护未来 Web 应用程序的技能和专业知识的人来说,有许多激动人心的机会。

Web 开发也是一个回报丰厚且具有挑战性的领域,它允许开发人员利用他们的创造力和解决问题的技能来构建供全球数百万人使用的应用程序。有了合适的工具和资源,任何人都可以学习 Web 开发并开始构建自己的 Web 应用程序,从而打开一个充满可能性和机遇的世界。


蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请加蓝小助,微信号:ben_lanlan,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系01063334945。


分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。


蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务UI设计公司、界面设计公司、UI设计服务公司、数据可视化设计公司、UI交互设计公司、高端网站设计公司、UI咨询、用户体验公司、软件界面设计公司

Vue.js 状态管理:Pinia 与 Vuex

前端达人

Vuex 和 Pinia 是用于管理 Vue.js 应用程序状态的标准 Vue.js 库。让我们比较一下他们的代码、语言、功能和社区支持。

如果没有合适的库,开发人员管理应用程序的状态可能会很困难。Vuex 和 Pinia 是标准的 Vue.js 库,用于处理应用程序中的条件。这两个库都非常适合状态管理,但是由于它们出色的特性和功能,选择哪个库用于你的项目需要时间并且令人沮丧。好吧,我们将在本文中看看为什么一个是最好的。

在本文中,我们将通过实际代码示例查看代码比较、它们的变体、功能,以及推荐使用哪一个来管理你的状态应用程序,以便更好地理解。我们还将考虑每个产品的语言、功能和社区支持。

Pinia 和 Vuex 简介

我将简要总结 Vuex 和 Pinia。如果你想要更详尽的解释,我建议阅读Vuex 文档和Pinia 文档。

什么是Pinia?

Pinia是一个新的状态管理库,可帮助你在 Vue.js 应用程序中跨组件管理和存储响应数据和状态。Pinia 由 Vue 核心团队成员之一 Eduardo San Martin Morote 创建。

Pinia 使用新的反应系统来构建一个直观且完全类型化的状态管理系统。

库中引入的新特性是促成 Pinia 推荐的因素之一。总体而言,Pinia 显得轻巧、简单且易于掌握。它拥有可以使 Vue 3 和 Vue 2 中的编程变得通用的一切。因此,这是试用 Pinia 的理想机会。

什么是 Vuex?

Vuex是一种状态管理模式和库,构建为集中式存储,可帮助你维护 Vue 应用程序中存在的所有组件的状态。Vuex 遵循确保你的状态突变为预测标准的规则。

使 Vuex 更强大的一个因素是组件从 Vuex store 中获取它们的状态,并且可以快速有效地响应 store 状态的变化。

Vuex虽然是维护你store的状态管理库,但建议你熟悉或搭建过大型SPA。如果你没有经验,Vuex 可能会冗长且令人生畏。

如果你的应用程序很广泛,你需要管理复杂的数据流,并且你有嵌套的组件,你可以使用 Vuex。查看官方文档以获取有关何时使用 Vuex 的更多信息。

Pinia 的特点

Pinia 和 Vuex 之间的区别之一是 Pinia 是“模块化设计”,换句话说,它被构建为拥有多个商店,而 Vuex 只有一个商店。在这些商店中,您可以拥有子模块。除此之外,Pinia 允许将这些模块中的每一个从他们的商店直接导入到需要的组件中。

模块化设计

如果您是一名 Vue 开发人员并且曾使用 Vuex 管理应用程序的状态,您会注意到 Vuex 只有一个商店。在该商店中,您可以在其中包含多个模块。使用 Pinia,您可以将这些模块中的每一个都存储在一个地方,并在需要时将它们直接导入到组件中。

此方法允许捆绑器自动对它们进行代码拆分,并提供更好的 TypeScript 推理。

完整的开发工具支持

Pinia 提供开发工具支持,以帮助您使用该库构建和轻松调试。当我们安装 Pinia 时,它会自动挂接到我们的 Vue.js 开发工具,并让我们跟踪对我们的商店所做的更改,这让我们在 Vue.js 版本(Vue 2 和 Vue3)中获得流畅的开发人员体验。

Pinia 很直观

Pinia 提供了一个简单的 API,使您的商店的编写变得简单且井井有条,就像创建组件一样。这意味着与 Vuex 解决方案相比,需要掌握的样板文件和概念更少。

Pinia 是可扩展的

Pinia 还提供了一个完整的插件系统,具有交易和本地存储同步等功能,适用于 Pinia 默认行为不足的情况。

TypeScript 支持

Pinia 提供比 Vuex 更好的 TypeScript 支持,具有 Javascript 自动完成功能,这使得开发过程变得简单。

Pinia 轻量的

Pinia 的重量只有 1 KB,因此很容易融入您的项目。这可能会提高您的应用程序性能。

Vuex的特点

模块

当您的应用程序扩展时,遍历变得很困难。但是,使用 Vuex 模块,您可以根据领域功能将您的商店拆分为多个文件,并从该特定命名空间中的模块访问状态循环。

开发工具支持

Vue devtools 中的 Vuex 选项卡允许我们查看状态并跟踪我们的变化。这使我们能够快速评估我们的程序如何执行和调试错误。

热重载

Vuex支持热重载功能,它使用 webpack 的热模块替换 API,可以在您开发时快速重载您的 mutations、modules、action 和 getters。

TypeScript 支持

如果你想编写一个 TypeScript 存储定义,Vuex 可以提供它的类型并且更容易实现。它有一个默认的 TypeScript 配置,不需要额外的设置。

Pinia和Vuex的代码对比

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) } } }) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

如果你看上面的代码,你可以看到 Vuex 存储中的三个动作:状态、 动作和突变。状态返回当前的todoListItems,动作提交一个突变来创建一个新项目,最后,突变创建新项目并将其添加到列表中。当你构建一个更大的应用程序时,你可能会意识到动作和突变相对相似,导致冗余代码,因为每个状态变化都需要一个样板。

Pinia

使用 Pinia 简单 API,您可以消除突变和冗余代码。让我们查看一个代码示例,了解当您使用 Pinia 实现之前的代码时的样子:

import { defineStore } from 'pinia' Export const useListStore = defineStore('list', { state() => ({ return { todoListItems: [] } }), actions: { addNewList() { this.todoListItems.push(item) } }}) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

上面的示例是 Pinia API 在管理应用程序状态时如何工作的简单代码。使用 Pinia,我们删除了突变并将其直接更新到我们的动作中。

注意:在上面的代码示例中,当我们将项目直接提交给我们的操作时,我们不需要跟踪我们的项目。

Pinia 和 Vuex 的优缺点

Pinia 和 Vuex 是控制应用程序状态的优秀工具,但其中一个必须具有另一个所没有的某些功能。让我们来看看它们是什么。

Pinia 的优点

  • Pinia 允许你在不重新加载页面的情况下修改你的商店。
  • 它在 JavaScript 中提供 TypeScript 支持和良好的自动完成功能。
  • Pinia 提供 devtool 支持,这有助于增强开发人员使用该工具的体验。
  • Pinia 只有状态、吸气剂和动作。不需要突变。
  • 使用 Pinia,你可以将状态存储在一个地方,并在请求时将其传递给它们的组件。
  • 它是一个重量为 1 KB 的轻量级库。
  • 它提供服务器端渲染支持和自动类型模块,无需额外工作。
  • Pinia 兼容 Vue 2 和 Vue 3。

Pinia 的缺点

  • 与 Vuex 相比,它没有庞大的社区支持和解决方案。
  • Pinia 不支持调试功能,如时间旅行和编辑。

Vuex 的优点

  • Vuex 有 mutations、getters 和 actions。
  • 与 Pinia 相比,Vuex 的社区支持很大。
  • Vuex 支持调试功能,如时间旅行和编辑。

Vuex 的缺点

  • 它对 TypeScript 不友好。
  • 你只能将其用于大型 SPA。

我应该使用哪个:Pinia 还是 Vuex?

好吧,这就是它变得更具挑战性的地方,因为仍然有一些项目需要使用 Vuex 来处理状态应用程序,即使 Pinia 是新推荐的状态管理库。它有几个 Vuex 没有的有价值的功能。

Vuex 仍然是构建大型 SPA 的理想解决方案,因为对于构建中小型应用程序的人来说,它相当冗长。

Pinia 也一样。尽管如此,如果你需要所有列出的功能,例如 devtool 支持、TypeScript 支持和状态应用程序的轻松管理,那么 Pinia 是最好的解决方案——它为你提供流畅的开发体验。

如果你正在构建一个不太复杂的应用程序,无论是中等到广泛的应用程序,你都可以使用 Pinia,因为它的重量约为 1 KB。

结论

由于功能多样,在管理应用程序状态时,在 Vuex 和 Pinia 之间进行选择可能会造成混淆。不过,这两个框架都非常适合管理状态应用程序。本文简要比较了它们的特性、功能和对代码的影响。读完这篇文章后,也许你将能够找到适合你的库。




蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请加蓝小助,微信号:ben_lanlan,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系01063334945。


分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。


蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务UI设计公司、界面设计公司、UI设计服务公司、数据可视化设计公司、UI交互设计公司、高端网站设计公司、UI咨询、用户体验公司、软件界面设计公司

MAC 解压rar

前端达人

本文转载至 : Mac解压压缩 rar文件

一、下载压缩包到本地(Downloads文件夹下)

RAR 5.60 for Mac OS Xwww.rarlab.com

二、双击打开下载好的rarosx-5.6.0.tar.gz文件,会自动解压出一个rar文件夹。由于默认下载到了Downloads目录,所以在终端中执行

cd ~/Downloads/rar 
  • 1

三、需要执行两个命令。一个是安装rar压缩命令,一个是安装unrar解压命令

sudo install -c -o $USER rar /usr/local/bin/
sudo install -c -o $USER unrar /usr/local/bin 
  • 1
  • 2

四、走完上面三步,实际上我们mac已经能够正常解压和压缩rar文件了。下面只介绍解压命令

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 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

2,压缩命令

// 将file文件压缩到text.rar
rar a text.rar file




蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请加蓝小助,微信号:ben_lanlan,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系01063334945。


分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。


蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务UI设计公司、界面设计公司、UI设计服务公司、数据可视化设计公司、UI交互设计公司、高端网站设计公司、UI咨询、用户体验公司、软件界面设计公司

前端基于DOM或者Canvas实现页面水印

前端达人

前言

我们会看到很多页面带有水印,但是怎么实现呢?当然可以有多种实现方式,本文主要讲解在vue项目中基于DOM或者Cavans实现水印效果,当然还有其他的实现方式,比如在原图片的基础上加上水印生成新的图片,但是这需要后端处理。因为要在vue项目中使用,所以我使用自定义指令可以直接对挂载的dom实现水印效果。

本文实现水印的项目环境为:vue + vite + ts

一、vue自定义指令directive讲解

前面专门有一篇讲解vue2.x与vue3.x中自定义指令详解

二、基于DOM的实现方式

1. 思路整理

  • 获取宽高
    (1)获取绑定元素的实际宽度clientWidth
    (2)获取绑定元素实际高度clientHeight
    (3)获取绑定元素的父元素parentElement
  • 创建盒子
    (1)创建一个包裹水印图片的盒子
    (2)创建一个水印图片的盒子
  • 设置盒子样式
    (1)包裹水印盒子宽高为绑定元素的宽高,即clientWidth、clientHeight
    (2)水印盒子设置背景图、旋转度、宽高、点击穿透
  • 设置创建的元素的位置
    (1)水印盒子放到包裹水印图片的盒子里 (包裹水印图片的盒子包裹水印)
    (2)包裹水印图片的盒子放到被绑定元素之前
    (3)被绑定元素放到裹水印图片的盒子里(不然被绑定元素与包裹水印图片的盒子层级同级)

2.新建index.vue

将水印的指令放到标签上,设置标签的宽高。水印可以放大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> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

3. 新建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 } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

4. 在directives文件下创建 index.ts文件

import type { App } from 'vue' import watermark from './waterMark' export default function installDirective(app: App) { app.directive(watermark.name, watermark.directives); } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

5. 在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'); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

6. 缺点

  • 直接删除水印元素时,页面中的水印直接就被删除了,当然我们可以用MutationObserver对水印元素进行监听,删除时,我们再立即生成一个水印元素就可以了,具体方面在下面讲解。
  • 如果原始元素本身存在 css 定位等规则,会导致整体布局效果出现影响,因为上面实现排除了原始元素没有定位,所以实现方式不是很严谨,本文具体实现实现如下:
    • 创建一个水印的容器设置为 position:relative
    • 将原有的节点放入到这个容器中
    • 同时创建一个带有水印的 dom 设置为position:absolute ,实现这个水印元素覆盖到原始元素的上层,以实现水印的效果。

三、基于Canvas和MutationObserver的实现方式

1. 思路整理

  • 配置水印的具体样式(大小,旋转角度,文字填充)
  • 设置水印(位置)
  • 监听dom变化(防止水印删除后页面不再展示水印)

2. 生成水印

通过将图片绘制在cavans中,然后通过cavanstoDataURL方法,将图片转为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"); }; 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

3. 使用MutationObserver监听水印

使用MutationObserver监听dom变化,MutationObserver详细用法之前已经讲过了,详细可见作为前端你还不懂MutationObserver?那Out了
具体监听逻辑如下:

  • 1.直接删除dom
    (1)先获取设置水印的dom
    (2)监听到被删除元素的dom
    (3)如果他两相等的话就停止观察,初始化(设置水印+启动监控)
  • 2.删除style中的属性
    (1)判断删除的是否是标签的属性 (type === “attributes”)
    (2)判断删除的标签属性是否是在设置水印的标签上
    (3)判断修改过的style和之前的style对比,不等的话,重新赋值
// 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); }, }; 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87

四、成果展示

删除水印标签依然还在,除非删除水印注册的标签才能删除水印,但是这样做毫无意义,因为这样做内容也会全部删除掉。

在这里插入图片描述

附:文中用到的js基础知识

toDataURL用法

toDataURL(type, encoderOptions),接收两个参数:

  • type:图片类型,比如image/png、image/jpeg、image/webp等等,默认为image/png格式
  • encoderOptions:图片质量的取值范围(0-1),默认值为0.92,当超出界限按默认值0.92






蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请加蓝小助,微信号:ben_lanlan,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系01063334945。


分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。


蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务UI设计公司、界面设计公司、UI设计服务公司、数据可视化设计公司、UI交互设计公司、高端网站设计公司、UI咨询、用户体验公司、软件界面设计公司

vue el-upload 和form表单一起提交

前端达人

图片上传和表单同时一起提交

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> 
                    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

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: '', //判断是新增还是编辑 }
                    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  1. methods部分 手动上传图片 **var fd = new FormData()**添加
// 上传文件之前的钩子 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 }, 
                    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
文章


蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请加蓝小助,微信号:ben_lanlan,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系01063334945。


分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。


蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务UI设计公司、界面设计公司、UI设计服务公司、数据可视化设计公司、UI交互设计公司、高端网站设计公司、UI咨询、用户体验公司、软件界面设计公司


使用Node.js的formidable模块实现文件上传

前端达人

在我上一篇写的Node.js实现简单的POST请求
里面POST请求接受参数需要写两个事件,这难免有些不太方便
在这里插入图片描述

如果我们用formidable来接受参数的话,会变得特别方便。

下面我们来写一个Demo,来利用formidable来实现图片上传

1.下面来看一眼 目录结构

在这里插入图片描述

2.先来写一个简单的前端上传页面

index.html
<!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> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

2.package.json 文件

安装依赖,执行下面这三句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"
  }
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

3.post.js

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端口'); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

4.最后找到post文件的目录,然后开始node post.js

会看到这个页面

在这里插入图片描述

然后选择任意文件点击提交
会发现在很短的时间内你的文件会提交成功在你的uploads文件夹下。




蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请加蓝小助,微信号:ben_lanlan,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系01063334945。


分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。


蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务UI设计公司、界面设计公司、UI设计服务公司、数据可视化设计公司、UI交互设计公司、高端网站设计公司、UI咨询、用户体验公司、软件界面设计公司

关于vue.js element ui 表单验证 使用this.$refs[formName].validate()

前端达人

实现form表单提交验证功能

model : 绑定整个表单model
rules : 整个表单校验规则
ref :获取该表单form组件
prop : 绑定每个表单的规则,写在el-form-item
validate : 对整个表单进行校验的方法
valid : 每个必填表单项都提交为true,否则为false

1、简易版 表单提交

//使用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; } }); }, } } 
        
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

2、复杂版 表单提交

  • 对于页面有多个整体的form提交,每个form表单里类型为文本框、下拉框、单选框、复选框等类型,可对类型进行封装,使用循环遍历使页面呈现不同类型表单项
<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> 
        
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178

什么是 Vite?

前端达人

一、什么是 Vite 

Vite 是 vue 的作者尤雨溪在开发 vue3.0 的时候开发的一个 web 开发构建工具。由于其原生 ES 模块导入方式,可以实现闪电般的冷服务器启动。

二、Vite 和 Webpack 区别

Vite 优势:

  1. vite 开发服务器启动速度比 webpack 快
    webpack 会先打包,然后启动开发服务器,请求服务器时直接给予打包结果。
    vite 在启动开发服务器时不需要打包,也就意味着不需要分析模块的依赖、不需要编译,因此启动速度非常快。当浏览器请求某个模块时,再根据需要对模块内容进行编译。这种按需动态编译的方式,极大的缩减了编译时间,项目越复杂、模块越多,vite的优势越明显。
  2. 由于现代浏览器本身就支持ES Module,会自动向依赖的Module发出请求。vite充分利用这一点,将开发环境下的模块文件,就作为浏览器要执行的文件,而不是像webpack那样进行打包合并。
  3. vite 热更新比 webpack 快
    在 HMR 方面,当改动了一个模块后,vite仅需让浏览器重新请求该模块即可,不像webpack那样需要把该模块的相关依赖模块全部编译一次,效率更高。
  4. vite 使用esbuild(Go 编写) 预构建依赖,比 webpack 的 nodejs,快 10-100 倍。

Vite 劣势:

  1. 生态不及webpack,加载器、插件不够丰富
  2. 打包到生产环境时,vite使用传统的 rollup(也可以自己手动安装webpack来)进行打包
  3. 项目的开发浏览器要支持 ES Module,而且不能识别 CommonJS 语法

其他区别:

     1. 打包原理的区别

webpack
webpack打包原理
 
vite打包原理

     2. 项目入口文件的区别
         
项目根目录的 index.html 是 Vite 项目的入口文件,而 webpack 的入口文件是 webpack 配置 entry 中指定的 js 文件。

三、Esbuild

Esbuild 是一款基于 Go 语言开发的 javascript 打包工具,最大的一个特征就是

通过官网提供的一张图,我们可以清晰的看到 Esbuild 的表现是多么优秀:

Esbuild 之所以能这么快,主要原因有两个:

  • Go 语言开发,可以多线程打包,代码直接编译成机器码;

    Webpack 一直被人诟病构建速度慢,主要原因是在打包构建过程中,存在大量的 resolveloadtransformparse 操作(详见 为什么有人说 vite 快,有人却说 vite 慢?- 快速的冷启动 ),而这些操作通常是通过 javascript 代码来执行的。要知道,javascript 并不是什么高效的语言,在执行过程中要先编译后执行,还是单线程并且不能利用多核 cpu 优势,和 Go 语言相比,效率很低。

  • 可充分利用多核 cpu 优势;

关键 API - transfrom & build

Esbuild 并不复杂,它对外提供了两个 API:transform 和 build,使用起来非常简单。

transfrom,转换的意思,将 tsjsxtsx 等格式的内容转化为 js。 transfrom 只负责文件内容转换,并不会生成一个新的文件。

build,构建的意思,根据指定的单个或者多个入口,分析依赖,并使用 loader 将不同格式的内容转化为 js 内容,生成一个或多个 bundle 文件。

Esbuild 在 Vite 中的巧妙使用

我们来看看Vite 是怎么利用 Esbuild 来做预构建和内容转换的。

预构建

为什么要做预构建?原因有两点:

  • 将非 ESM 规范的代码转换为符合 ESM 规范的代码;

  • 将第三方依赖内部的多个文件合并为一个,减少 http 请求数量;

middlewares 中内容转换

Vite 中源文件的转换是在 dev server 启动以后通过 middlewares 实现的。

当浏览器发起请求以后,dev sever 会通过相应的 middlewares 对请求做处理,然后将处理以后的内容返回给浏览器。

middlewares 对源文件的处理,分为 resolveloadtransformparser 四个过程:

  1. resolve - 解析 url,找到源文件的绝对路径;

  2. load - 加载源文件。如果是第三方依赖,直接将预构建内容返回给浏览器;如果是业务代码,继续 transformparser

  3. transfrom - 对源文件内容做转换,即 ts -> jsless -> css 等。转换完成的内容可以直接返回给浏览器了。

  4. parser - 对转换以后的内容做分析,找到依赖模块,对依赖模块做预转换 - pre transform 操作,即重复 1 - 4

    pre transform 是 Vite 做的一个优化点。预转换的内容会先做缓存,等浏览器发起请求以后,如果已经完成转换,直接将缓存的内容返回给浏览器。

Vite 在处理步骤 3 时,是通过 esbuild.transform 实现的,对比 Webpack 使用各个 loader 处理源文件,那是非常简单、快捷的。

四、关于 Vite 的一些其他知识

  • 在工程中不是所有的引用模块都是ES写法,可能是CommonJS 和 UMD 、AMD 等等,这个时候Vite 会进行预构建,将其转换为ESM模块,以支持Vite。
  • 对于JSX、或者TS 等需要编译的文件,Vite是用esbuild来进行编译的。

五、Webpack 和 Rollup 区别

经验法则:对于应用使用 webpack,对于类库使用 Rollup。

如果你需要代码拆分(Code Splitting),或者你有很多静态资源需要处理,再或者你构建的项目需要引入很多CommonJS模块的依赖,那么 webpack 是个很不错的选择。

如果您的代码库是基于 ES2015 模块的,而且希望你写的代码能够被其他人直接使用,你需要的打包工具可能是 Rollup 。

蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请加蓝小助,微信号:ben_lanlan,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系01063334945。


分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。


蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务UI设计公司、界面设计公司、UI设计服务公司、数据可视化设计公司、UI交互设计公司、高端网站设计公司、UI咨询、用户体验公司、软件界面设计公司

nodejs--图片上传

前端达人

前端部分

html部分


  1. <div class="add">
  2. <p>商品名称: <input type="text" class="productName"></p>
  3. <p>商品价格: <input type="number" class="price" ></p>
  4. <!-- multiple: 允许同时上传多张图片 -->
  5. <!-- <p>商品图片: <input type="file" class="file" multiple="multiple"></p> -->
  6. <p>商品图片: <input type="file" class="file"></p>
  7. <p><button class="add-btn">添加商品</button></p>
  8. </div>
  9. <script src="js/axios.js"></script>
  10. <script src="js/util.js"></script>
  11. <script src="js/upload.js"></script>

upload.js


  1. // 新建表单数据对象,用来存储上传的文件及上传的其它数据
  2. let param = new FormData()
  3. $(".file").onchange = function(){
  4. //获取图片信息
  5. let file = this.files[0]
  6. //"file"为前后端约定vb的属性名
  7. param.append("file",file)
  8. }
  9. $(".add-btn").onclick = function(){
  10. let productName = $(".productName").value;
  11. let price = $(".price").value;
  12. param.append("productName",productName)
  13. param.append("price",price)
  14. axios.post("/product",param,{
  15. headers: {
  16. // 默认提交的类型
  17. // "content-type": "application/json"
  18. // 复杂的表单数据(只要上传文件,就必须是下面的类型)
  19. "content-type": "multipart/form-data"
  20. }
  21. })
  22. .then((res)=>{
  23. console.log(res.data);
  24. })
  25. }

postman

 

Express后端部分

使用multer实现图片上传

下载

npm i multer -S

引入


  1. const multer = require("multer")
  2. const path = require("path")

配置

注意: 该文件在/router文件夹中,而uploads存放上传图片文件夹在根目录


  1. var storage = multer.diskStorage({
  2. // 配置文件上传后存储的路径
  3. destination: function (req, file, cb) {
  4. // NodeJS的两个全局变量
  5. // console.log(__dirname); //获取当前文件在服务器上的完整目录
  6. // console.log(__filename); //获取当前文件在服务器上的完整路径
  7. cb(null, path.join(__dirname,'../uploads'))
  8. },
  9. // 配置文件上传后存储的路径和文件名
  10. filename: function (req, file, cb) {
  11. console.log('file',file);
  12. cb(null, Date.now() + path.extname(file.originalname))
  13. }
  14. })
  15. var upload = multer({ storage: storage })

在路由中使用


  1. //添加商品
  2. router.post("/product",upload.single("file1"),(req,res)=>{
  3. //接收普通文本参数
  4. let {productName,price} = req.body;
  5. 、接收上传文件数据 -->
  6. let imgUrl = req.file.filename;
  7. let sql = "insert into product (productName,price,imgUrl) values (?,?,?)"
  8. conn.query(sql,[productName, price , imgUrl],(err,result)=>{
  9. if (err){
  10. console.log('增加失败');
  11. return;
  12. }
  13. let data;
  14. if (result.affectedRows === 1){
  15. data = {
  16. code: 0,
  17. msg: '添加成功'
  18. }
  19. }else{
  20. data = {
  21. code: 1,
  22. msg: '添加失败'
  23. }
  24. }
  25. res.send(data)
  26. })
  27. })

如果抽离路由模块中的处理函数upload.single("file1")写在Router模块

实现写在抽取的模块 

 NODEJS--express图片上传 - 简书

如果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




蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请加蓝小助,微信号:ben_lanlan,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系01063334945。


分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。


蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务UI设计公司、界面设计公司、UI设计服务公司、数据可视化设计公司、UI交互设计公司、高端网站设计公司、UI咨询、用户体验公司、软件界面设计公司

日历

链接

个人资料

蓝蓝设计的小编 http://www.lanlanwork.com

存档