Web编程大作业(四)高清重制+在线测验+热点广播(angular框架,websocket,树莓派)

1.高清重制

前几篇写的代码功能更多的是从技术层面出发,把网站需要用到的业务逻辑打通,但没有怎么考虑网页的外观样式和代码结构之类的问题。同时也是觉得因为代码结构写的太乱,很难在此基础上加更多的功能和样式。

于是就从零开始,手写了整个express框架,配合angular重新写了一个高清重制版。样式方面没有用bootstrap,一方面感觉bootstrap还是需要一些css基础,另一方面用flex手写布局本身就挺方便了,基本能满足所有需求,并且更加灵活,可以知道每个属性对html元素产生的影响。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
大多数技术方面的逻辑其实都已经体现在前两篇博客了,还有一些样式方面的需要的话也可以直接看代码,这里就不多赘述。

说几个重制过程中感觉比较有体会的点和踩过的坑吧。

1. express的再理解

在express的文档中有这样一句话
在这里插入图片描述
所谓中间件,指的就是用app.use所调用的部件,一些express内置的,一些是自定义的。理解中间件在我看来其实只要把它们当成一种处理http请求的方式即可。只要这个http请求的地址满足app.use的第一个参数(若缺省则默认为’/’),那么就会调用第二个参数的中间件。

从之前经常用的路由器说起:

router.get('/',function(req,res,next){
   
    res.send('hello~');
})

这段代码很好理解,只要在该路由下收到get请求,就会给页面返回’hello~'的响应。可以说function(req,res,next)这个函数就是一个中间件,是一个在收到请求后“被调用”的组件。

那么完全可以用这个思路去理解app.use,区别在于app.use不仅限于get请求而能够接受任何类型的http请求。同时,express.Router()本身就可以在主程序app.js被当作一个中间件来使用:(express.Router()是一个内置的路由中间件,本质上是帮助我们根据不同的路径进行代码分离)

var indexRouter = require('./router/index.js');
app.use(indexRouter);//第一个参数的缺省值为'/'

一些中间件仅仅是为了引入某个功能,用文档中的话说,这种中间件不是函数调用,而是“使能”的意思,比如使后端能够解析req.body:

//用来解析req.body,分别对应application/json和application/x-www-form-unlencoded
app.use(express.json());
app.use(express.urlencoded({
    extended: false }));

还有一些第三方中间件可以有各种其他的功能,比如:

//打印和记录请求信息
app.use(logger('dev'));
//“使能”通过req.cookies获取cookie
app.use(cookieParser());

还有一些则负责对http请求返回响应,通常是我们自定义的一些中间件,为了代码整洁清晰,通常把这些中间件放进路由器里,再通过路由中间件express.Router()执行。

值得一提的是,http请求除了对网址的直接访问,还包括了html元素中src属性的间接访问。对主页的一次get请求可能包含了非常多的请求,包括html引入的css样式、script代码、各种图片资源等等,比如我访问了一次首页,实际上发生了9次get请求:
在这里插入图片描述
对于每一个get请求,无论是直接还是间接的,都会经过设置的中间件。为了让网页能正常找到这些静态资源,还需要用express.static()这个中间件设置静态资源的路径(可以理解为重定向)。

app.use(express.static(path.join(__dirname+'/public')));
app.use('/angular',express.static(path.join(__dirname+'/node_modules/angular')));
app.use('/jquery',express.static(path.join(__dirname+'/node_modules/jquery')));

以上就是我对中间件的一点理解。。其实理解中间件也就等同于理解express框架本身。在手写express的时候经常会发现以前原本没有遇到过的问题(比如说不能用req.body获取post请求数据,不能用req.cookies获取当前网页cookie之类的问题),折腾半天之后发现原来是没有引入对应的中间件导致的。所以这个过程其实非常能加深对于中间件作用的理解,也能明白每一个中间件到底对应了什么功能,这些功能如何产生作用,继而明白为什么要写这个中间件。在此基础上再去文档里看各种自定义中间件的request、response的属性和方法也会变得容易很多。

reference:https://www.expressjs.com.cn/

2. angular作用域问题、自动同步问题

这是我课堂页面的导航栏
在这里插入图片描述
利用angular,在写课堂页面时我想到了一个看上去还比较优雅的写法,可以实现页面切换,同时保证各个页面的数据都能实时更新。

<div ng-include="'html/chat.html'" class='container' ng-show="chatIsShow"></div>
<div ng-include="'html/file.html'" class='container' ng-show="fileIsShow"></div>
<div ng-include="'html/problem.html'" class='container_problem' ng-show="problemIsShow"></div>

也就是通过ng-include引入三张网页,同时置于class页面中。使用ng-show控制页面的可见性,并确保同一时间只有一张页面显示,另外两张页面均隐藏。这样一来,即使我当前显示的是“课堂测验”页面,“实时消息”的页面仍然存在,其中的内容依然能正常地发生改变。当用户切换过去即可看到这段时间的实时消息了。

然而遇到了一个问题,在ng-include内部,通过ng-model绑定的变量在class中无法正常被捕获。

比如说chat.html的一个input元素是这样的

<input class='message_input' ng-model="chatMessage" type='text' placeholder="请输入消息">

通常$scope.chatMessage即可获取这个输入框里的内容,但是现在不行了。后来查了一下,捕获不到的原因是因为外面套了一个ng-include。在angular中,ng-include(包括ng-repeat,ng-switch,ng-view,ng-controller)实际上会创建一个新的作用域,而这个新作用域就脱离了class中$scope的作用范围。解决方法是在chatMessage前加上$parent,因为这个新作用域是继承自父级作用域的,可以用$parent调用父scope($parent是子作用域指向父作用域的一个引用),也就是把input的内容绑定在class的作用域上。

<!-- $parent解决子页面作用域问题,否则数据不能实时更新 -->
<input class='message_input' ng-model="$parent.chatMessage" type='text' placeholder="请输入消息">

同时还有一个小问题,angular的ng-model模型绑定本来是可以自动同步的,也就是修改变量值后,页面中显示的内容会同步发生改变。但是套了一层ng-include之后有时也会失去这个特性。。初步猜测也是因为这个作用域变化的问题。解决方法也很简单,每次修改变量值后,通过$scope.$apply()手动传播一下model的变化(即更新页面)即可。

这两个问题解决之后很自然引入了一个叫做“angular作用域”的概念,虽然暂时也没有别的理解,但是用$parent来追踪父-子关系应该可以解决大部分问题了。

3. 写html页面的一点方法

其实我觉得写html要比js要累的多。。但是又不得不写。。个人觉得一个好的html代码应该要尽量做到以下几点:

  1. 前、后端、样式分离
  2. 对于每一块页面结构(比如一行)都应该包含在一个块里(比如一个<div>),同时尽量减少多余的父元素(便于样式设计)
  3. 样式复用率尽可能高
  4. class和id的命名有一定层级逻辑(但是又不能太复杂),用同样的class控制同样的样式,确保id唯一,便于用getElementById获取

比如如果我要设计下图这个界面:
在这里插入图片描述
那么首先先大致根据行来分层,找出样式相同的行
在这里插入图片描述
然后先用<div>把整体框架写出来,同时设置好class属性,将相同的行设置成相同的class

<div class='container'>
    <div class='title_row'>
    </div>
    <div class='input_row'>
    </div>
    <div class='input_row'>
    
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值