项目介绍
整个项目分为两大部分:内容管理和内容展示。
技术栈:
- 数据层:mongDB
- 服务层:node.js(express)
- 客户端:art-template、jQuery、font-awesome、swipe
项目描述:
根据相关技术栈实现前后端分离开发。内容管理部分实现用户模块的登录退出,增删改查功能。文章模块实现分类评论等文章管理。最后采用jQuery和font-awesome、swipe等对网站的关键字,描述,轮播图等功能进行设置。
整个项目主要分为两大部分,其一是内容管理部分,其二是数据展示部分。通过对页面内容的增删改查将其渲染在浏览器端页面并展示给用户。内容管理部分分为5个部分,其一是对用户模块的设置,实现用户登录,注册,修改密码等一系列操作,通过jQuery和Ajax技术从后台获取数据,在进行用户信息的增删改查。其余模块分别包括,文章列表管理,文章的分类,以及对文章评论系统进行的操作。这三个部分主要也是通过前后端数据的交互,对模块进行增删改查操作,并将内容渲染在浏览器端的详情页面。最后也就是对网站的设置。通过font-awesome字体库,以及swipe技术对网站进行优化,实现展示网站logo以及轮播图效果。
项目的难点:
你遇到的问题:
1、在进行修改和删除的时候为按钮点击添加事件的时候要通过事件委托的行式(因为Ajax是异步操作,时间不确定),刚开始没注意到所以导致,事件一直无法绑定。
2、在进行模板拼接的时候,日期数据是以字符串形式展示的,而此时需要获取日期数据的属性,所以要先转化为对象的形式,才能获取到日期的年月日属性。
模版中的formdata格式是字符串的形式,因此必须将日期数据转换成对象的形式
相关面试问题:
-
说一下Ajax如何解决浏览器缓存问题
-
登录怎么实现的、轮播图相关
css方法实现轮播(采用动画的方式,设置每一个图片的依次播放时间)
JS的方式,绑定鼠标事件实现轮播图。 -
事件委托 是什么?
事件委托本质上是利用了浏览器事件冒泡的机制。因为事件在冒泡过程中会上传到父节点,并且父节点可以通过事件对象获取到目标节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件,这种方式称为事件代理。
优点:
1、不必要为每一个子元素都绑定一个监听事件,这样减少了内存上的消耗。
2、 可以实现事件的动态绑定,比如说新增了一个子节点,我们并不需要单独地为它添加一个监听事件,它所发生的事件会交给父元素中的监听函数来处理。
举个例子,比如一个宿舍的同学同时快递到了,一种方法就是他们都傻傻地一个个去领取,还有一种方法就是把这件事情委托给宿舍长,让一个人出去拿好所有快递,然后再根据收件人一一分发给每个宿舍同学;
在这里,取快递就是一个事件,每个同学指的是需要响应事件的 DOM 元素,而出去统一领取快递的宿舍长就是代理的元素,所以真正绑定事件的是这个元素,按照收件人分发快递的过程就是在事件执行中,需要判断当前响应的事件应该匹配到被代理元素中的哪一个或者哪几个。
-
同步和异步的区别
同步,可以理解为在执行完一个函数或方法之后,一直等待系统返回值或消息,这时程序是处于阻塞的,只有接收到返回的值或消息后才往下执行其他的命令。
异步,执行完函数或方法后,不必阻塞性地等待返回值或消息,只需要向系统委托一个异步过程,那么当系统接收到返回值或消息时,系统会自动触发委托的异步过程,从而完成一个完整的流程。 -
说一下事件冒泡
浅谈JS时间冒泡
时间冒泡先看一个例子
事件冒泡 :当一个元素接收到事件的时候 会把他接收到的事件传给自己的父级,一直到window 。(注意这里传递的仅仅是事件 并不传递所绑定的事件函数。所以如果父级没有绑定事件函数,就算传递了事件 也不会有什么表现 但事件确实传递了。)
var div1 = document.getElementById("div1");
var div2 = document.getElementById("div2");
div2.onclick = function(){alert(1);};
div1.onclick = function(){alert(2);};//父亲
//html代码
<div id="div1">
<div id="div2"></div>
</div>
两个父子关系的div,然后分别加了点击事件,当我们在div2里面点击的时候,会发现弹出了一次1,接着又弹出了2,这说明点击的时候,不仅div2的事件被触发了,它的父级的点击事件也触发了,这种现象就叫做冒泡。点击了div1,自己父级的点击事件也会被触发
取消事件冒泡有两种方式:
标准的W3C 方式:e.stopPropagation();这里的stopPropagation是标准的事件对象的一个方法,调用即可
非标准的IE方式:ev.cancelBubble=true; 这里的cancelBubble是 IE事件对象的属性,设为true就可以了
用户模块
实现功能:
1、登录功能
界面如下所示
第一步:给登录按钮添加点击事件
第二步:获取输入的用户名和密码
第三步:验证输入用户名和密码是否有效
第四步:Ajax调用实现登录的接口,向后台发送post请求,此时将输入的密码和数据库中默认用户密码进行对比,**返回的结果(response)是什么?**对比成功则直接跳转到数据管理页面
<script type="text/javascript">
// 选择登录按钮并为其添加点击事件
$('#loginBtn').on('click', function() {
// 获取用户输入的邮箱地址
var email = $('#email').val();
// 获取用户输入的密码
var password = $('#password').val();
// 判断用户是否输入了邮箱地址
if (email.trim().length == 0) {
alert('请输入邮箱')
return;
}
// 判断用户是否输入了密码
if (password.trim().length == 0) {
alert('请输入密码');
return;
}
// 判断完成之后需要进行登录操作,email和password都有默认的参数,如果和数据库保存的不匹配则此时用户名或密码错误
$.ajax({
type: 'post',
url: '/login',
data: {
email: email,
password: password
},
success: function(response) {
// 登录成功 跳转到数据管理的首页面
location.href = 'index.html';
},
error: function() {
// 登录失败
alert('用户名或者密码错误')
}
})
});
</script>
除此之外为了防止用户在没有登录的情况下采用localhost:3000/index.html访问数据管理页面此时需要添加登录拦截功能。(有可能会漏掉,重点之一)
2. 添加用户
数据管理页面如下所示
第一步:为用户功能的每一个表单添加name属性,并且要和接口文档中的参数名称保持一致(要在数据库中可以对应)。
第二步:微表单绑定提交事件,在事件处理函数中阻止表单默认提交行为(为什么?表单默认提交行为?)
第三步:在事件处理函数中获取用户在表单中输入的内容
第四步:调用用户接口,获取到的内容发送给服务器端。
// 当表单发生提交行为的时候
$('#userForm').on('submit', function() {
// 获取到用户在表单中输入的内容并将内容格式化成参数字符串
var formData = $(this).serialize();
// 向服务器端发送添加用户的请求
$.ajax({
type: 'post',
url: '/users',
data: formData,
success: function() {
// 刷新页面
location.reload();
},
error: function() {
alert('用户添加失败')
}
})
// 阻止表单的默认提交行为
return false;
});
3、 用户头像上传
第一步:为上传控件添加onchange事件
第二步:创建formData对象用于实现图片上传
第三步:调用图片上传接口,实现上传
第四步:再添加新用户表单中新增一个隐藏域,将图片地址存储在隐藏域中
<div class="col-md-4" id="modifyBox">
<form id="userForm">
<h2>添加新用户</h2>
<div class="form-group">
<label>头像</label>
<div class="form-group">
<label class="form-image">
<input id="avatar" type="file">
<!-- 添加预览功能,给图片添加id属性 -->
<img src="../assets/img/default.png" id="preview">
<i class="mask fa fa-upload"></i>
</label>
<!-- 添加新用户的表单准备隐藏域,因为需要将图片地址再一次体检给服务器端,
name的属性值要和添加新用户中图像的参数名称一致 -->
<input type="hidden" name="avatar" id="hiddenAvatar">
</div>
</div>
// 当用户选择文件的时候
$('#modifyBox').on('change', '#avatar', function() {
// 用户选择到的文件
// this.files[0]
var formData = new FormData();
// this.files[0]选择的列表中的第一个文件
formData.append('avatar', this.files[0]);
//向服务器端发送ajax请求实现上传功能
$.ajax({
type: 'post',
url: '/upload',
data: formData,
// 告诉$.ajax方法不要解析请求参数
processData: false,
// 告诉$.ajax方法不要设置请求参数的类型
contentType: false,
// response存储的是上传之后图片的地址
// 服务器端将要上传的图片地址返回给客户端
success: function(response) {
console.log(response)
// 实现头像预览功能
$('#preview').attr('src', response[0].avatar);
// 设置隐藏域的值为上传之后的图片地址
$('#hiddenAvatar').val(response[0].avatar)
}
})
});
4、用户信息修改
第一步:采用事件委托的方式为编辑按钮添加点击事件。(因为采用Ajax技术从服务器端请求到客户端后再显示,Ajax是异步操作,所以服务器返回数据的时间不确定,因此采用时间委托的方式)
第二步:在事件处理函数中获取当前点击用户的id值。
第三步:根据id值获取用户信息,并渲染在左侧表单中。
// 通过事件委托的方式为编辑按钮添加点击事件
$('#userBox').on('click', '.edit', function() {
// 获取被点击用户的id值
var id = $(this).attr('data-id');
// 根据id获取用户的详细信息
$.ajax({
type: 'get',
url: '/users/' + id,
// response存储的是用户的详细信息
success: function(response) {
console.log(response)
// html是拼接好的字符串
var html = template('modifyTpl', response);
// 让modifyBox里面的内容就是我们拼接好的字符串
$('#modifyBox').html(html);
}
})
});
第四步:为修改表单添加表单提交事件,将修改的结果上传到后台数据库中并渲染在右侧用户列表中
// 为修改表单添加表单提交事件
$('#modifyBox').on('submit', '#modifyForm', function() {
// 获取用户在表单中输入的内容
var formData = $(this).serialize();
// 获取要修改的那个用户的id值
var id = $(this).attr('data-id');
// 发送请求 修改用户信息
$.ajax({
type: 'put',
url: '/users/' + id,
data: formData,
success: function(response) {
// 修改用户信息成功 重新加载页面
location.reload()
}
})
// 阻止表单默认提交
return false;
});
文章管理
添加分类
文章内容管理页面
文章列表数据展示
网站设置
图片轮播图
功能:点击图片进入到相关页面。