都前后端分离啦,还不看看注意点

目标

能说出常见的web开发模式及其优劣
对自己在还原项目时觉得值得注意的地方进行记录

写在前面

写在前面:本文案例为跑在node服务器上的全栈项目,对项目中的注意点以及个人理解进行记录(此类项目功能大同小异)。可能存在许多个人记忆性注意点,但也有共性点,希望大家都能有所收获。

1. 开发模式

1.1 web开发模式的变化
  1. 最早,混合开发,由后端主导,前端写的代码,会交给后端,后端将自己写的代码与前端代码混合在一起,拼接成模板字符串,也称为后端渲染。这样的话,前端代码和后端代码融合在一个文件中,前端代码会被破坏,分工也不明确,代码多,很难排错,花费时间长,效率不高;

  2. 在这样的情况下,出现一种mvc开发模式,前后端分离,前端代码不会被破坏,而是在视图环节参与进去,后端把接口写好,我们可以直接通过接口调数据,进行业务逻辑,是通过模板引擎渲染界面,也称为前端渲染。显示什么页面,也是路由决定,这样的话,分工明确,实现前后端分离,在这个阶段,我们还是用的后端服务器,路由,传参,收参还需要借助后端服务器完成。

  3. Node的崛起的推动了全栈时代的到来,也是当代市场上最新的思维方法,前后端完全分离。前端通过建立自己的web服务器,解决一系列的路由 传参 收参问题,实现前后端完全分离,不再受限后端主导。

1.2 开发模式图解
  1. 混合开发

在这里插入图片描述
问题

  • 前后端开发人员对互相的代码都不是特别熟悉,混合开发两者在处理互相的代码时非常困难。
  • 在开发的过程中难免会出现代码互相覆盖,导致工作量倍增。
  1. 前后端分离

在这里插入图片描述
好处职责、分工明确,独立开发,互不影响。

2. 注意点

2.1 Ajax的使用及注意项
  1. 阻止表单默认提交

ajax大家都不陌生,jquery封装的ajax功能也是非常的强悍,实战中大多会使用jquery中的ajax。对于前后端分离项目ajax也是起着至关重要的作用。对于项目中的表单几乎都会用ajax来提交,对于ajax提交过程中,如果存在表单的默认提交行为,会导致页面默认提交数据刷新等问题。
对于此类问题只需阻止表单默认提交行为即可。阻止默认行为的方法有:1.事件对象法e.preventDefault()(普通浏览器),e.returnValue = false(ie678),2.简单粗暴发:return false(无兼容性问题),项目中常用 return false

  1. RESTful 风格的接口注意点

此类接口目前几乎已经普及,好处不再阐述。对于值得注意的地方一般为:后端提供的接口文档一般格式/users/:id,但我们在发送请求时切记不能带上,一般写法url: '/users/' + id。关于RESTful风格的API详情查看:RESTful风格的接口介绍

  1. 接口一般可复用

对于不同的功能,可能存在数据的交集,此时用过的接口也会派上用场,不是所有的接口只能用一次。
对于ajax请求成功后的success()函数内嵌套ajax请求也非常常见,只需用.给第一次请求对象追加第二次请求对象即可。

2.2 表单提交(普通值+二进制文件)
  1. 表单值的提交
  • 对于动态渲染的表单,绑定提交事件时要用到事件委托(先获取其父元素,再获取它);
  • 给每个表单项添加name属性,且name属性与接口文档的参数名称保持一致
  • 在事件处理函数中获取到用户在表单中输入的内容
  • 调用接口,将获取到的内容通过接口发送给服务器端,最后处理响应
 const formData = $(this).serialize();
 console.log(formData);

serialize()方法可以得到表单中内容,并格式化成参数字符串

在这里插入图片描述
注意:对于参数字符串中汉字的base64格式服务器会对其进行解析,返回我们需要的数据。

  1. 二进制文件的上传(图片为例)

对于文件的上传(<input type="file">),监听文件上传控件的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

  1. 表单值得注意的元素

下拉选择框select

    <select name="" id="">
        <option value="0">0</option>
        <option value="1">1</option>
    </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">

