JavaWeb
参考文章:
https://heavy_code_industry.gitee.io/code_heavy_industry/pro001-javaweb/lecture/
01、Web基础概念简介
1、服务器与客户端
线下的服务器与客户端
线上的服务器与客户端
客户端的各种形式
PC端网页
移动端
Iot设备
服务器的各种形式
参考文章:https://heavy_code_industry.gitee.io/code_heavy_industry/pro000-dev-story/chapter11/content.html
2、服务器端应用程序
我们要开发的就是服务器端应用程序。
3、业务
项目中的功能就是业务。
4、请求和响应
发生在饭馆的请求和响应
项目中的请求和响应
5、项目的逻辑构成
-
请求:请求是项目中最基本的逻辑单元,就像万事万物都由原子构成
举例:点超链接跳转到注册页面
-
功能:一个功能包含很多个请求
举例:注册用户功能
- 请求1:点超链接跳转到注册页面
- 请求2:发送请求获取短信验证码
- 请求3:检查用户名是否可用
- 请求4:提交表单完成注册
-
模块:一个模块包含很多功能
举例:用户信息管理模块
- 功能1:用户注册功能
- 功能2:用户登录功能
- 功能3:个人中心——账户安全功能
- 功能4:个人中心——账户绑定功能
- 功能5:个人中心——收货地址功能
- 功能6:个人中心——我的银行卡功能
-
子系统:根据项目规模的不同,子系统这层逻辑概念可能有也可能没有。如果设置了子系统,那么子系统中也必然包含很多模块。其实庞大项目的子系统已经相当于一个项目了,甚至比小型项目整个都大。
举例:认证中心子系统
- 模块1:用户信息管理模块
- 模块2:权限管理模块
- 模块3:授权管理模块
- 模块4:权限检查模块
-
项目:为了解决现实生活中的实际问题开发一个项目,这个项目就是为这个需求提供的一整套解决方案。
举例:电商项目
- 子系统1:认证中心子系统
- 子系统2:商品管理子系统
- 子系统3:购物车子系统
- 子系统4:仓储子系统
- 子系统5:物流子系统
- 子系统6:订单子系统
6、架构
01、概念
『架构』其实就是项目的『结构』。只不过『结构』这个词太小了,不适合用来描述项目这么大的东西,所以换了另一个更大的词:架构。所以当我们聊一个项目的架构时,我们聊的是项目是由哪些部分组成的。
02、发展演变历程
一个项目就是一个工程,这样的结构就是单一架构,也叫all in one。我们现在的JavaWeb阶段、SSM阶段都是学习单一架构开发技术。
分布式架构
一个项目中包含很多工程,每个工程作为一个模块。模块之间存在调用关系。分布式架构阶段的技术分为两类:
- Java框架:SpringBoot、SpringCloud、Dubbo等等。
- 中间件:Redis、ElasticSearch、FastDFS、Nginx、Zookeeper、RabbitMQ等等。
03、单一架构技术体系
- 视图:用户的操作界面+数据的动态显示
- 前端技术:HTML/CSS/JavaScript
- 服务器端页面模板技术:Thymeleaf
- 控制层:处理请求+跳转页面
- 服务器:Tomcat
- 控制器:Servlet
- 域对象:request、session、servletContext
- 过滤器:Filter
- 监听器:Listener
- 异步交互:Ajax
- 业务逻辑层:业务逻辑计算
- 持久化层:操作数据库
7、本阶段技术体系
8、本阶段案例简介
02、拜托了大脑
0、学习中的痛点问题
- 为什么明明很努力了,但就是没效果?
- 学完记不住怎么办?
- 每天上课老师讲的代码我也都敲(抄)了,但是感觉什么都没学会怎么办?
- 为什么学着学着会感觉跟不上了?
- 学的东西太多感觉非常混乱怎么办?
1、人和人的差异是『系统』的差异
起点、路径、目标
为什么同样是毕业5年,你和你的同学差距特别大?起点、路径、目标这三个东西哪个对人影响最大?
- 目标:有的人目标是1亿,有的人目标是够吃饭就行。目标不同活法肯定不同。
- 路径:有的人根本不知道路在哪,有的人靠两条腿狂奔,有的人开汽车,有的人坐飞机,有的人坐火箭。
- 起点:最不重要的就是起点。对那些靠两条腿跑的人来说,10公里是非常遥远的距离,但是对开汽车的人来说很近。
如果一个问题的解决办法已经有别人反复验证过可行、有效的路径存在,那这种问题就非常容易解决。但即使这样不同的人应对同样问题时效果也完全不同。从深圳到北京,徒步、开车、高铁、飞机就是效率完全不同的解决方案。
在路上使用的交通工具不同就是人和人之间系统的不同,而系统其实就是一个人的认知水平、思维方式、学习和工作的方法。
思维跃迁
世界本身是极其复杂的,即使是细分之后的领域仍然非常复杂,比如一颗小小的芯片背后就是一个非常庞大、复杂的体系:科学、技术、设计、制造、供应链、操作系统、市场等等。面对这么复杂的世界,简单的思维方式是没法理解和应对的。而比我们成功的人一定是从更底层把握了复杂世界中简单规律的人。
穿透现象看到本质
实现同一个功能,代码可以有很多种不同的写法,我们要做的并不是把某一种代码背下来,而是直击本质,把握规律,以不变应万变。
宏观视野
将来大家走上工作岗位,参与开发都是非常庞大的系统,此时要求大家能够把视角拔高,从最高处俯瞰整个项目的架构。而在具体的开发过程中对于微观的代码编写和故障调试又要求能够做到细致认真,对程序员来说这两种看似矛盾的能力必须同时具备。
目标导向
任何项目、任何技术都是为了解决实际问题而生的,所以我们不论是在技术学习过程中还是在项目开发过程中都要锻炼自己理解需求的能力和根据需求设定目标的能力。有了明确的目标下一步才能一步一步分析出实现目标的思路,然后根据思路中的各个环节编写代码,最终把需求落地实现。
抽象空间
一个人每天按时上课,按时自习,从不违纪,身体确实在教室,但是灵魂早已不知到哪里游荡,他算努力吗?
一个人把老师的代码抄了一遍又一遍,把课件背了一回又一回,他算努力吗?
一个人顶着狂风烈日面试了一家又一家公司,屡战屡败,屡败屡战,他算努力吗?
另一个人看着好像也没怎么努力,该打球打球,该拍拖拍拖,面试没几家就拿到N个不错的offer,老师劝他不着急入职,再多面几家肯定有更好的,他说现在这个不错了,懒的面了。你好像确实没法说他*『努力』*,但是你不得不承认至少单纯在**『参加培训找工作』这一件事上他很『成功』**。
所以老师不必费力向你证明前面那三个人并没有*『真正努力』*,而只是*『用战术上的勤奋掩盖战略上的懒惰』*——老师希望你注意到:即使是**『真正的努力』仍然只是『手段』而不是『目的』,我们真正的目的是『成功』**。不管过程中再怎么努力,最后达不成目的不还是白搭?当然,如果因此你得出一个结论就是那我不用努力了我也没有办法,毕竟谁都没法叫醒一个装睡的人不是?
那怎么做算是**『战略正确』**呢?
进军抽象空间,到抽象空间里占领一个又一个知识高地。
学习的真正过程发生在人的意识中,而意识是看不见、摸不着的。所以当一个同学『人在教室、神游天外』时,老师明知道他没在学习可是还真不好说啥,因为他确实没有违反纪律。纪律只能在物质世界设置规则,而没法限制你的想法。
但所谓知识其实就是人类认识世界过程中总结、提炼的结晶,全部都是抽象的概念,同样看不见、摸不着。我们上课的过程就是老师把他自己的意识空间用声音和图像投影到教室里,然后再投影到你的意识空间——毕竟老师没法双掌贴着你的后背把毕生功力传给你。
大家需要接收到声音和图像的信号,然后理解它们的含义,再重新凝练成一个一个的概念结晶,最后还要分门别类、井然有序的保存起来以备将来使用。
所以学习真要比的话应该比的就是在意识空间中知识晶体的\数量**和*秩序***。
很多人为什么学习起来非常吃力?就是因为他完全没有办法进入抽象空间,完全没法理解任何抽象的东西。这里我们举个例子:
具象:3×2=6,2×3=6,4×7=28,7×4=28,……
抽象:乘法交换律
用具象的算式描述这个规律可以写出无限多个,可是用抽象的规律短短五个字就概括了。这就是掌握规律的力量,这就是为什么培根说『知识就是力量』。好在老师会用举例、类比、画图等等手段把抽象的东西尽量具象化,但是谁也代替不了你自己的理解、提炼和总结。不过好消息是现在你知道怎么努力了。
所以各位朝气蓬勃的少男少女们,充分调动起你活跃的大脑,一起来提炼闪闪发光的知识晶体吧!
2、『学习能力』就是一个系统
敞开心扉
你真的对技术感兴趣吗?
小明拿瓶子去接水,咕咚咕咚一通灌。完事儿一看,瓶子里一滴水都没有。
为啥?瓶塞没有拔出来。
像不像你叫嚷着学Java,但其实真正的内心对Java没有任何兴趣,只是因为听说它很赚钱才学。你**『真正喜欢』的是『钱』而不是『Java』**。
而真正学的时候内心是**『抗拒』**的,你觉得这东西和你一点关系都没有。禁闭的心扉如同没有拔掉木塞的瓶子。这样谁都帮不了你,不管听了多少课都学不到东西的。
正确的状态是:对『Java本身』贼啦好奇,**『挖空心思』**想闹明白到底是咋回事,谁不让我学我跟谁急。
学会以后干活,不给钱也干,谁不让我干我跟谁急,然后肯定会干得特别好,**『意外』**赚了很多钱。
任何成功都来自于*『内心深处强烈的渴求』*。而程序员的成功秘诀是*『敲代码本身即是最大幸福和最高奖赏』*。
很多同学总是问学完Java用不用再学学大数据呀?Java干3年以后转型什么呀?
其实Java也好,大数据也好,都是『路径』,不是『目标』。你的**『好奇心』**决定了你在这条路上能够走多远。而培训完的起薪都只是『起点』,前面说过了,三者中『起点』是最不重要的。
在以后的学习中我们任何技术点都会通过提出问题的方式来引入,大家要留意这个环节,在揭示答案之前用这个问题问问自己,看看这个问题是否能在你的心里引起共鸣,激发你的好奇心,这是我们迈向成功的第一步。
大脑的工作机制
大脑的结构
- 最内层:爬行动物脑,只在乎吃饭和制造下一代,再复杂点的事情就理解不了了。
- 中间层:哺乳动物脑,感情中枢,很多哺乳动物都进化出了这一层大脑,所以你会感觉到你家狗狗对你非常有感情——相信我,那是真感情。
- 最外层:大脑皮层,人的理性思维在这里生成,语言、视觉、听觉、逻辑思维、空间想象力等等都在大脑皮层这里有专门的负责区域。其中学Java的时候要用到的理性思维是大脑皮层中的**『前额叶』**这个部分。可以说迄今为止人类文明所造就的所有辉煌成果都是建立在前额叶的基础上。
]死记硬背?
不会吧,不会吧?现在还有同学想靠死记硬背来学Java?请马上停止!
相比较**『记忆』来说,大脑更擅长『思考』**。前面说过思考是由前额叶来负责的,下面说说记忆:
- 临时记忆:海马体。比如别人和你说忙完给他打个电话,你当时答应了但是一转眼就忘了。信息刚刚进入大脑的时候其实是在海马体临时存储的。
- 长期记忆:写入大脑皮层。这可不容易,死记硬背就是通过大量的重复把信息强行写入大脑皮层。就好比你非要靠脑子记住一个手机号,大致就是这个办法。但遗憾的是一个孤立的信息即使通过大量重复强行写入到大脑皮层也不会存在太久。小学同学朝夕相处,但是分开20年还是会忘记很多人的名字。
这就是为什么总有同学很困扰:学完了记不住呀!对于这个问题我的回应如下:
-
你想记住啥?
你想记住代码怎么写吗?需求会变,代码永远要跟着变。
你想记住老师说的每一句话吗?老师一天能说一万句话。
想记住这些这不是痴心妄想吗?
-
你该记住啥?
具象:3×2=6,2×3=6,4×7=28,7×4=28,……
抽象:乘法交换律
你该记住的是从现象中提取出来的规律而不是现象。甚至这么说也不准确。因为这个规律你理解了自然就记住了,不需要背。
-
知识的网络
任何孤立的信息都很容易忘,但是点和点之间组成一个彼此联系的网络就很不容易忘记了。
-
细节记不住咋办?
即使理解并且记住了要点,但是知识点相关的细节还是记不住怎么办?比如大段的配置,代码调用的API方法,特定场景需要传递的参数等等。好办,『好记性不如烂笔头』,这些东西记到笔记里永久保存。
外接硬盘
通过前面的分析我们看到,大脑是一个有CPU(前额叶)有内存(海马体)的电脑,但是没有硬盘来做永久存储。所以我们需要给大脑连接一个能够永久存储信息的外部设备:笔记。由此我们就得出了大脑要扮演的第一个角色:搜索引擎。
首先,学习的过程就是建设索引库的过程:
然后在解决实际问题时需要运用学过的知识就到索引库中去检索:
快思维和慢思维
大脑的第二个角色是:司令部。而你是司令。对,你没看错,其实『你不是你的大脑,你的大脑也不是你』。就像手、脚、胯骨轴是你的一部分一样,大脑同样只是你的一部分。但是大脑对人来说太重要了,人的很多无意识行为都是大脑来协调和指挥的。比如:人走路时的身体平衡,身体各个系统和脏器的正常工作,应激反应等等都是大脑来指挥的,而这些事情你完全不知道是怎么做的,也无法干涉。司令部协助司令指挥部队,司令把握总体的战略方向。
而司令部这个角色和学习有关系的部分就是大脑的快思维和慢思维。
小孩子没法一边穿衣服、系扣子一边走路。因为它穿衣服、系扣子需要慢慢做,一边做一边想。所以事情不熟练、需要慢慢思考的时候,大脑就需要以慢思维的模式工作——这个过程是需要**『你』**参与的。
大人穿衣服、系扣子都很熟练了,不需要想,所以可以一边走路,一边穿衣服。这个过程就不需要『你』参与了,大脑调用现成的『路径』在快思维的工作模式下完成动作。
这是因为**『慢思维』非常消耗能量,而『快思维』能耗非常低,大脑会优先选择能耗低的路径执行动作,节约能量。这就是为什么人会有『习惯』,而习惯一旦养成很难改变。本质原因就是大脑的这种『路径依赖』**的机制。
知识的知识:元知识
知识点
比如:**『黄赤交角导致地球上四季更迭』**这就是一个知识点。
前置知识
想理解『黄赤交角导致地球上四季更迭』这个知识点的前提是知道『赤道』、『黄道』、『地球自转』、『地球公转』等等概念,还必须具备一定的『立体几何』的基础。这就说明知识的大厦是一砖一瓦建成的,没有1楼别想上2楼。
如果想理解B的前提是知道A,那么A就是B的前置知识点。
知识链
把所有前置知识连起来就形成了一条知识的链条。虽然我们学习的时候不需要把这个链条画出来,但是它可以帮助你理解你为什么会跟不上:在知识的链条中前置知识点缺失太多了。不知道『赤道』、『黄道』、『地球自转』、『地球公转』等等概念也不理解两个平面之间的夹角是怎么回事的时候听别人给你讲地球上为什么会有春夏秋冬那就是听天书,完全不明白什么意思。
知识树
为什么老师讲课的课件总是划分成章节,章节里面还有一、二、三、……1、2、3、……①、②、③、……这样的小点?就是因为知识点根据彼此之间的归类和相关性可以『纵向抽取』,从而整理成一个树形结构,这样也是为了大家更好理解。
但是老师讲课的时候还是要从这根葡萄梗上把葡萄一颗一颗摘下来给你。
而你拿到葡萄以后就乱放了,散落一地的葡萄非常不好拿,到用的时候各种颜色的葡萄混杂的胡乱堆放在一起,根本找不到你要的。
所以大家听完课还是要在自己的精神世界里把葡萄往葡萄梗上一颗一颗装回去。用专业术语来说就是把节点按照树形结构重新组装起来。
知识网络
哲学知识点:矛盾是对立统一,矛盾中对立的双方都不能脱离对方而单独存在。
化学知识点:在碱溶液中会有极少量的H+离子,在酸溶液中会有极少量的OH-离子。
横向来看,知识点之间很容易找到相通或类似的情况。有些知识点之间的横向对比能够彼此印证,帮助我们理解;而有些看起来相似但实质不同的知识点却会干扰我们的判断和使用。
所以知识点融会贯通之后必然会打破彼此的界限连成网络,这个网络越发达你的视野越开阔,网络中的具体知识点掌握越牢固。
知识体系
在生物学中把生物划分为了界、门、纲、目、科、属、种,这有什么好处呢?不仅让已知的生物更易于研究和学习,将来发现新物种就直接按照这个划分方法纳入体系就好了。
有了知识体系之后,你的学习会非常快速,因为新的知识点会快速被已有的知识体系接纳,旧的知识会帮助你理解新的知识。
MySQL | Redis | |
---|---|---|
数据库连接 | Connection | Jedis |
数据库连接池 | Druid | JedisPool |
连接信息 | 主协议:子协议://主机地址:端口号/数据库名称 用户名 密码 数据库驱动 | 主机地址:端口号 |
当你不断的感受到旧知识点在帮助你理解新知识点,你的知识体系就在不断扩大;知识系统不断扩大之后,旧知识点对新知识点的帮助能力就更大,形成一个*『增强回路』*,让你的学习越来越快,形成一条指数曲线。
卖油翁的微笑
陈康肃公善射,当世无双 ,公亦以此自矜。尝射于家圃,有卖油翁释担而立,睨之久而不去。见其发矢十中八九,但微颔之。 康肃问曰:“汝亦知射乎?吾射不亦精乎?”。翁曰:“无他, 但手熟尔。”康肃忿然曰:“尔安敢轻吾射!”翁曰:“以我酌油知之。”乃取一葫芦置于地,以钱覆其口,徐以杓酌油沥之,自钱孔入,而钱不湿。因曰:“我亦无他,惟手熟尔。”康肃笑而遣之。
编程本质上是一个技能,而任何技能都需要通过大量的重复练习才能够熟练掌握。李小龙说:『我不怕会一万种招式的人,我怕把一种招式练一万次的人』。神枪手是用一匣一匣的子弹喂出来的,优秀的程序员就是用一堆又一堆的bug给练出来的。所以学编程肯定要多敲多练。
但是我说的是**『敲』不是『抄』**!很多同学照着老师的代码敲自己的代码,看着是敲了一遍,其实只是抄了一遍。抄完发现没有什么效果。关上电脑什么都不记得。这其实是正常的认知规律的体现。
在『抄』的时候大脑其实不需要多想什么,因为它只需要考虑A处是什么单词,再到B处敲同样的单词就行了,这是一件很简单的事情,大脑调用5%就足够了——这调用深度远远不够。而且你不觉得非常枯燥无聊吗?
真正的学习状态是什么?向知识点提问、打草稿、分析思路、画流程图、和别人讨论、敲代码验证、分析结果为什么和老师不一样、把验证结果写到笔记里……
你看看这是不是热火朝天?这么整的话大脑的利用率可是有95%啊!而且兴趣盎然啊有木有?这么学习既高效又开心,谁不让我学我和谁急!
这时大脑扮演了第三个角色:教练。
输出倒逼输入
你有没有发现看老师讲课的视频特别容易睡着?这不是老师讲得不好,也不是你不爱学习,而是单纯的看视频只是被动接受,大脑还是没有充分调动起来。大脑进入闲置状态自然会昏昏欲睡。
而当你和别人讨论问题,把你的观点讲出来,就会越聊越兴奋甚至争得脸红脖子粗有木有?
甚至是在和别人表达自己观点的时候会发现自己以前理解的某个知识点其实完全不是那么回事,开始以为自己懂了但是要说的时候才发现自己根本没有懂,理解的不透彻。
其实在大脑里很多角落都在黑暗中,当我们想拿出来的时候才会用手电筒照过去,把那个地方照亮,照亮以后才能看清楚那里到底放着什么。
所以一切形式的**『输出』**都会非常有效的提高学习效率。那么输出的形式包括哪些呢?
- 做笔记:自己亲手做,不是抄别人的。
- 敲代码:不是抄啊!
- 和别人讨论:有问有答的那种
- 调bug:bug虐我千百遍,我待bug如初恋
- 发博客:积累多了对职业发展很有帮助的哟
总结
说了这么多,我们具体在学习的时候应该怎么学呢?
- 第一步:提出问题,激发好奇。
- 第二步:思考分析,理解原理。
- 第三步:敲代码、调bug练习,验证原理,修正理解。
- 第四步:做笔记,既是备忘,又是建设自己的索引库和知识体系。
- 第五步:遇到相似知识点就详细辨析比对,直到充分区别不会混淆。
- 第六步:回归到真实场景,在项目中运用,彻底掌握这个技术,让所学技术真正落地。
所以**『学习』两个字中,『学』指的是理解原理,建立知识体系,而『习』则是练习技能,引申到各种形式的输出都算『习』。而只有拿学过、练过的东西真正的解决了现实生活中真正的实际问题才算是『会』。而任何形式的市场都只会为能够真正解决问题的人付『钱』**。
03、单一架构回顾
我们从现在的JavaWeb阶段到后面学习SSM框架阶段都是在学习单一架构项目开发的技术。而在JavaWeb阶段由于重点是探讨如何实现Web开发,所以必须学习一部分前端开发的技术。本节就是让大家明确我们现在要学习的内容在整个架构体系中处于什么位置。
1、单一架构技术体系
2、视图层
严格来说视图分成两层:
- 前端技术:HTML/CSS/JavaScript
- 服务器端页面模板技术:Thymeleaf
其中HTML、CSS、JavaScript都是工作在浏览器上的,所以它们都属于前端技术。而Thymeleaf是在服务器上把动态内容计算出具体数据,所以严格来说Thymeleaf是后端技术。
这里大家会有个疑问:为什么在『视图』这个地方已经有HTML、CSS、JavaScript这些前端技术了,能够生成用户可以操作的界面,那为什么还需要Thymeleaf这样一个后端技术呢?
简单来说原因是Thymeleaf=HTML+动态数据,而HTML不支持动态数据,这部分需要借助Thymeleaf来完成。
更进一步的细节咱们讲到那再说啦!
3、Web2.0
Web2.0是相对于更早的网页开发规范而提出的新规范。Web2.0规范之前的网页开发并没有明确的将HTML、CSS、JavaScript代码分开,而是互相之间纠缠在一起,导致代码维护困难,开发效率很低。
在开发中我们把这样彼此纠缠、互相影响的现象称为『耦合』。而把耦合在一起的东西拆解开,让他们彼此独立出来称为『解耦』。各个组成部分独立完成自己负责的功能,和其他模块无关称为『内聚』。
将来大家经常会听到一句话:软件开发提倡『 高内聚,低耦合』。
一个软件项目只有做到了高内聚、低耦合才能算得上结构严谨,模块化程度高,有利于开发和维护。
所以Web2.0规范主张将网页代码分成下面三个部分:
- 结构:由HTML实现,负责管理网页的内容。将来网页上不管是静态还是动态的数据都是填写到HTML的标签里。
- 表现:由CSS实现,负责管理网页内容的表现形式。比如:颜色、尺寸、位置、层级等等。也就是给数据穿上一身漂亮的衣服。
- 行为:由JavaScript实现,负责实现网页的动态交互效果。比如:轮播图、表单验证、鼠标滑过显示下拉菜单、鼠标滑过改变背景颜色等等。
04、HTML&CSS
一、HTML简介
参考文章:https://www.cnblogs.com/zhaostudy/p/16685971.html
1、名词解释
HTML是Hyper Text Markup Language的缩写。意思是*『超文本标记语言』*。
2、超文本
HTML文件本质上是文本文件,而普通的文本文件只能显示字符。但是HTML技术则通过HTML标签把其他网页、图片、音频、视频等各种多媒体资源引入到当前网页中,让网页有了非常丰富的呈现方式,这就是超文本的含义——本身是文本,但是呈现出来的最终效果超越了文本。
3、标记语言
说HTML是一种『标记语言』是因为它不是向Java这样的『编程语言』,因为它是由一系列『标签』组成的,没有常量、变量、流程控制、异常处理、IO等等这些功能。HTML很简单,每个标签都有它固定的含义和确定的页面显示效果。
标签是通过一组尖括号+标签名的方式来定义的:
HTML is a very popular fore-end technology.
这个例子中使用了一个p标签来定义一个段落,
叫*『开始标签』*,
叫*『结束标签』*。开始标签和结束标签一起构成了一个完整的标签。开始标签和结束标签之间的部分叫*『文本标签体』*,也简称*『标签体』*。
有的时候标签里还带有*『属性』*:
show detail
href="http://www.xxx.com"就是属性,href是**『属性名』**,"http://www.xxx.com"是**『属性值』**。
还有一种标签是*『单标签』*:
4、HelloWorld
5、HTML文件结构
文档类型声明
HTML文件中第一行的内容,用来告诉浏览器当前HTML文档的基本信息,其中最重要的就是当前HTML文档遵循的语法标准。这里我们只需要知道HTML有4和5这两个大的版本,HTML4版本的文档类型声明是:
HTML5版本的文档类型声明是:
现在主流的技术选型都是使用HTML5,之前的版本基本不用了。
历史上HTML的各个版本:
版本名称 | 年份 |
---|---|
HTML | 1991 |
HTML+ | 1993 |
HTML2.0 | 1995 |
HTML3.2 | 1997 |
HTML4.01 | 1999 |
XHTML1.0 | 2000 |
HTML5 | 2012 |
XHTML5 | 2013 |
根标签
html标签是整个文档的根标签,所有其他标签都必须放在html标签里面。上面的文档类型不能当做普通标签看待。
所谓『根』其实是『树根』的意思。在一个树形结构中,根节点只能有一个。
头部
head标签用于定义文档的头部,其他头部元素都放在head标签里。头部元素包括title标签、script标签、style标签、link标签、meta标签等等。
主体
body标签定义网页的主体内容,在浏览器窗口内显示的内容都定义到body标签内。
注释
HTML注释的写法是:
注释的内容不会显示到浏览器窗口内,是开发人员用来对代码内容进行解释说明。
6、HTML语法规则
- 根标签有且只能有一个
- 无论是双标签还是单标签都必须正确关闭
- 标签可以嵌套但不能交叉嵌套
- 注释不能嵌套
- 属性必须有值,值必须加引号,单引号或双引号均可
- 标签名不区分大小写但建议使用小写
二、使用HTML展示文章
以文章的组织形式展示数据是HTML最基本的功能了,网页上显示的文章在没有做任何CSS样式设定的情况下如下图所示:
本节我们要学习的HTML标签如下表:
标签名称 | 功能 |
---|---|
h1~h6 | 1级标题~6级标题 |
p | 段落 |
a | 超链接 |
ul/li | 无序列表 |
img | 图片 |
div | 定义一个前后有换行的块 |
span | 定义一个前后无换行的块 |
为了方便编写代码,我们在IDEA中创建一个静态Web工程来操作:
1、标题标签
代码
Title
这是一级标题
这是二级标题
这是三级标题
这是四级标题
这是五级标题
这是六级标题
页面显示效果
注意:标题标签前后有换行。
2、段落标签
代码
There is clearly a need for CSS to be taken seriously by graphic artists. The Zen Garden aims to excite, inspire, and encourage participation. To begin, view some of the existing designs in the list. Clicking on any one will load the style sheet into this very page. The code remains the same, the only thing that has changed is the external .css file. Yes, really.
页面显示效果
注意:段落标签前后有换行。
3、超链接
代码
点我跳转到下一个页面
页面显示效果
点击后跳转到href属性指定的页面
4、路径
在我们整个Web开发技术体系中,『路径』是一个贯穿始终的重要概念。凡是需要获取另外一个资源的时候都需要用到路径。要想理解路径这个概念,我们首先要认识一个概念:『文件系统』。
文件系统
我们写代码的时候通常都是在Windows系统来操作,而一个项目开发完成后想要让所有人都能够访问到就必须『部署』到服务器上,也叫『发布』。而服务器通常是Linux系统。
Windows系统和Linux系统的文件系统有很大差别,为了让我们编写的代码不会因为从Windows系统部署到了Linux系统而出现故障,实际开发时不允许使用物理路径。
物理路径举例:
D:\aaa\pro01-HTML\page01-article-tag.html
D:\aaa\pro01-HTML\page02-anchor-target.html
幸运的是不管是Windows系统还是Linux系统环境下,目录结构都是树形结构,编写路径的规则是一样的。
所以我们以项目的树形目录结构为依据来编写路径就不用担心操作系统平台发生变化之后路径错误的问题了。有了这个大前提,我们具体编写路径时有两种具体写法:
- 相对路径
- 绝对路径(建议使用)
相对路径
相对路径都是以\『当前位置』**为基准**来编写的。假设我们现在正在浏览a页面,想在a页面内通过超链接跳转到z页面。
那么按照相对路径的规则,我们现在所在的位置是a.html所在的b目录:
z.html并不在b目录下,所以我们要从b目录出发,向上走,进入b的父目录——c目录:
c目录还是不行,继续向上走,进入c的父目录——d目录:
在从d目录向下经过两级子目录——e目录、f目录才能找到z.html:
所以整个路径的写法是:
To z.html
可以看到使用相对路径有可能会很繁琐,而且在后面我们结合了在服务器上运行的Java程序后,相对路径的基准是有可能发生变化的,所以不建议使用相对路径。
绝对路径
通过IDEA服务器打开HTML文件
测试绝对路径的前提是通过IDEA的内置服务器访问我们编写的HTML页面——这样访问地址的组成结构才能和我们以后在服务器上运行的Java程序一致。
服务器访问地址的组成
绝对路径的写法
绝对路径要求必须是以**『正斜线』**开头。这个开头的正斜线在整个服务器访问地址中对应的位置如下图所示:
这里标注出的这个位置代表的是*『服务器根目录』*,从这里开始我们就是在服务器的内部查找一个具体的Web应用。
所以我们编写绝对路径时就从这个位置开始,按照目录结构找到目标文件即可。拿前面相对路径中的例子来说,我们想在a.html页面中通过超链接访问z.html。此时路径从正斜线开始,和a.html自身所在位置没有任何关系:
To z.html
具体例子
编写超链接访问下面的页面:
Cat Page
小结
为了和我们后面学习的内容和正确的编码方式保持一致,建议大家从现在开始就使用绝对路径。
5、换行
代码
We would like to see as much CSS1 as possible. CSS2 should be limited to widely-supported elements only. The css Zen Garden is about functional, practical CSS and not the latest bleeding-edge tricks viewable by 2% of the browsing public.
The only real requirement we have is that your CSS validates.
页面显示效果
6、无序列表
代码
- Apple
- Banana
- Grape
页面显示效果
7、图片
准备图片文件
代码
src属性用来指定图片文件的路径,这里同样按我们前面说的使用*『绝对路径』*。
页面显示效果
8、块
**『块』**并不是为了显示文章内容的,而是为了方便结合CSS对页面进行布局。块有两种,div是前后有换行的块,span是前后没有换行的块。
把下面代码粘贴到HTML文件中查看他们的区别:
This is a div block
This is a div block
This is a span block
This is a span block
页面显示效果为:
9、HTML实体
在HTML文件中,<、>等等这样的符号已经被赋予了特定含义,不会作为符号本身显示到页面上,此时如果我们想使用符号本身怎么办呢?那就是使用HTML实体来转义。
三、使用HTML收集表格数据
参考文章:
HTML DOM Table 对象 (w3school.com.cn)
Table 对象
Table 对象代表一个 HTML 表格。
在 HTML 文档中
标签每出现一次,一个 Table 对象就会被创建。
Table 对象集合
集合 | 描述 |
---|---|
[cells] | 返回包含表格中所有单元格的一个数组。 |
[rows] | 返回包含表格中所有行的一个数组。 |
tBodies[] | 返回包含表格中所有 tbody 的一个数组。 |
Table 对象属性
属性 | 描述 |
---|---|
align | 表在文档中的水平对齐方式。(已废弃) |
bgColor | 表的背景颜色。(已废弃) |
border | 设置或返回表格边框的宽度。 |
caption | 对表格的元素的引用。 |
cellPadding | 设置或返回单元格内容和单元格边框之间的空白量。 |
cellSpacing | 设置或返回在表格中的单元格之间的空白量。 |
frame | 设置或返回表格的外部边框。 |
id | 设置或返回表格的 id。 |
rules | 设置或返回表格的内部边框(行线)。 |
summary | 设置或返回对表格的描述(概述)。 |
tFoot | 返回表格的 TFoot 对象。如果不存在该元素,则为 null。 |
tHead | 返回表格的 THead 对象。如果不存在该元素,则为 null。 |
width | 设置或返回表格的宽度。 |
标准属性
属性 | 描述 |
---|---|
className | 设置或返回元素的 class 属性。 |
dir | 设置或返回文本的方向。 |
lang | 设置或返回元素的语言代码。 |
title | 设置或返回元素的 title 属性。 |
Table 对象方法
方法 | 描述 |
---|---|
createCaption() | 为表格创建一个 caption 元素。 |
createTFoot() | 在表格中创建一个空的 tFoot 元素。 |
createTHead() | 在表格中创建一个空的 tHead 元素。 |
deleteCaption() | 从表格删除 caption 元素以及其内容。 |
deleteRow() | 从表格删除一行。 |
deleteTFoot() | 从表格删除 tFoot 元素及其内容。 |
deleteTHead() | 从表格删除 tHead 元素及其内容。 |
insertRow() | 在表格中插入一个新行。 |
水果库存案例
HTML代码
CSS代码
body {
margin: 0;
padding: 0;
/* background-color: #ccc; */
}
div {
position: relative;
float: left;
}
#div_container {
width: 80%;
height: 100%;
margin-left: 10%;
border: 0px solid red;
float: left;
border-radius: 8px;
/* background-color: #ccc; */
}
#div_fruit_list {
width: 100%;
border: 0px darkcyan solid;
}
#tbl_fruit {
width: 80%;
line-height: 28px;
margin-top: 150px;
margin-left: 15%;
}
#tbl_fruit,
#tbl_fruit tr,
#tbl_fruit td,
#tbl_fruit th {
border: 1px dodgerblue solid;
border-collapse: collapse;
text-align: center;
font-size: 16px;
font-family: '黑体';
color: pink;
}
.wp {
width: 20%;
}
.btn {
border: 1px solid sliver;
width: 80px;
height: 24px;
}
JS代码
// 这个方法可以显示在外部的js文件中通过外部导入的方式!
window.onload = function() {
// 当页面加载完成,我们需要绑定各种事件
var fruitTbl = document.getElementById('tbl_fruit');
// 获取表格中的所有的行
var rows = fruitTbl.rows;
for (var i = 1; i < rows.length - 1; i++) {
var tr = rows[i];
trBindEvent(tr);
}
document.getElementById("addBtn").onclick = addFruit;
};
function trBindEvent(tr) {
tr.onmouseover = showBGColor;
tr.onmouseout = clearBGColor;
var cells = tr.cells;
var priceTD = cells[1];
// 当鼠标悬浮在单价单元格变成手势!
priceTD.onmouseover = showHand;
// 绑定鼠标点击单价单元格的事件
priceTD.onclick = editPrice;
// 绑定删除小图标的点击事件
var img = cells[4].firstChild;
if (img && img.tagName == "IMG") {
img.onclick = delFruit;
}
}
function addFruit() {
var fname = document.getElementById("fname").value;
var price = parseInt(document.getElementById("price").value);
var fcount = parseInt(document.getElementById("fcount").value);
var xj = price * fcount;
var fruitTbl = document.getElementById("tbl_fruit");
var tr = fruitTbl.insertRow(fruitTbl.rows.length - 1);
var fnameTD = tr.insertCell();
fnameTD.innerText = fname;
var priceTD = tr.insertCell();
priceTD.innerText = price;
var fcountTD = tr.insertCell();
fcountTD.innerText = fcount;
var xjTD = tr.insertCell();
xjTD.innerText = xj;
var imgTD = tr.insertCell();
imgTD.innerText = "";
updateZJ();
trBindEvent(tr);
}
function delFruit() {
if (event && event.srcElement && event.srcElement.tagName == "IMG") {
if (window.confirm("是否确认删除当前库存记录")) {
var img = event.srcElement;
var tr = img.parentElement.parentElement;
var fruitTbl = document.getElementById("tbl_fruit");
fruitTbl.deleteRow(tr.rowIndex);
updateZJ();
}
}
}
// 当鼠标悬浮时,显示背景颜色!
function showBGColor() {
if (event && event.srcElement && event.srcElement.tagName == 'TD') {
var td = event.srcElement;
var tr = td.parentElement;
tr.style.backgroundColor = 'skyblue';
// 获取表格中的所有单元格
var tds = tr.cells;
for (var i = 0; i < tds.length; i++) {
tds[i].style.color = 'white';
}
}
}
// 当鼠标离开时,恢复背景颜色!
function clearBGColor() {
if (event && event.srcElement && event.srcElement.tagName == 'TD') {
var td = event.srcElement;
var tr = td.parentElement;
tr.style.backgroundColor = 'transparent';
var tds = tr.cells;
for (var i = 0; i < tds.length; i++) {
tds[i].style.color = 'pink';
}
}
}
// 当鼠标在单价单元格时,显示手势
function showHand() {
if (event && event.srcElement && event.srcElement.tagName == 'TD') {
var td = event.srcElement;
td.style.cursor = 'pointer';
}
}
// 当鼠标点击单价单元格进行价格编辑
function editPrice() {
if (event && event.srcElement && event.srcElement.tagName == 'TD') {
var priceTD = event.srcElement;
// 判断当前priceTD有子节点,而且第一个子节点是文本节点,TypeNode 对应为3,ElementNode 对应为1
if (priceTD.firstChild && priceTD.firstChild.nodeType == 3) {
// innerText 表示设置或者获取当前节点的内部文本
var oldPrice = priceTD.innerText;
// innerHTML表示设置当前内部节点的HTML
priceTD.innerHTML = "";
var input = priceTD.firstChild;
if (input.tagName == 'INPUT') {
input.value = oldPrice;
// 选中输入框内部的文本
input.select();
// 绑定输入框失去焦点事件,失去焦点,更新单价!
input.onblur = updatePrice;
// 在输入框上绑定键盘按下的事件,此处需要保证按下的是数字
input.onkeydown = ckInput;
}
}
}
}
// 检验键盘按下的事件
function ckInput() {
var kc = event.KeyCode;
if (!((kc >= 48 && kc <= 57) || kc == 8 || kc == 13)) {
event.returnValue = false;
}
if (kc == 13) {
event.srcElement.blur();
}
}
function updatePrice() {
if (event && event.srcElement && evnet.srcElement.tagName == 'INPUT') {
var input = event.srcElement;
var newPrice = input.value;
// input节点的父节点是td
var priceTD = input.parentElement;
priceTD.innerText = newPrice;
// 更新当前内部的小计这一个格子的值
// priceTD。parentElement td的父元素是tr
updateXJ(priceTD.parentElement);
}
}
function updateXJ(tr) {
if (tr && tr.tagName == 'TR') {
var tds = tr.cells;
var price = tds[1].innerText;
var count = tds[2].innerText;
// innerText获取到的值类型是字符串类型,因此进行数据转换,进行数学运算
var xj = parseInt(price) * parseInt(count);
td[3].innerText = xj;
// 更新总计
updateZJ();
}
}
// 更新总计
function updateZJ() {
var fruitTbl = document.getElementById('tbl_fruit');
var rows = fruitTbl.rows;
var sum = 0;
for (var i = 1; i < rows.length - 1; i++) {
var tr = rows[i];
var xj = parseInt(tr.cells[3].innerText);
sum = sum + xj;
}
rows[rows.length - 1].cells[1].innerText = sum;
}
四、使用HTML表单收集数据
1、什么是表单
在项目开发过程中,凡是需要用户填写的信息都需要用到表单。
2、form标签
在HTML中我们使用form标签来定义一个表单。而对于form标签来说有两个最重要的属性:action和method。
action属性
用户在表单里填写的信息需要发送到服务器端,对于Java项目来说就是交给Java代码来处理。那么在页面上我们就必须正确填写服务器端的能够接收表单数据的地址。
这个地址要写在form标签的action属性中。但是现在暂时我们还没有服务器端环境,所以先借用一个HTML页面来当作服务器端地址使用。
method属性
『method』这个单词的意思是『方式、方法』,在form标签中method属性用来定义提交表单的*『请求方式』*。method属性只有两个可选值:get或post,没有极特殊情况的话使用post即可。
什么是*『请求方式』*?
浏览器和服务器之间在互相通信时有大量的**『数据』**需要传输。但是不论是浏览器还是服务器都有很多不同厂商提供的不同产品。
常见的浏览器有:
- Chrome
- Firefox
- Safari
- Opera
- Edge
常见的Java服务器有:
- Tomcat
- Weblogic
- WebSphere
- Glassfish
- Jetty
这么多不同厂商各自开发的应用程序怎么能保证它们彼此之间传输的**『数据』**能够被对方正确理解呢?
很简单,我们给这些数据设定*『格式』*,发送端按照格式发送数据,接收端按照格式解析数据,这样就能够实现数据的**『跨平台传输』**了。
而这里定义的**『数据格式』就是应用程序之间的『通信协议』**。
在JavaSE阶段的网络编程章节我们接触过TCP/IP、UDP这样的协议,而我们现在使用的**『HTTP协议』**的底层就是TCP/IP协议。
HTTP1.1中共定义了八种请求方式:
- GET
- POST
- PUT
- DELETE
- HEAD
- CONNECT
- OPTIONS
- TRACE
但是在HTML标签中,点击超链接是GET方式的请求,提交一个表单可以通过form标签的method属性指定GET或POST请求,其他请求方式无法通过HTML标签实现。除了GET、POST之外的其他请求方式暂时我们不需要涉及(到我们学习SpringMVC时会用到PUT和DELETE)。至于GET请求和POST请求的区别我们会在讲HTTP协议的时候详细介绍,现在大家可以从表面现象来观察一下。
3、name和value
在用户使用一个软件系统时,需要一次性提交很多数据是非常正常的现象。我们肯定不能要求用户一个数据一个数据的提交,而肯定是所有数据填好后一起提交。那就带来一个问题,服务器怎么从众多数据中识别出来收货人、所在地区、详细地址、手机号码……?
很简单,给每个数据都起一个『名字』,发送数据时用**『名字』携带对应的数据,接收数据时通过『名字』**获取对应的数据。
在各个具体的表单标签中,我们通过**『name属性』来给数据起『名字』,通过『value属性』来保存要发送给服务器的『值』**。
但是名字和值之间既有可能是*『一个名字对应一个值』*,也有可能是*『一个名字对应多个值』*。
这么看来这样的关系很像我们Java中的Map,而事实上在服务器端就是使用Map类型来接收请求参数的。具体的是类型是:Map
name属性就是Map的键,value属性就是Map的值。
有了上面介绍的基础知识,下面我们就可以来看具体的表单标签了。
4、单行文本框
个性签名:
显示效果
5、密码框
代码
密码:
显示效果
6、单选框
代码
你最喜欢的季节是:
春天
夏天
秋天
冬天
你最喜欢的动物是:
路虎
宝马
捷豹
效果
说明
- name属性相同的radio为一组,组内互斥
- 当用户选择了一个radio并提交表单,这个radio的name属性和value属性组成一个键值对发送给服务器
- 设置checked="checked"属性设置默认被选中的radio
7、多选框
代码
你最喜欢的球队是:
巴西
德国
法国
中国
意大利
8、下拉列表
代码
你喜欢的运动是:
效果
说明
- 下拉列表用到了两种标签,其中select标签用来定义下拉列表,而option标签设置列表项。
- name属性在select标签中设置。
- value属性在option标签中设置。
- option标签的标签体是显示出来给用户看的,提交到服务器的是value属性的值。
- 通过在option标签中设置selected="selected"属性实现默认选中的效果。
9、按钮
代码
效果
说明
类型 | 功能 |
---|---|
普通按钮 | 点击后无效果,需要通过JavaScript绑定单击响应函数 |
重置按钮 | 点击后将表单内的所有表单项都恢复为默认值 |
提交按钮 | 点击后提交表单 |
10、表单隐藏域
代码
说明
通过表单隐藏域设置的表单项不会显示到页面上,用户看不到。但是提交表单时会一起被提交。用来设置一些需要和表单一起提交但是不希望用户看到的数据,例如:用户id等等。
11、多行文本框
代码
自我介绍:
效果
说明
textarea没有value属性,如果要设置默认值需要写在开始和结束标签之间。
五、CSS的简单应用
1、设置CSS样式的三种方式
在HTML标签内设置
仅对当前标签有效
在head标签内设置
对当前页面有效
Title
引入外部CSS样式文件
创建CSS文件
编辑CSS文件
.two {
border: 1px solid black;
width: 100px;
height: 100px;
background-color: yellow;
margin-top: 5px;
}
引入外部CSS文件
在需要使用这个CSS文件的HTML页面的head标签内加入:
于是下面HTML代码的显示效果是:
2、CSS代码语法
- CSS样式由选择器和声明组成,而声明又由属性和值组成。
- 属性和值之间用冒号隔开。
- 多条声明之间用分号隔开。
- 使用/* ... */声明注释。
3、CSS选择器
标签选择器
HTML代码:
Hello, this is a p tag.
Hello, this is a p tag.
Hello, this is a p tag.
Hello, this is a p tag.
Hello, this is a p tag.
CSS代码:
p {
color: blue;
font-weight: bold;
}
id选择器
HTML代码:
Hello, this is a p tag.
Hello, this is a p tag.
Hello, this is a p tag.
Hello, this is a p tag.
Hello, this is a p tag.
CSS代码:
#special {
font-size: 20px;
background-color: aqua;
}
类选择器
HTML代码:
CSS代码:
.one {
border: 1px solid black;
width: 100px;
height: 100px;
background-color: lightgreen;
margin-top: 5px;
}
4、定位与浮动
这里不做太多的简介!
简单来说定位与浮动的关系:
- relative:定位相对于float进行调试!
- absoulte:定位与top、left进行调试!
05、JavaScript
一、JavaScript简介
参考文章:
https://www.cnblogs.com/zhaostudy/p/16733510.html
https://www.cnblogs.com/zhaostudy/p/16051571.html
https://www.cnblogs.com/zhaostudy/p/15883773.html
1、起源
在1995年时,由Netscape公司的Brendan Eich,在网景导航者浏览器上首次设计实现而成。Netscape在最初将其脚本语言命名为LiveScript,因为Netscape与Sun合作,网景公司管理层希望它外观看起来像Java,因此取名为JavaScript。
2、特性
脚本语言
JavaScript是一种解释型的脚本语言。不同于C、C++、Java等语言先编译后执行, JavaScript不会产生编译出来的字节码文件,而是在程序的运行过程中对源文件逐行进行解释。
基于对象
JavaScript是一种基于对象的脚本语言,它不仅可以创建对象,也能使用现有的对象。但是面向对象的三大特性:『封装』、『继承』、『多态』中,JavaScript能够实现封装,可以模拟继承,不支持多态,所以它不是一门面向对象的编程语言。
弱类型
JavaScript中也有明确的数据类型,但是声明一个变量后它可以接收任何类型的数据,并且会在程序执行过程中根据上下文自动转换类型。
事件驱动
JavaScript是一种采用事件驱动的脚本语言,它不需要经过Web服务器就可以对用户的输入做出响应。
跨平台性
JavaScript脚本语言不依赖于操作系统,仅需要浏览器的支持。因此一个JavaScript脚本在编写后可以带到任意机器上使用,前提是机器上的浏览器支持JavaScript脚本语言。目前JavaScript已被大多数的浏览器所支持。
二、JS-HelloWorld
1、功能效果图
2、代码实现
HelloWorld
三、JavaScript基本语法
1、JavaScript代码嵌入方式
HTML文档内
- JavaScript代码要写在script标签内
- script标签可以写在文档内的任意位置
- 为了能够方便查询或操作HTML标签(元素)script标签可以写在body标签后面
可以参考简化版的HelloWorld
引入外部JavaScript文档
在script标签内通过src属性指定外部xxx.js文件的路径即可。但是要注意以下两点:
- 引用外部JavaScript文件的script标签里面不能写JavaScript代码
- 先引入,再使用
- script标签不能写成单标签
引入方式如下:
2、声明和使用变量
JavaScript数据类型
基本数据类型
-
数值型:JavaScript不区分整数、小数
-
字符串:JavaScript不区分字符、字符串;单引号、双引号意思一样。
-
布尔型:true、false
在JavaScript中,其他类型和布尔类型的自动转换。
- true:非零的数值,非空字符串,非空对象
- false:零,空字符串,null,undefined
例如:"false"放在if判断中
// "false"是一个非空字符串,直接放在if判断中会被当作『真』处理
if("false"){
alert("true");
}else{
alert("false");
}
- 引用类型
- 所有new出来的对象
- 用[]声明的数组
- 用{}声明的对象
变量
-
关键字:var
-
数据类型:JavaScript变量可以接收任意类型的数据
-
标识符:严格区分大小写
-
变量使用规则
-
如果使用了一个没有声明的变量,那么会在运行时报错
Uncaught ReferenceError: b is not defined
-
如果声明一个变量没有初始化,那么这个变量的值就是undefined
-
3、函数
内置函数
内置函数:系统已经声明好了可以直接使用的函数。
弹出警告框
alert("警告框内容");
弹出确认框
用户点击『确定』返回true,点击『取消』返回false
var result = confirm("老板,你真的不加个钟吗?");
if(result) {
console.log("老板点了确定,表示要加钟");
}else{
console.log("老板点了确定,表示不加钟");
}
在控制台打印日志
console.log("日志内容");
声明函数
写法1:
function sum(a, b) {
return a+b;
}
写法2:
var total = function() {
return a+b;
};
写法2可以这样解读:声明一个函数,相当于创建了一个『函数对象』,将这个对象的『引用』赋值给变量total。最后加的分号不是给函数声明加的,而是给整体的赋值语句加的分号。
调用函数
JavaScript中函数本身就是一种对象,函数名就是这个**『对象』的『引用』**。而调用函数的格式是:函数引用()。
function sum(a, b) {
return a+b;
}
var result = sum(2, 3);
console.log("result="+result);
或:
var total = function() {
return a+b;
}
var totalResult = total(3,6);
console.log("totalResult="+totalResult);
4、对象
JavaScript中没有『类』的概念,对于系统内置的对象可以直接创建使用。
使用new关键字创建对象
// 创建对象
var obj01 = new Object();
// 给对象设置属性和属性值
obj01.stuName = "tom";
obj01.stuAge = 20;
obj01.stuSubject = "java";
// 在控制台输出对象
console.log(obj01);
使用{}创建对象
// 创建对象
var obj02 = {
"soldierName":"john",
"soldierAge":35,
"soldierWeapon":"gun"
};
// 在控制台输出对象
console.log(obj02);
给对象设置函数属性
// 创建对象
var obj01 = new Object();
// 给对象设置属性和属性值
obj01.stuName = "tom";
obj01.stuAge = 20;
obj01.stuSubject = "java";
obj01.study = function() {
console.log(this.stuName + " is studying");
};
// 在控制台输出对象
console.log(obj01);
// 调用函数
obj01.study();
或:
// 创建对象
var obj02 = {
"soldierName":"john",
"soldierAge":35,
"soldierWeapon":"gun",
"soldierShoot":function(){
console.log(this.soldierName + " is using " + this.soldierWeapon);
}
};
// 在控制台输出对象
console.log(obj02);
// 调用函数
obj02.soldierShoot();
this关键字
this关键字只有两种情况:
- 在函数外面:this关键字指向window对象(代表当前浏览器窗口)
- 在函数里面:this关键字指向调用函数的对象
// 直接打印this
console.log(this);
// 函数中的this
// 1.声明函数
function getName() {
console.log(this.name);
}
// 2.创建对象
var obj01 = {
"name":"tom",
"getName":getName
};
var obj02 = {
"name":"jerry",
"getName":getName
};
// 3.调用函数
obj01.getName();
obj02.getName();
5、数组
使用new关键字创建数组
// 1.创建数组对象
var arr01 = new Array();
// 2.压入数据
arr01.push("apple");
arr01.push("orange");
arr01.push("banana");
arr01.push("grape");
// 3.遍历数组
for (var i = 0; i < arr01.length; i++) {
console.log(arr01[i]);
}
// 4.数组元素反序
arr01.reverse();
for (var i = 0; i < arr01.length; i++) {
console.log(arr01[i]);
}
// 5.数组元素拼接成字符串
var arrStr = arr01.join(",");
console.log(arrStr);
// 6.字符串拆分成数组
var arr02 = arrStr.split(",");
for (var i = 0; i < arr02.length; i++) {
console.log(arr02[i]);
}
// 7.弹出数组中最后一个元素
var ele = arr01.pop();
console.log(ele);
使用[]创建数组
// 8.使用[]创建数组
var arr03 = ["cat","dog","tiger"];
console.log(arr03);
6、JSON
JSON格式的用途
在开发中凡是涉及到*『跨平台数据传输』*,JSON格式一定是首选。
JSON格式的说明
- JSON数据两端要么是*{}*,要么是**[]**
- **{}**定义JSON对象
- **[]**定义JSON数组
- JSON对象的格式是:
{key:value,key:value,...,key:value}
- JOSN数组的格式是:
[value,value,...,value]
- key的类型固定是字符串
- value的类型可以是:
- 基本数据类型
- 引用类型:JSON对象或JSON数组
正因为JSON格式中value部分还可以继续使用JSON对象或JSON数组,所以JSON格式是可以**『多层嵌套』**的,所以JSON格式不论多么复杂的数据类型都可以表达。
{
"stuId":556,
"stuName":"carl",
"school":{
"schoolId":339,
"schoolName":"atguigu"
},
"subjectList":[
{
"subjectName":"java",
"subjectScore":50
},
{
"subjectName":"PHP",
"subjectScore":35
},
{
"subjectName":"python",
"subjectScore":24
}
],
"teacherMap":{
"aaa":{
"teacherName":"zhangsan",
"teacherAge":20
},
"bbb":{
"teacherName":"zhangsanfeng",
"teacherAge":108
},
"ccc":{
"teacherName":"zhangwuji",
"teacherAge":25
}
}
}
JSON对象和JSON字符串互转
JSON对象转JSON字符串
var jsonObj = {"stuName":"tom","stuAge":20};
var jsonStr = JSON.stringify(jsonObj);
console.log(typeof jsonObj); // object
console.log(typeof jsonStr); // string
JSON字符串转JSON对象
jsonObj = JSON.parse(jsonStr);
console.log(jsonObj); // {stuName: "tom", stuAge: 20}
四、DOM
1、概念
名词解释
DOM是Document Object Model的缩写,意思是*『文档对象模型』*——将HTML文档抽象成模型,再封装成对象方便用程序操作。
这是一种非常常用的编程思想:将现实世界的事物抽象成模型,这样就非常容易使用对象来量化的描述现实事物,从而把生活中的问题转化成一个程序问题,最终实现用应用软件协助解决现实问题。而在这其中**『模型』**就是那个连通现实世界和代码世界的桥梁。
DOM树
浏览器把HTML文档从服务器上下载下来之后就开始按照**『从上到下』的顺序『读取HTML标签』。每一个标签都会被封装成一个『对象』**。
而第一个读取到的肯定是根标签html,然后是它的子标签head,再然后是head标签里的子标签……所以从html标签开始,整个文档中的所有标签都会根据它们之间的**『父子关系』被放到一个『树形结构』**的对象中。
这个包含了所有标签对象的整个树形结构对象就是JavaScript中的一个可以直接使用的内置对象:document。
例如,下面的标签结构:
会被解析为:
2、具体概念
各个组成部分的类型
整个文档中的一切都可以看做Node。各个具体组成部分的具体类型可以看做Node类型的子类。
其实严格来说,JavaScript并不支持真正意义上的『继承』,这里我们借用Java中的『继承』概念,从逻辑上来帮助我们理解各个类型之间的关系。
组成部分 | 节点类型 | 具体类型 |
---|---|---|
整个文档 | 文档节点 | Document |
HTML标签 | 元素节点 | Element |
HTML标签内的文本 | 文本节点 | Text |
HTML标签内的属性 | 属性节点 | Attr |
注释 | 注释节点 | Comment |
父子关系
先辈后代关系
3、DOM操作
由于实际开发时基本上都是使用JavaScript的各种框架来操作,而框架中的操作方式和我们现在看到的原生操作完全不同,所以下面罗列的API仅供参考,不做要求。
在整个文档范围内查询元素节点
功能 | API | 返回值 |
---|---|---|
根据id值查询 | document.getElementById(“id值”) | 一个具体的元素节 |
根据标签名查询 | document.getElementsByTagName(“标签名”) | 元素节点数组 |
根据name属性值查询 | document.getElementsByName(“name值”) | 元素节点数组 |
在具体元素节点范围内查找子节点
功能 | API | 返回值 |
---|---|---|
查找全部子节点 | element.childNodes 【W3C考虑换行,IE≤8不考虑】 | 节点数组 |
查找第一个子节点 | element.firstChild 【W3C考虑换行,IE≤8不考虑】 | 节点对象 |
查找最后一个子节点 | element.lastChild 【W3C考虑换行,IE≤8不考虑】 | 节点对象 |
查找指定元素节点的父节点
功能 | API | 返回值 |
---|---|---|
查找指定元素节点的父节点 | element.parentNode | 节点对象 |
查找指定元素节点的兄弟节点
功能 | API | 返回值 |
---|---|---|
查找前一个兄弟节点 | node.previousSibling 【W3C考虑换行,IE≤8不考虑】 | 节点对象 |
查找后一个兄弟节点 | node.nextSibling 【W3C考虑换行,IE≤8不考虑】 | 节点对象 |
属性操作
需求 | 操作方式 |
---|---|
读取属性值 | 元素对象.属性名 |
修改属性值 | 元素对象.属性名=新的属性值 |
文本操作
需求 | 操作方式 |
---|---|
读取文本值 | element.firstChild.nodeValue |
修改文本值 | element.firstChild.nodeValue=新文本值 |
DOM增删改操作
API | 功能 |
---|---|
document.createElement(“标签名”) | 创建元素节点并返回,但不会自动添加到文档中 |
document.createTextNode(“文本值”) | 创建文本节点并返回,但不会自动添加到文档中 |
element.appendChild(ele) | 将ele添加到element所有子节点后面 |
parentEle.insertBefore(newEle,targetEle) | 将newEle插入到targetEle前面 |
parentEle.replaceChild(newEle, oldEle) | 用新节点替换原有的旧子节点 |
parentEle.removeChild(childNode) | 删除指定的子节点 |
element.innerHTML | 读写HTML代码 |
五、 JavaScript事件驱动
下面是简化的代码:
document.getElementById("eventArea").onmousemove = function (event){
document.getElementById("showData").innerText = event.clientX + " " + event.clientY;
};
06、Vue.js
一、Vue.js简介
1、框架
任何编程语言在最初的时候都是没有框架的,后来随着在实际开发过程中不断总结*『经验』*,积累*『最佳实践』*,慢慢的人们发现很多**『特定场景』下的『特定问题』总是可以『套用固定解决方案』**。
于是有人把成熟的**『固定解决方案』收集起来,整合在一起,就成了『框架』**。
在使用框架的过程中,我们往往只需要告诉框架*『做什么(声明)』*,而不需要关心框架*『怎么做(编程)』*。
对于Java程序来说,我们使用框架就是导入那些封装了**『固定解决方案』的jar包,然后通过『配置文件』**告诉框架做什么,就能够大大简化编码,提高开发效率。我们使用过的junit其实就是一款单元测试框架。
而对于JavaScript程序来说,我们使用框架就是导入那些封装了**『固定解决方案』的『js文件』**,然后在框架的基础上编码。
用洗衣服来类比框架:
典型应用场景:洗衣服
输入数据:衣服、洗衣液、水
不使用框架:手洗
使用框架:使用洗衣机,对人来说,只需要按键,具体操作是洗衣机完成的。人只是告诉洗衣机做什么,具体的操作是洗衣机完成的。
实际开发中使用框架时,我们也主要是告诉框架要做什么,具体操作是框架完成的。
2、Vue.js
Vue.js的作者
在为AngularJS工作之后,Vue的作者尤雨溪开Vue.js。他声称自己的思路是提取Angular中自己喜欢的部分,构建出一款相当轻量的框架。
Vue最早发布于2014年2月。作者在Hacker News、Echo JS与 Reddit的JavaScript版块发布了最早的版本。一天之内,Vue 就登上了这三个网站的首页。
Vue是Github上最受欢迎的开源项目之一。同时,在JavaScript框架/函数库中, Vue所获得的星标数已超过React,并高于Backbone.js、Angular 2、jQuery等项目。
Vue.js的官网介绍
Vue (读音 /vjuː/,类似于view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链 (opens new window)以及各种支持类库 (opens new window)结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
官网地址:https://cn.vuejs.org/
二、准备Vue.js环境
1、开发中的最佳实践
『最佳实践』是实际开发中,针对特定问题提炼出来的最好的解决方案。把『最佳实践』抽取出来,封装到各自编程语言的程序包中,就是框架的基础。
- Java语言的程序包:jar包
- JavaScript语言的程序包:外部js文件
对于Java程序来说,框架=jar包+配置文件。对于Vue来说,导入Vue的外部js文件就能够使用Vue框架了。
2、Vue框架的js文件获取
官网提供的下载地址:https://cdn.jsdelivr.net/npm/vue/dist/vue.js
3、本地创建vue.js文件
第一步:在HBuilderX中创建工程
第二步:在工程目录下创建script目录用来存放vue.js文件
第三步:创建空vue.js文件
第四步:将官网提供的vue.js文件的内容复制粘贴到本地vue.js文件中
4、创建HTML文档并引入vue.js
三、Vue.js基本语法:声明式渲染
1、概念
声明式
**『声明式』是相对于『编程式』**而言的。
- 声明式:告诉框架做什么,具体操作由框架完成
- 编程式:自己编写代码完成具体操作
渲染
上图含义解释:
- 蓝色方框:HTML标签
- 红色圆形:动态、尚未确定的数据
- 蓝色圆形:经过程序运算以后,计算得到的具体的,可以直接在页面上显示的数据、
- 渲染:程序计算动态数据得到具体数据的过程
2、demo
HTML代码
{{message}}
vue代码
// 1.创建一个JSON对象,作为new Vue时要使用的参数
var argumentJson = {
// el用于指定Vue对象要关联的HTML元素。el就是element的缩写
// 通过id属性值指定HTML元素时,语法格式是:#id
"el":"#app",
// data属性设置了Vue对象中保存的数据
"data":{
"message":"Hello Vue!"
}
};
// 2.创建Vue对象,传入上面准备好的参数
var app = new Vue(argumentJson);
3、查看声明式渲染的响应式效果
通过验证Vue对象的『响应式』效果,我们看到Vue对象和页面上的HTML标签确实是始终保持着关联的关系,同时看到Vue在背后确实是做了大量的工作。
四、Vue.js基本语法:绑定元素属性
1、基本语法
v-bind:HTML标签的原始属性名
2、demo
HTML代码
{{vueValue}}
Vue代码
// 创建Vue对象,挂载#app这个div标签
var app = new Vue({
"el":"#app",
"data":{
"vueValue":"太阳当空照"
}
});
3、小结
本质上,v-bind:属性名="表达式"它们都是用Vue对象来渲染页面。只不过:
- 文本标签体:使用形式
- 属性:使用v-bind:属性名="表达式"形式
五、Vue.js基本语法:双向数据绑定
1、提出问题
而使用了双向绑定后,就可以实现:页面上数据被修改后,Vue对象中的数据属性也跟着被修改。
2、demo
HTML代码
{{vueValue}}
Vue代码
// 创建Vue对象,挂载#app这个div标签
var app = new Vue({
"el":"#app",
"data":{
"vueValue":"太阳当空照"
}
});
页面效果
p标签内的数据能够和文本框中的数据实现同步修改:
3、去除前后空格
:value可以省略
.trim修饰符
实际开发中,要考虑到用户在输入数据时,有可能会包含前后空格。而这些前后的空格对我们程序运行来说都是干扰因素,要去掉。在v-model后面加上.trim修饰符即可实现。
Vue会帮助我们在文本框失去焦点时自动去除前后空格。
六、Vue.js基本语法:条件渲染
根据Vue对象中,数据属性的值来判断是否对HTML页面内容进行渲染。
1、v-if
HTML代码
if
Vue代码
var app = new Vue({
"el":"#app",
"data":{
"flag":true
}
});
2、v-if和v-else
HTML代码
if/else
Vue代码
var app02 = new Vue({
"el":"#app02",
"data":{
"flag":true
}
});
3、v-show
HTML代码
v-show
Vue代码
var app03 = new Vue({
"el":"#app03",
"data":{
"flag":true
}
});
七、Vue.js基本语法:列表渲染
1、迭代一个简单的数组
HTML代码
- {{fruit}}
Vue代码
var app01 = new Vue({
"el":"#app01",
"data":{
"fruitList": [
"apple",
"banana",
"orange",
"grape",
"dragonfruit"
]
}
});
2、迭代一个对象数组
HTML代码
编号
姓名
年龄
专业
{{employee.empId}}
{{employee.empName}}
{{employee.empAge}}
{{employee.empSubject}}
Vue代码
var app = new Vue({
"el":"#app",
"data":{
"employeeList":[
{
"empId":11,
"empName":"tom",
"empAge":111,
"empSubject":"java"
},
{
"empId":22,
"empName":"jerry",
"empAge":222,
"empSubject":"php"
},
{
"empId":33,
"empName":"bob",
"empAge":333,
"empSubject":"python"
}
]
}
});
八、Vue.js基本语法:事件驱动
1、demo:字符串顺序反转
HTML代码
{{message}}
Vue代码
var app = new Vue({
"el":"#app",
"data":{
"message":"Hello Vue!"
},
"methods":{
"reverseMessage":function(){
this.message = this.message.split("").reverse().join("");
}
}
});
2、demo:获取鼠标移动时的坐标信息
HTML代码
{{position}}
Vue代码
var app = new Vue({
"el":"#app",
"data":{
"position":"暂时没有获取到鼠标的位置信息"
},
"methods":{
"recordPosition":function(event){
this.position = event.clientX + " " + event.clientY;
}
}
});
九、Vue.js基本语法:侦听属性
1、提出需求
尊姓:{{firstName}}
大名:{{lastName}}
尊姓:
大名:
全名:{{fullName}}
在上面代码的基础上,我们希望firstName或lastName属性发生变化时,修改fullName属性。此时需要对firstName或lastName属性进行*『侦听』*。
具体来说,所谓**『侦听』**就是对message属性进行监控,当firstName或lastName属性的值发生变化时,调用我们准备好的函数。
2、Vue代码
在watch属性中声明对firstName和lastName属性进行**『侦听』**的函数:
var app = new Vue({
"el":"#app",
"data":{
"firstName":"jim",
"lastName":"green",
"fullName":"jim green"
},
"watch":{
"firstName":function(inputValue){
this.fullName = inputValue + " " + this.lastName;
},
"lastName":function(inputValue){
this.fullName = this.firstName + " " + inputValue;
}
}
});
十、Vue.js基本语法:简化写法
1、v-bind的简化写法
正常写法:
简化以后:
2、v-on的简化写法
正常写法:
简化以后:
十一、练习
1、功能效果演示
2、任务拆解
- 第一步:显示表格
- 第二步:显示四个文本框
- 第三步:创建一个p标签用来显示用户在文本框中实时输入的内容
- 第四步:点击添加记录按钮实现记录的添加
3、第一步:显示表格
HTML标签
编号
姓名
年龄
专业
{{employee.empId}}
{{employee.empName}}
{{employee.empAge}}
{{employee.empSubject}}
Vue代码
var appTable = new Vue({
"el": "#appTable",
"data": {
"employeeList": [{
"empId": 1,
"empName": "tom",
"empAge": 11,
"empSubject": "java"
},
{
"empId": 2,
"empName": "jerry",
"empAge": 22,
"empSubject": "php"
},
{
"empId": 3,
"empName": "peter",
"empAge": 33,
"empSubject": "python"
}
]
}
});
4、第二步:显示四个文本框
HTML标签
编号:
姓名:
年龄:
专业:
Vue代码
var appDiv = new Vue({
"el":"#appDiv",
"data":{
// 初始值设置空字符串即可
"empId":"",
"empName":"",
"empAge":"",
"empSubject":""
}
});
测试是否正确的方式是:在控制台尝试修改Vue对象的数据属性值:
5、第三步:创建一个p标签
HTML标签:
编号:
姓名:
年龄:
专业:
{{empId}} {{empName}} {{empAge}} {{empSubject}}
6、第四步:点击添加记录按钮
第一小步:给按钮设置事件驱动
HTML标签
编号:
姓名:
年龄:
专业:
{{empId}} {{empName}} {{empAge}} {{empSubject}}
Vue代码
var appDiv = new Vue({
"el":"#appDiv",
"data":{
// 初始值设置空字符串即可
"empId":"",
"empName":"",
"empAge":"",
"empSubject":""
},
"methods":{
"addRecord":function(){
console.log("我点击了那个按钮……");
}
}
});
第二小步:打印一下文本框输入的数据
var appDiv = new Vue({
"el":"#appDiv",
"data":{
// 初始值设置空字符串即可
"empId":"",
"empName":"",
"empAge":"",
"empSubject":""
},
"methods":{
"addRecord":function(){
console.log("我点击了那个按钮……");
console.log(this.empId);
console.log(this.empName);
console.log(this.empAge);
console.log(this.empSubject);
}
}
});
第三小步:将收集到的数据添加到表格中
"addRecord":function(){
// 确认单击事件是否绑定成功
console.log("我点击了那个按钮……");
// 确认是否能够正确收集到文本框数据
console.log(this.empId);
console.log(this.empName);
console.log(this.empAge);
console.log(this.empSubject);
// 将收集到的文本框数据封装为一个对象
var employee = {
"empId":this.empId,
"empName":this.empName,
"empAge":this.empAge,
"empSubject":this.empSubject
};
// 将上面的对象压入表格数据的employeeList数组
appTable.employeeList.push(employee);
}
十二、Vue对象生命周期
1、概念
在我们各种语言的编程领域中,**『生命周期』**都是一个非常常见的概念。一个对象从创建、初始化、工作再到释放、清理和销毁,会经历很多环节的演变。比如我们在JavaSE阶段学习过线程的生命周期,今天学习Vue对象的生命周期,将来还要学习Servlet、Filter等Web组件的生命周期
2、Vue对象的生命周期
3、生命周期钩子函数
Vue允许我们在特定的生命周期环节中通过钩子函数来加入我们的代码。
{{message}}
new Vue({
"el":"#app",
"data":{
"message":"hello"
},
"methods":{
"changeValue":function(){
this.message = "new hello";
}
},
// 1.实例创建之前
"beforeCreate":function(){
console.log("beforeCreate:"+this.message);
},
// 2.实例创建完成
"created":function(){
console.log("created:"+this.message);
},
// 3.数据挂载前
"beforeMount":function(){
console.log("beforeMount:"+document.getElementById("content").innerText);
},
// 4.数据已经挂载
"mounted":function(){
console.log("mounted:"+document.getElementById("content").innerText);
},
// 5.数据更新前
"beforeUpdate":function(){
console.log("beforeUpdate:"+document.getElementById("content").innerText);
},
// 6.数据更新之后
"updated":function(){
console.log("updated:"+document.getElementById("content").innerText);
}
});
07、书城项目第一阶段
一、事件驱动补充
1、取消控件的默认行为
控件默认行为
- 点超链接会跳转页面
- 点表单提交按钮会提交表单
本来控件的默认行为是天经地义就该如此的,但是如果我们希望点击之后根据我们判断的结果再看是否要跳转,此时默认行为无脑跳转的做法就不符合我们的预期了。
取消方式
调用事件对象的**preventDefault()**方法。
超链接举例
HTML代码:
超链接
JavaScript代码:
document.getElementById("anchor").onclick = function() {
console.log("我点击了一个超链接");
event.preventDefault();
}
表单提交按钮举例
HTML代码:
JavaScript代码:
document.getElementById("submitBtn").onclick = function() {
console.log("我点击了一个表单提交按钮");
event.preventDefault();
}
2、阻止事件冒泡
图中的两个div,他们的HTML标签是:
点击里面的div同时也等于点击了外层的div,此时如果两个div上都绑定了单击响应函数那么就都会被触发:
document.getElementById("outterDiv").onclick = function() {
console.log("外层div的事件触发了");
}
document.getElementById("innerDiv").onclick = function() {
console.log("内层div的事件触发了");
}
所以事件冒泡就是一个事件会不断向父元素传递,直到window对象。
如果这不是我们想要的效果那么可以使用事件对象的**stopPropagation()**函数阻止。
document.getElementById("innerDiv").onclick = function() {
console.log("内层div的事件触发了");
event.stopPropagation();
}
3、Vue事件修饰符
对于事件修饰符,Vue官网的描述是:
在事件处理程序中调用
event.preventDefault()
或event.stopPropagation()
是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。
取消控件的默认行为
控件的默认行为指的是:
- 点击超链接跳转页面
- 点击表单提交按钮提交表单
实现这个需求使用的Vue事件修饰符是:.prevent
超链接
取消事件冒泡
实现这个需求使用的Vue事件修饰符是:.stop
二、正则表达式
1、从凤姐的择偶标准说起
本人对伴侣要求如下:
- 第一、必须为北京大学或清华大学硕士毕业生。必须本科硕士连读,中途无跳级,不留级,不转校。在外参加工作后再回校读书者免。
- 第二、必须为经济学专业毕业。非经济学专业毕业则必须精通经济学。或对经济学有浓厚的兴趣。
- 第三、必须具备国际视野,但是无长期定居国外甚至移民的打算。
- 第四、身高176--183左右。长得越帅越好。
- 第五、无生育史。过往所有女友均无因自身而致的堕胎史。
- 第六、东部户籍,即江、浙、沪三地户籍或黑龙江、广东、天津、山东、北京、吉林、辽宁等。
- 东北三省和内蒙古等地户籍,西南地区即重庆、贵州、云南、西藏和湖南、湖北等地籍贯者不予考虑。
- 第七、年龄25--28岁左右。即06届,07届,08届,09届毕业生。有一至两年的工作经验,06级毕业生需年龄在28岁左右,09级毕业生则需聪明过人。且具备丰富的社会实践经验。就职于国家机关,国有企事业单位者不愿考虑。但就职于中石油,中石化等世界顶尖型企业或银行者又比较喜欢。现自主创业者要商榷一番了。
2、标准在手,世界我有
模式验证
使用标准衡量一位具体的男士,返回一个布尔值,从而知道这位男士是否满足自己的标准——相当于我们使用正则表达式验证一个字符串是否满足规则。比如验证一个字符串是否是一个身份证号。
匹配读取
对全中国的男士应用这个标准,返回一个数组,遍历这个数组,可以得到所有符合标准的男士——相当于我们使用正则表达式获取一段文本中匹配的子字符串。比如将一篇文章中的电子邮件地址读取出来。
匹配替换
对全中国的男士应用这个标准,把其中已婚的变成未婚,这样凤姐就有机会了——相当于我们使用正则表达式替换所有匹配的部分。比如将一段文字中的”HelloWorld”替换为”HelloJava”。
花絮:
记者:封老师您好!由于您的名字『封捷』和『凤姐』谐音,同学们总是以此来调侃您,说您是尚硅谷『凤姐』,对此您有什么想说的吗?
封老师:太过分了!我咋能和人家比!
记者:呃……太意外了,您的意思是?
封老师:虽然过气了,但人家好歹也是网红呀!
3、正则表达式的概念
使用一段字符串定义的一个规则,用以检测某个字符串是否满足这个规则,或将目标字符串中满足规则的部分读取出来,又或者将目标字符串中满足标准的部分替换为其他字符串。所以正则表达式有三个主要用途:
- 模式验证
- 匹配读取
- 匹配替换
4、正则表达式零起步
创建正则表达式对象
使用两个斜杠
// 类似创建数组时可以使用[]、创建对象可以使用{}
var reg = /a/;
使用new关键字创建RegExp类型的对象
// 类似创建数组可以new Array()、创建对象可以使用new Object()
var reg = new RegExp("a");
正则表达式的组成
正则表达式本身也是一个字符串,它由两种字符组成:
- 普通字符,例如大、小写英文字母;数字等。
- 元字符:被系统赋予特殊含义的字符。例如:^表示以某个字符串开始,$表示以某个字符串结束。
正则表达式初体验
模式验证
注意:这里是使用正则表达式对象来调用方法。
// 创建一个最简单的正则表达式对象
var reg = /o/;
// 创建一个字符串对象作为目标字符串
var str = 'Hello World!';
// 调用正则表达式对象的test()方法验证目标字符串是否满足我们指定的这个模式,返回结果true
console.log("/o/.test('Hello World!')="+reg.test(str));
匹配读取
注意:这里是使用字符串对象来调用方法。
// 在目标字符串中查找匹配的字符,返回匹配结果组成的数组
var resultArr = str.match(reg);
// 数组长度为1
console.log("resultArr.length="+resultArr.length);
// 数组内容是o
console.log("resultArr[0]="+resultArr[0]);
替换
注意:这里是使用字符串对象来调用方法。
var newStr = str.replace(reg,'@');
// 只有第一个o被替换了,说明我们这个正则表达式只能匹配第一个满足的字符串
console.log("str.replace(reg)="+newStr);//Hell@ World!
// 原字符串并没有变化,只是返回了一个新字符串
console.log("str="+str);//str=Hello World!
匹配方式
全文查找
如果不使用g对正则表达式对象进行修饰,则使用正则表达式进行查找时,仅返回第一个匹配;使用g后,返回所有匹配。
// 目标字符串
var targetStr = 'Hello World!';
// 没有使用全局匹配的正则表达式
var reg = /[A-Z]/;
// 获取全部匹配
var resultArr = targetStr.match(reg);
// 数组长度为1
console.log("resultArr.length="+resultArr.length);
// 遍历数组,发现只能得到'H'
for(var i = 0; i < resultArr.length; i++){
console.log("resultArr["+i+"]="+resultArr[i]);
}
对比代码:
// 目标字符串
var targetStr = 'Hello World!';
// 使用了全局匹配的正则表达式
var reg = /[A-Z]/g;
// 获取全部匹配
var resultArr = targetStr.match(reg);
// 数组长度为2
console.log("resultArr.length="+resultArr.length);
// 遍历数组,发现可以获取到“H”和“W”
for(var i = 0; i < resultArr.length; i++){
console.log("resultArr["+i+"]="+resultArr[i]);
}
忽略大小写
//目标字符串
var targetStr = 'Hello WORLD!';
//没有使用忽略大小写的正则表达式
var reg = /o/g;
//获取全部匹配
var resultArr = targetStr.match(reg);
//数组长度为1
console.log("resultArr.length="+resultArr.length);
//遍历数组,仅得到'o'
for(var i = 0; i < resultArr.length; i++){
console.log("resultArr["+i+"]="+resultArr[i]);
}
对比代码:
//目标字符串
var targetStr = 'Hello WORLD!';
//使用了忽略大小写的正则表达式
var reg = /o/gi;
//获取全部匹配
var resultArr = targetStr.match(reg);
//数组长度为2
console.log("resultArr.length="+resultArr.length);
//遍历数组,得到'o'和'O'
for(var i = 0; i < resultArr.length; i++){
console.log("resultArr["+i+"]="+resultArr[i]);
}
多行查找
不使用多行查找模式,目标字符串中不管有没有换行符都会被当作一行。
//目标字符串1
var targetStr01 = 'Hello\nWorld!';
//目标字符串2
var targetStr02 = 'Hello';
//匹配以'Hello'结尾的正则表达式,没有使用多行匹配
var reg = /Hello$/;
console.log(reg.test(targetStr01));//false
console.log(reg.test(targetStr02));//true
对比代码:
//目标字符串1
var targetStr01 = 'Hello\nWorld!';
//目标字符串2
var targetStr02 = 'Hello';
//匹配以'Hello'结尾的正则表达式,使用了多行匹配
var reg = /Hello$/m;
console.log(reg.test(targetStr01));//true
console.log(reg.test(targetStr02));//true
5、元字符
概念
在正则表达式中被赋予特殊含义的字符,不能被直接当做普通字符使用。如果要匹配元字符本身,需要对元字符进行转义,转义的方式是在元字符前面加上“\”,例如:^
常用元字符
代码 | 说明 |
---|---|
. | 匹配除换行字符以外的任意字符。 |
\w | 匹配字母或数字或下划线等价于[a-zA-Z0-9_] |
\W | 匹配任何非单词字符。等价于[^A-Za-z0-9_] |
\s | 匹配任意的空白符,包括空格、制表符、换页符等等。等价于[\f\n\r\t\v]。 |
\S | 匹配任何非空白字符。等价于[^\f\n\r\t\v]。 |
\d | 匹配数字。等价于[0-9]。 |
\D | 匹配一个非数字字符。等价于[^0-9] |
\b | 匹配单词的开始或结束 |
^ | 匹配字符串的开始,但在[]中使用表示取反 |
$ | 匹配字符串的结束 |
例1
var str = 'one two three four';
// 匹配全部空格
var reg = /\s/g;
// 将空格替换为@
var newStr = str.replace(reg,'@'); // one@two@three@four
console.log("newStr="+newStr);
例2
var str = '今年是2014年';
// 匹配至少一个数字
var reg = /\d+/g;
str = str.replace(reg,'abcd');
console.log('str='+str); // 今年是abcd年
例3
var str01 = 'I love Java';
var str02 = 'Java love me';
// 匹配以Java开头
var reg = /^Java/g;
console.log('reg.test(str01)='+reg.test(str01)); // flase
console.log("
");
console.log('reg.test(str02)='+reg.test(str02)); // true
例4
var str01 = 'I love Java';
var str02 = 'Java love me';
// 匹配以Java结尾
var reg = /Java$/g;
console.log('reg.test(str01)='+reg.test(str01)); // true
console.log("
");
console.log('reg.test(str02)='+reg.test(str02)); // flase
6、字符集合
语法格式 | 示例 | 说明 |
---|---|---|
[字符列表] | 正则表达式:[abc] 含义:目标字符串包含abc中的任何一个字符 目标字符串:plain 是否匹配:是 原因:plain中的“a”在列表“abc”中 | 目标字符串中任何一个字符出现在字符列表中就算匹配。 |
[^字符列表] | [^abc] 含义:目标字符串包含abc以外的任何一个字符 目标字符串:plain 是否匹配:是 原因:plain中包含“p”、“l”、“i”、“n” | 匹配字符列表中未包含的任意字符。 |
[字符范围] | 正则表达式:[a-z] 含义:所有小写英文字符组成的字符列表 正则表达式:[A-Z] 含义:所有大写英文字符组成的字符列表 | 匹配指定范围内的任意字符。 |
var str01 = 'Hello World';
var str02 = 'I am Tom';
//匹配abc中的任何一个
var reg = /[abc]/g;
console.log('reg.test(str01)='+reg.test(str01));//flase
console.log('reg.test(str02)='+reg.test(str02));//true
7、重复
代码 | 说明 |
---|---|
* | 重复零次或多次 |
+ | 重复一次或多次 |
? | 重复零次或一次 |
{n} | 重复n次 |
{n,} | 重复n次或多次 |
{n,m} | 重复n到m次 |
console.log("/[a]{3}/.test('aa')="+/[a]{3}/g.test('aa')); // flase
console.log("/[a]{3}/.test('aaa')="+/[a]{3}/g.test('aaa')); // true
console.log("/[a]{3}/.test('aaaa')="+/[a]{3}/g.test('aaaa')); // true
8、在正则表达式中表达『或者』
使用符号:|
// 目标字符串
var str01 = 'Hello World!';
var str02 = 'I love Java';
// 匹配'World'或'Java'
var reg = /World|Java/g;
console.log("str01.match(reg)[0]="+str01.match(reg)[0]);//World
console.log("str02.match(reg)[0]="+str02.match(reg)[0]);//Java
9、常用正则表达式
需求 | 正则表达式 |
---|---|
用户名 | /^[a-zA-Z_][a-zA-Z_-0-9]{5,9}$/ |
密码 | /^[a-zA-Z0-9_-@#&*]{6,12}$/ |
前后空格 | /^\s+\ |
电子邮箱 | /^[a-zA-Z0-9_.-]+@([a-zA-Z0-9-]+[.]{1})+[a-zA-Z]+$/ |
三、第一阶段要实现的功能
01、准备工作
创建目录后,把一整套现成的前端页面复制到新建的目录下,然后用HBuilderX打开这个目录。然后把vue.js文件复制到script目录下。
02、登录页面的表单验证
规则设定
- 用户名非空
- 密码非空
在login.html页面中加入Vue的环境