Demo总结


一、简介  

  此Demo是一个简单的后台管理系统,主要实现不同element-ui组件下数据的增删改查功能。通过这个简单的Demo,我了解了跨域下的身份认证以及登录的实现,Vue.js的组件化开发和单页面应用的开发的思想,Element-UI的使用,javascript基础的重要性以及javascript在渲染数据和提交数据过程中对数据的处理方法。

二、身份认证

  web开发模式分为服务端渲染的传统开发模式,以及前后端分离的新型开发模式。服务端渲染的开发模式。

(1)服务端渲染开发模式(Server-Sider Rendering)

  服务端在返回 html 之前,通过模板字符串拼接,动态填充数据,再发送给客户端解析。客户端不需要使用Ajax请求页面数据。

1 app.get('/index.html', (req, res) => {
2     //需要渲染的数据
3     const user = { name: 'zs', age: '20' }
4     //字符串拼接,动态填充数据
5     const html = `

姓名:${user.name},年龄:${user.age}

` 6 res.send(html) 7 })

  服务端渲染的开发模式使得前端耗时少,有利于SEO(Search Engine Optimization,搜索引擎优化),但是占用服务端资源,不利于前后端分离。服务端渲染开发模式适合主要功能是展示而没有复杂的交互,并且需要良好的 SEO的网站

(2)前后端分离的开发模式

  前后端分离的开发模式下,前端编写html页面,使用Ajax技术向服务器请求数据并渲染到页面。前后端分离的开发模式有助于提高开发效率,提升用户体验,减轻服务端渲染压力,但不利于SEO,前后端分离的开发模式适用于交互性较强,SEO需求低的开发。

