插曲
之前已发布了一次了。在编写和发布的过程中一直有一个BUG困扰着我。最后被我找到了,只能暂时避开这个BUG重新发布一篇了。之前那篇就被我删掉了,浏览和收藏的也没了。
那个问题我也记录下来了:https://blog.51cto.com/steed/2071264
Web的三个层次
网页设计思路是把网页分成三个层次,即:结构层(HTML)、表示层(CSS)、行为层(Javascript)。
形象的比喻,先是HTML捏了一个人,然后CSS则是给人穿上衣服,最后通过JS让人动起来。
Web服务的本质
对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端。用户向服务器发送一个请求。然后服务器响应,将数据和格式发回给客户端,然后断开这个连接。客户端收到返回的数据后,通过浏览器将数据按照一定的格式呈现出来。整个过程就是一个socket的短连接。
下面是一个服务端的python代码,实现一个简单的Hello World:
import socket
def handle_request(conn):
data = conn.recv(1024) # 接收数据,随便收到啥我们都回复Hello World
conn.send('HTTP/1.1 200 OK\r\n\r\n'.encode('utf-8')) # 这是什么暂时不需要知道,客户端浏览器会处理
conn.send('Hello World'.encode('utf-8')) # 回复的内容,就是网页的内容
def main():
# 先起一个socket服务端
server = socket.socket()
server.bind(('localhost', 8000))
server.listen(5)
# 然后持续监听
while True:
conn, addr = server.accept() # 开启监听
handle_request(conn) # 将连接传递给handle_request函数处理
conn.close() # 关闭连接
if __name__ == '__main__':
main()
在本机启动上面的socket之后,直接使用浏览器作为客户端连接。在地址栏输入 http://127.0.0.1:8000/
或 http://localhost:8000/
之后,浏览器上就会显示服务端返回的内容了。
这里显示的内容比较low,实际应用中,要返回给客户端的网页内容比较大。而且除了数据,还会包括格式(html标签)。实际应用中会将所有的内容写成一个html文件,然后再返回数据的时候调用这个文件。
先写一个简单的带一点标签的html文件,index.html:
Hello World
51CTO
1
2
3
A
B
C
然后我们的socket不再发送简单的数据,而是读取文件,将文件中的数据发送给客户端。
在上面代码的基础上修改一下handle_request函数的内容:
def handle_request(conn):
data = conn.recv(1024) # 接收数据,随便收到啥我们都回复Hello World
conn.send('HTTP/1.1 200 OK\r\n\r\n'.encode('utf-8')) # 这是什么暂时不需要知道,客户端浏览器会处理
# conn.send('Hello World'.encode('utf-8')) # 回复的内容
# 读取html文件,将文件内容返回给客户端
with open('index.html' , encoding='utf-8') as file:
html = file.read()
conn.send(html.encode('utf-8'))
现在已经将html和我们的socket服务分离了,需要返回给客户端什么样的页面,我们只需要编辑修改我们的html文件即可。而我们的socket服务器代码则负责和客户端的数据交换。
之后学习Web暂时只需要关注html的部分就好了,直接使用浏览器打开本地的html文件就可以查看实现的效果。
html
使用pycharm直接创建一个html文件,内容如下(HTML5的模板):
Title
:这是一个声明,声明下面html的版本。这里是一个html5的声明。这个不是html标签,下面的都是。
:这是一个html标签,里面的 lang="en"
是标签内部的属性。一般html标签这么写就行了。这个属性也用不着。
:body标签,html的主体,后面详讲
最后补充一个
注释 :
标签的分类
主动闭合标签:大多数的标签都是这种形式。标签有两部分,比如上面的、
、,后面都有一个对应的、、来主动闭合这个标签。自闭合标签:像上面 head 中的 meta 标签,就是一个自闭合标签。这类标签比较少。另外也可以这样写,加上一个
/
符号,不影响浏览器的识别,但是可以直观的让人看明白各个标签已经闭合了。推荐加上表示闭合的/
。
head内标签
:指定页面的字符编码,否则中文可能会变成乱码。
还可以加一些其他标签,举例一些比较常用的,基本上都用处不大
:页面30秒自动刷新
:页面5秒后自动跳转,这种跳转用的少,因为不是动态的无法显示倒计时或进度条,学了JS可以用JS来实现跳转并且能显示倒计时。
:加关联字,给搜索引擎搜索用的。告诉搜索引擎搜索什么关键字可以搜索到你的网站。对我们用处不大。
:加网站描述,同样用处不大
:网站兼容模式的设置,就是告诉浏览器选择什么模式来打开网页,通过content的属性识别。以上代码IE = edge告诉IE使用最新的引擎渲染网页,chrome = 1则是告诉chrome可以激活Chrome Frame。
:指定网站的图标
还有更多的 标签,以及
body中的标签只要id正确,就是应用上对应的style样式了。
这样貌似看着更复杂了,但是body内的结果更加清晰了,而且这只是因为我们的web页面还不是太复杂。
另外如果多个标签的样式其实是一样的,但是id只能用一次,我们可以为一个样式定义多个id,就是这样,如此也解决的代码重用的问题:
Title
第一块
第二块
第三块
class选择器
因为id不能重复,上面的方式应用起来不方便。最常用的是这里的方式。
现在以 .class 来设置sytle,标签中只要设置对应项class属性,就会应用该样式。关键是class属性是可以重复使用的:
Title
第一块
第二块
第三块
标签选择器
就是标签选择器。以标签的名字来设置style,这样所有的标签都会应用这个样式:
Title
第一块
红色的内容
第二块
2.1
第三块
关联选择器
也可以理解为层级选择器,每一个层级关系之间用空格分隔。现在我们以 "div span" 来设置style。如此,所有div标签下的span标签就都会应用这个样式。
Title
第一块
第一模块的内容
第二块
第二模块的内容
第三块
第三模块的内容
另外,这里的层级也可以使用class,比如以 ".c1 spen" 来设置style:
Title
第一块
第一模块的内容
第二块
第二模块的内容
第三块
第三模块的内容
这样c2这个class下的pan就会应该到这个样式。
使用#id也是一样的道理。
组合选择器
和层级关系类似,组合之间用","逗号分隔。在id选择器后面的例子里,其实就是组合了。所以就不试了。
现在我们知道,不只是id,class和标签都可以用来组合。
另外,组合是一个或的关系,上面的层级是一个与的关系。
属性选择器
这里先用 input[type='text']
来举例,前面是一个选择器,后面中括号是判断属性,如果有这个属性,就应该改样式。
对于前半部分,同样可以使用 #id 或 .class 。
对于后半部分,我们还可以使用自定义的属性,比如下面例子用自定义了一个myattr属性,来应用了一个样式:
Title
css的优先级
我们可以在标签内设置有限级,还可以在head里设置优先级模板,按几个选择器的规则应用其中的样式。所有可能出现符合多个要求而会应用到多个要是的情况。这里就有了一个优先级的概念。
对于不重复的样式,要么会全部应用上。
对于重复的要是,会应用最下面的那个样式。即body中的样式优先级高于head中的样式。同在body或head中,那么下面的样式优先级高。
总结,按我的理解,应该就是最新加载的样式会覆盖之前的样式。不冲突就追加上是,有冲突就替代掉。
上一个例子:
Title
优先级测试1
优先级测试2
优先级测试3
这里标签中的字体颜色属性就覆盖掉了 .c2 中的字体颜色。
而前2个div都是同时属于 c1 和 c2 这2个class,背景色的样式应用的都是处于下面的 c2 的样式。
class属性赋予多个值 :这里的class属性同时赋了2个值,注意一下这个赋值的格式。
css写到独立的文件
如果有多个页面文件,但用的是同一套css样式。我们目前只能在每个页面文件的head里都写上全部的css代码。这样又有代码重复的问题了。
可以创建一个css文件(pycharm里选择New->Stylesheet),将