在这里插入图片描述

2.3 批量操作

此知识点就是实现复选框的全选及反选,用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);
        }
    });
2.4 分页功能

对于分页功能,知识点:服务器返回的数据+模板引擎,处理分页功能时,注意,上一页、下一页按钮的显示情况。

<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()为请求第几页数据函数,模板引擎的知识运用较多,了解模板引擎:让交互变得优雅

2.5 地址栏中获取参数方法的封装

对于一些依靠页面跳转,且地址栏中携带操作参数(携带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编辑页)),拿到参数值,查询到数据,然后页面呈现。当修改页与编辑页同一路由时,就可根据是否携带参数来进行相应页面的渲染。

2.6 逻辑依靠数据

对于一些动画的渲染(轮播图为例),如果其基本元素为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()中,逻辑部分可忽略。

2.7 公共部分代码抽离(iframe、load()、公共模板使用)

对于一些页面的重复部分(公共部分)我们当然要将他们集中处理,尽量避免代码的冗余度过高、难以维护的情况。

  1. iframe元素

iframe可谓功能强大,它可以解决资源的跨域请求,当然本地页面请求当然不在话下。实现步骤:1.公共代码抽离,写在独立的文件内,2.在抽离的部分写入iframe标签,src属性写公共部分代码路径。

注意:对于请求到的资源会在iframe中,我们要为iframe重新写样式(不推荐)。

  1. jquery的load()方法

jquery的load方法类似于ajax请求,请求公共部分代码,然后渲染。实现步骤:1.公共代码抽离,写在独立的文件内,2.在抽离的部分写入任意块级元素,3.用jquery获取此元素用load() 方法请求公共代码并填充到元素内。

<script src="./js/jquery.min.js"></script>
$('#header').load('./common/header.html')

注意:此方法仅限于同一服务器(不可跨域且服务器运行正常)。对于公共部分抽离方法较多,建议用load()(毕竟简便且项目要跑在服务器上),此外还可用gulp对公共部分进行抽离,此处不赘述,了解gulp可查看:一文学会gulp

  1. 公共模板引擎的渲染

重复的页面往往不只静态页面,对于重复的动态页面,我们可在模板引擎上做手脚

$.ajax({
    type: 'get',
    url: '/posts/random',
    success(response) {
        // 用模板字符串对数据进行拼接
        const randomTpl = `
       {{each data}}
       <li>
           <a href="detail.html?id={{$value._id}}">
               <p class="title">{{$value.title}}</p>
               <p class="reading">阅读({{$value.meta.views}})</p>
               <div class="pic">
                   <img src="{{$value.thumbnail}}" alt="">
               </div>
           </a>
       </li>
       {{/each}}
       `;
        // 定义要渲染的模板及数据
        const html = template.render(randomTpl, {
            data: response
        });
        // 把拼接好的模板填充到渲染位置
        $('#randomBox').html(html);
    }
})

注意:哪里需要填充,就在哪里填充。

2.8 项目中其他注意点
  1. 对于项目中的操作一定要确认操作者的状态(确认用户登录状态下操作,不然后续难维护);
  2. 对于请求资源时,要明白资源路径,相对于服务器的位置;
  3. 对于请求失败的数据,不防打印出请求警告,看是否是参数不符合验证规则
  4. 对于MongoDB数据库要了解数据的id是自动生成的,且id获取时要写作_id
  5. 对于请求到的数据,以真实数据为准,接口文档作为参考。对于复杂的数据,不防单独细致的看清结构,再进行操作;
  6. 对于一些动态渲染的元素,我们在操作时,可能会存在获取不到的情况,此时我们就要用到事件委托(获取其父级元素,再获取它)。

写在最后

写在最后:对于项目中碰到的细节可能有遗漏的地方,对于已写出的注意点也可能有不准确的地方,希望大家能够给予意见,坐等斧正,随时更新。最后希望大家都能够不负韶华,用代码养活自己。 Come on

猜你喜欢

转载自blog.csdn.net/cwq521o/article/details/106910227