(3)不同开发模式下的身份认证

  服务端通常使用session认证机制

  HTTP协议具有无状态性,服务器不会保留每次HTTP请求的状态,而Session和Cookie弥补了HTTP无状态性的缺点。

  Cookies

  Cookies是存储在用户浏览器中的一段不超过4KB的字符串 。它由一个名称(Name)、一个 值 (Value和其它几个用于控制 Cookie 有效期 、安全性 、使用范围的可选属性组成。不同域名下的Cookie各自独立,每当客户端发起请求时,会自动把当前域名下所有 未过期的 Cookie一同发送到服务器。

  Cookie的几大特性:自动发送、域名独立、过期时限、4KB 限制

  Session机制认证过程

  1.客户端把用户ID和密码等登录信息存入HTTP报文中并向服务器发起请求.

  2.服务器收到请求,根据报文中的信息进行身份认证,认证通过后开辟session空间,创建session对象,生成sessionId,把身份认证状态与sessionid绑定保存在服务器中,服务器在响应客户端请求时,会在首部字段 Set-Cookie 内写入 Session ID。

  3.客户端接受从服务器发送来的sessionid,把sessionid作为cookies保存在本地中。

  4.接下来客户端每次向服务器发送请求时,会把cookies放在请求头,服务器从请求头中得到放在cookies中的sessionid,通过sessionid识别用户和认证状态。认证成功后服务器根据请求响应特定的内容。

  Session 的缺点

  Session 机制有个缺点,比如 A 服务器存储了 Session,就是做了负载均衡后,假如一段时间内 A 的访问量激增,会转发到 B 进行访问,但是 B 服务器并没有存储 A 的 Session,会导致 Session 的失效。

另外,由于Cookies不支持跨域访问,所以当涉及到前端跨域请求时,需要进行额外配置才能实现跨域。

  前后端分离的JWT认证机制

  JWT的全称是Json Web Token ,可以成为Json令牌。JWT通常由三部分组成,分别是 Header (头部)、Payload(有效荷载)、 Signature (签名)。

Header.Payload.Signature

  Payload部分是真正的用户信息 ,它是用户信息经过加密之后生成的字符串。Header 和 Signature是安全性相关的部分,是为了保证 Token 的安全性。

  JWT工作原理

  1.客户端通过登录请求向服务器提交账号密码。

  2.服务器接收账号密码后验证账号和密码,验证通过则加密生成token字符串,将生成的token发送给客户端,服务器不保存token字符串。

  3.客户端接收token字符串后存储到本地SessionStorage中,不建议将token存储到LocalStorage中。可能会遭受xss攻击。

  4.客户端每次发送请求,将token放在Authorization字段中发送给服务器。

//通过axios请求拦截器添加token,保证拥有获取数据的权限
axios.interceptors.request.use((config) => {
    //console.log(config)
    nprogress.start()
    config.headers.Authorization = window.sessionStorage.getItem('token')
    return config
})

  5.服务器将token字符串还原成用户的信息对象进行身份认证。认证成功则向客户端响应特定的内容。

  JWT与Session的区别

  1.JWT存储在客户端,而不是服务端。sessionid同时存储在客户端和服务端。

  2.JWT具有加密签名,而Session cookies没有

  3.Session Cookies适用于只需要登录用户并访问存储在站点数据库中的一些信息的中小型网站。而JWT适用于请求量大的企业级站点。

  4.JWT支持跨域认证,而Session cookies实现跨域认证需要配置

(4)路由导航

路由导航守卫防止了用户没有登陆获取token的情况下直接通过域名访问对应的页面

router.beforeEach((to, from, next) => {
    //to表示将要访问的路径
    //from表示从哪个路劲来的
    //next()表示到哪里去,是一个跳转函数
    if (to.path === '/login') {
        return next()
    }
    const tokenStr = window.sessionStorage.getItem('token')
    if (!tokenStr) {
        //tokenStr不存在,表示没有登陆,则回到登录页登录
        return next('/login')
    }
    //如果tokenStr存在,则登录成功了,放行
    next()
})

三、Element-UI的使用

   总结一些在Element-UI使用中遇到的坑

  el-form表单

  el-form表单中,prop的值必需与改item项中v-model绑定的值一致。el-form项和el-input应绑定同一个model。


  el-form表单除了给每一个input项设置自定义校验规则外,在提交前还使用$refs与validate方法应该对整个表单进行校验,校验通过方可提交数据。否则不允许提交表单。 

this.$refs.loginRef.validate(async (bool) => {                     //console.log(bool)                     if (!bool) {                         return //验证失败,不允许登录请求                     }                 })

  el-upload

   el-upload上传图片的一些细节。

:on-success="handleSuccess">
	点击上传

  action指定了上传的地址,只有指定了图片上传路径图片才可正确上传图片

  headers:设置上传的请求头部。el-upload组件内部封装了一套axios,此Demo使用路由导航守卫设置了访问权限,所以需要为headers设置token以获取访问权限

headerObj: {
                    Authorization: window.sessionStorage.getItem('token'),
                },
  on-success监听图片上传成功状态,当图片上传成功时,应当把图片上传成功后返回的临时路径保存到要发送到服务器的数据对象中。   
handleSuccess(response) {
                //console.log(response)
                const picInfo = { pic: response.data.tmp_path }
                this.addGoodForm.pics.push(picInfo)
                //console.log(this.addGoodForm)
            },

  on-remove事件,用于监听图片是否移除,当图片被移除时,利用被移除图片的临时路径从数据对象中找到改图片把改图片的临时路径移除出数据对象中。

handleRemove(file) {
                const filePath = file.response.data.tmp_path
                const i = this.addGoodForm.pics.findIndex((x) => {
                    x.pic == filePath
                })
                this.addGoodForm.pics.splice(i, 1)
                console.log(this.addGoodForm)
            },

on-preview事件,用于预览图片。定义一个盒子,当预览事件被触发时,把图片的url存放到盒子img的url中实现预览效果。

handlePreview(file) {
                //console.log(file)
                this.previewPath = file.response.data.url
                this.previewVisible = true
            },

  过滤器的使用

 
//在script中定义过滤器
formatDate(row) {
				//row是表格里该行的数据
				//console.log(row)
				let date = new Date(parseInt(row.add_time))
				let Y = date.getFullYear() + '-'
				let M = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) + '-' : date.getMonth() + 1 + '-'
				let D = date.getDate() < 10 ? '0' + date.getDate() + ' ' : date.getDate() + ' '
				let h = date.getHours() < 10 ? '0' + date.getHours() + ':' : date.getHours() + ':'
				let m = date.getMinutes() < 10 ? '0' + date.getMinutes() + ':' : date.getMinutes() + ':'
				let s = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
				return Y + M + D + h + m + s
			},

  也可以在main.js中定义全局过滤器

Vue.filter('dateFormat', function(originVal) {
  const dt = new Date(originVal)

  const y = dt.getFullYear()
  const m = (dt.getMonth() + 1 + '').padStart(2, '0')
  const d = (dt.getDate() + '').padStart(2, '0')

  const hh = (dt.getHours() + '').padStart(2, '0')
  const mm = (dt.getMinutes() + '').padStart(2, '0')
  const ss = (dt.getSeconds() + '').padStart(2, '0')

  return `${y}-${m}-${d} ${hh}:${mm}:${ss}`
})
//使用

          
        

  $message与$confirm

  这两个el元素导入后注册方式为

Vue.prototype.$confirm = MessageBox.confirm
Vue.prototype.$message = Message

四、javascript基础

  三元表达式

< :width="isCollapse ? '64px' : '200px'">

isCollapse: false,
//添加按钮触发此事件
toggleButton() {
    this.isCollapse = !this.isCollapse
},

  k in obj[k]遍历数据

              iconsObj: {                     125: 'iconfont icon-user',                     103: 'iconfont icon-tijikongjian',                     101: 'iconfont icon-shangpin',                     102: 'iconfont icon-danju',                     145: 'iconfont icon-baobiao',                 },

  作用域插槽


  scope.row的值对应userList的值,使用template模板实现html结构间数据传输。

  解构赋值与模板字符串

const { data: res } = await this.$http.put(`users/${userInfo.id}/state/:${userInfo.mg_state}`)

  计算属性

cateId() {
                if (this.addGoodForm.goods_cat.length === 3) {
                    return this.addGoodForm.goods_cat[2]
                }
                return null
            },

 五、用到的依赖包或其他组件

  quill-editor

   

  tree-table