能说出常见的web开发模式及其优劣
对自己在还原项目时觉得值得注意的地方进行记录
写在前面:本文案例为跑在node服务器上的全栈项目,对项目中的注意点以及个人理解进行记录(此类项目功能大同小异)。可能存在许多个人记忆性注意点,但也有共性点,希望大家都能有所收获。
最早,混合开发
,由后端主导,前端写的代码,会交给后端,后端将自己写的代码与前端代码混合在一起,拼接成模板字符串,也称为后端渲染。这样的话,前端代码和后端代码融合在一个文件中,前端代码会被破坏,分工也不明确,代码多,很难排错,花费时间长,效率不高;
在这样的情况下,出现一种mvc开发模式,前后端分离
,前端代码不会被破坏,而是在视图环节参与进去,后端把接口写好,我们可以直接通过接口调数据,进行业务逻辑,是通过模板引擎渲染界面,也称为前端渲染。显示什么页面,也是路由决定,这样的话,分工明确,实现前后端分离,在这个阶段,我们还是用的后端服务器,路由,传参,收参还需要借助后端服务器完成。
Node的崛起的推动了全栈时代的到来,也是当代市场上最新的思维方法,前后端完全分离
。前端通过建立自己的web服务器,解决一系列的路由 传参 收参问题,实现前后端完全分离,不再受限后端主导。
ajax
大家都不陌生,jquery封装的ajax
功能也是非常的强悍,实战中大多会使用jquery中的ajax
。对于前后端分离项目ajax
也是起着至关重要的作用。对于项目中的表单几乎都会用ajax
来提交,对于ajax提交
过程中,如果存在表单的默认提交行为,会导致页面默认提交
、数据刷新
等问题。
对于此类问题只需阻止表单默认提交行为即可。阻止默认行为的方法有:1.事件对象法e.preventDefault()
(普通浏览器),e.returnValue = false
(ie678),2.简单粗暴发:return false
(无兼容性问题),项目中常用 return false。
此类接口目前几乎已经普及,好处不再阐述。对于值得注意的地方一般为:后端提供的接口文档一般格式/users/:id
,但我们在发送请求时切记不能带上:
,一般写法url: '/users/' + id
。关于RESTful
风格的API详情查看:RESTful风格的接口介绍。
对于不同的功能,可能存在数据的交集,此时用过的接口也会派上用场,不是所有的接口只能用一次。
对于ajax请求成功后的success()
函数内嵌套ajax请求也非常常见,只需用.
给第一次请求对象追加第二次请求对象即可。
动态渲染的表单
,绑定提交事件时要用到事件委托
(先获取其父元素,再获取它);name属性
,且name属性与接口文档的参数名称保持一致
;获取到用户在表单中输入的内容
;发送给服务器端
,最后处理响应 const formData = $(this).serialize();
console.log(formData);
serialize()
方法可以得到表单中内容,并格式化成参数字符串
注意:对于参数字符串中汉字的base64
格式服务器会对其进行解析,返回我们需要的数据。
对于文件的上传(),监听文件上传控件的
onchange
事件,file控件的this
指向选中文件的信息,将此信息作为属性值给FormData
实例对象,提交给服务器处理(node第三方模块formidable
),服务器返回客户端需要的数据(此处返回图片路径),此时可将图片路径的值给表单中的隐藏域作为参数
,随表单其他参数一起提交
。
$('#modifyBox').on('change', '#avatar', function() {
// 二进制数据上传需要FormData对象解析
var formData = new FormData();
formData.append('avatar', this.files[0]);
$.ajax({
url: '/upload',
type: 'post',
data: formData,
// 告诉ajax方法不要解析请求参数
processData: false,
// 告诉ajax方法不要设置请求参数类型
contentType: false,
success(response) {
// 实现预览功能
$('#preview').attr('src', response[0].avatar);
// 隐藏域向服务器传递图片路径
$('#hiddenAvatar').val(response[0].avatar)
},
error() {
console.log('图片上传失败')
}
})
})
注意:FormData对象在表单提交中也是非常有用,对于FormData的进一步了解可参考下:一文让你搞懂FormData。
下拉选择框select
<select name="" id="">
<option value="0">0option>
<option value="1">1option>
select>
注意:表单提交的name写在select
身上,value写在option
身上,提交时,哪个value
在可视化区域,提交哪个value。
状态选择radio
<label><input type="radio" name="role" value="admin ">超级管理员label>
<label><input type="radio" name="role" value="normal">普通用户label>
注意:此时两个元素的name
要保持一致,value
存在差别,提交时,谁被选中提交谁。
文本域textarea
<textarea id="content" class="form-control input-lg" cols="30" rows="10" placeholder="内容" name="content">textarea>
注意:文本域无value
值,它的内容直接写在双标签内。
date标签在赋值时注意格式
<input type="date" value="2020-12-01">
此知识点就是实现复选框的全选及反选
,用jquery更加简便一些
// 全选按钮,实现全选功能
$(".checkall").change(function() {
// 所有子复选框随全选变化
$(".j-checkbox, .checkall").prop("checked", $(this).prop("checked"));
});
// 子复选框的变化影响总复选框
$(".j-checkbox").change(function() {
// 如何子复选框的选中数 = 商品总数,总复选框就选中,否则不选
if ($(".j-checkbox:checked").length === $(".cart-item").length) {
$(".checkall").prop("checked", true);
} else {
$(".checkall").prop("checked", false);
}
});
对于分页功能,知识点:服务器返回的数据+模板引擎
,处理分页功能时,注意,上一页、下一页按钮的显示情况。
<script type="text/html" id="pageTpl">
{
{
if page > 1}}
<li><a href="javascript:;" onclick="getPage({
{page - 1}})">上一页</a></li>
{
{
/if}} {
{
each display}}
<li>
<a href="javascript:;" onclick="getPage({
{$value}})">{
{
$value}}</a>
</li>
{
{
/each}} {
{
if page
< pages}} <li><a href="javascript:;" onclick="getPage({
{page + 1}})">下一页</a></li>
{
{
/if}}
</script>
注意:此处的getpage()
为请求第几页数据函数,模板引擎的知识运用较多,了解模板引擎:让交互变得优雅。
对于一些依靠页面跳转,且地址栏中携带操作参数
(携带id、数据表的主键等)的任务,我们需要获取到地址栏中的参数
来进行后续的操作,因为此类任务比较常见,所以此处对其进行封装。
/ 注意此处的name与路由中要传递的参数保持一致
function getUtlParams(name) {
// 可能有多个参数,去除第一个"?",以"&"符为分界分割成数组
const paramsAry = location.search.substr(1).split('&');
// 循环数组,进行第二次分割,以"="为界限
for (let i = 0; i < paramsAry.length; i++) {
// 把每个数据从"="分割成数组
const tmp = paramsAry[i].split('=');
// 如果传入的参数名就是数组第一个值,返回数组第二个值(参数值)
if (tmp[0] == name) {
return tmp[1]
}
}
}
注意:此方法一般用于修改数据,且支持页面跳转(例如:https://editor.csdn.net/md?articleId=106910227(csdn编辑页)),拿到参数值,查询到数据,然后页面呈现。当修改页与编辑页同一路由时,就可根据是否携带参数来进行相应页面的渲染。
对于一些动画的渲染
(轮播图为例),如果其基本元素为ajax
动态渲染,此时我们在发送ajax请求渲染模板时就要把动画的逻辑写在success()
函数中,防止渲染后动画失效(因为逻辑找不到元素)
$.ajax({
type: 'get',
url: '/slides',
success(response) {
const html = template('slideTpl', {
data: response
});
$('#slideBox').html(html);
// 模板加载完毕才可调用轮播图逻辑代码,所以,逻辑在此处调用
var swiper = Swipe(document.querySelector('.swipe'), {
auto: 3000,
transitionEnd: function(index) {
// index++;
$('.cursor span').eq(index).addClass('active').siblings('.active').removeClass('active');
}
});
// 上/下一张
$('.swipe .arrow').on('click', function() {
var _this = $(this);
if (_this.is('.prev')) {
swiper.prev();
} else if (_this.is('.next')) {
swiper.next();
}
})
}
})
注意:意在表示逻辑在success()
中,逻辑部分可忽略。
对于一些页面的重复部分(公共部分)我们当然要将他们集中处理
,尽量避免代码的冗余度过高、难以维护的情况。
iframe可谓功能强大,它可以解决资源的跨域请求,当然本地页面请求当然不在话下。实现步骤:1.公共代码抽离,写在独立的文件内,2.在抽离的部分写入iframe
标签,src属性
写公共部分代码路径。
注意:对于请求到的资源会在iframe
中,我们要为iframe
重新写样式(不推荐)。
jquery的load方法类似于ajax
请求,请求公共部分代码,然后渲染。实现步骤:1.公共代码抽离,写在独立的文件内,2.在抽离的部分写入任意块级元素,3.用jquery获取此元素
,用load() 方法
请求公共代码并填充到元素内。
$('#header').load('./common/header.html')
注意:此方法仅限于同一服务器(不可跨域且服务器运行正常)。对于公共部分抽离方法较多,建议用load()
(毕竟简便且项目要跑在服务器上),此外还可用gulp
对公共部分进行抽离,此处不赘述,了解gulp可查看:一文学会gulp
重复的页面往往不只静态页面,对于重复的动态页面,我们可在模板引擎上做手脚
$.ajax({
type: 'get',
url: '/posts/random',
success(response) {
// 用模板字符串对数据进行拼接
const randomTpl = `
{
{each data}}
{
{$value.title}}
阅读({
{$value.meta.views}})
{
{/each}}
`;
// 定义要渲染的模板及数据
const html = template.render(randomTpl, {
data: response
});
// 把拼接好的模板填充到渲染位置
$('#randomBox').html(html);
}
})
注意:哪里需要填充,就在哪里填充。
状态
(确认用户登录状态下操作,不然后续难维护);服务器
的位置;验证规则
;MongoDB
数据库要了解数据的id
是自动生成的,且id获取时要写作_id
;以真实数据为准
,接口文档作为参考。对于复杂的数据,不防单独细致的看清结构
,再进行操作;动态渲染的元素
,我们在操作时,可能会存在获取不到
的情况,此时我们就要用到事件委托
(获取其父级元素,再获取它)。写在最后:对于项目中碰到的细节可能有遗漏的地方,对于已写出的注意点也可能有不准确的地方,希望大家能够给予意见,坐等斧正,随时更新。最后希望大家都能够不负韶华,用代码养活自己。 Come on