使用 json-server 来快速搭建后台服务器
所有的数据可以存放在 server 中创建的 db.json 文件中
在前端的 app 文件中,可以在 index.html 中通过 CDN 的方式引入 Bootstrap 以及 jQuery
为了方便 ,则使用 jQuery 中所提供的 $.ajax 方法来发送请求
需要 先引入 jquery
methods: {
getInfo() {
// 发送 Ajax 请求
$.ajax({
url: "http://localhost:3000/users",
type: "GET",
success: (data) => {
this.stuInfo = data;
},
});
}
}
是 Web 提供的一个可以获取 异步资源的 api (应用程序接口)
所提供的 api 返回的是 Promise 对象
fetch('http://localhost:3000/stu')
.then(res=>res.json())
.then(text=>{
this.stuInfo = text;
})
拿到响应对象 res 后,调用 json 方法从响应对象中将 json 数据流转换为一个被解决为 js 对象的 Promise,成功后会再次进入到 then 方法,进入时会传入转换好的 js 对象
fetch("/search/project/", {
method: "POST", //请求方法
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: "q=参数q" //请求体
}).then(function(response) {
});
主要用于异步编程计算
优点:
将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数,解决回调函数 的 回调地狱
Promise 对象提供统一的接口,使得控制异步操作更加容易
缺点:
一旦新建它就会立即执行,无法中途取消
不设置回调函数,Promise 内部抛出的错误,不会反应到外部
Pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)
可以使用 new 来调用 Promise 的构造器来进行实例化
var promise = new Promise(function(resolve, reject) {
// 异步处理
// 处理结束后、调用resolve 或 reject
});
promise.then() 是 promise 最为常用的方法
实例化过的 promise 对象可以调用 promise.then() 方法,传递 resolve 和 reject 方法作为回调
Promise.reject() 方法返回一个带有拒绝原因的Promise对象
vue 是数据驱动的,这使得我们并不需要直接操作 DOM
vue-resource 是 vue 的一款插件 ,它的 api(应用程序接口) 更为简洁
与Fetch 不同,vue-resource 返回的响应对象中的 body 对应的值 直接就是数据,不再需要使用 json 方法来解析一次。
Axios 是一个基于 promise 的 http 库
可以用在浏览器和 node.js 中
// 引入 axios
import axios from 'axios'
// 配置路径
axios.defaults.baseURL = 'http://localhost:3000/'
// 配置 vue 原型
Vue.prototype.http = axios;
this.http.get('/stu')
.then(res=>{
this.stuInfo = res.data;
})
从响应对象的 data 属性中就可以直接拿到需要的数据
分为请求拦截和响应拦截
在请求发出之前,对请求做一些额外处理,一般是配置统一的 token
在请求返回时,对返回的数据进行一些处理,主要用于获取状态值
如果为 401(约定为 token 失效,需要登录)
路由,主要用于 路径的匹配,通过引入 vue-router 文件的方式来实现组件的切换
// 对路由进行注册
Vue.use(Router);
export default new Router({
// 此对象进行路由配置
routes : [{
path : '/comone',
component : Comone // 组件首字母大写
},
{
path : '/comtwo',
component : Comtwo // 组件首字母大写
}]
});
实现对地址 的切换 ,从而进行不同地址访问
会在访问地址末尾加 #name
不会被包含在 http 请求中,对后端没有影响,hash 改变不会重新加载页面
没有# ,通过 back、forword、go 等方法控制页面跳转,会请求后端接口,需要后台配置支持
充分利用 history.pushState
API 来完成 URL 跳转而实现和hash一样无须重新加载页面
history弊端 :
在history下,可以自由的修改path,当刷新时,如果服务器中没有相应的响应或者资源,会报404
router-link 用来实现跳转。最终,router-link 会被渲染为 a 标签
组1
组2
除了在 router-link 中直接为 to 属性指定要切换的组件以外,也通过使用data数据绑定一个变量
<!-- 要切换的组件来自于变量所对应的值 -->
<router-link :to="test1">内容1</router-link>
<router-link :to="test2">内容2</router-link>
data () {
return {
test1: '/com1',
test2: '/com2'
}
}
router-link 最终在 html 中生成的是 a 标签
通过 tag 属性,我们可以指定生成为所需要的标签。
<router-link :to="test1" tag='div'>内容1router-link>
在路由文件中 ,通过 linkActiveClass 可以配置指定的样式
// 设置激活样式
linkActiveClass: '样式名'
设置 event 属性,属性值为 mouseover,表示鼠标移入时就会切换组件
内容1
在路由中,可以通过设置name 属性,来代替路径
{
path: 'one',
component: One,
name: 'childname' // 命名路由
}
要实现路劲匹配时,可直接使用 name
<router-link :to="{name:'childname'}">onerouter-link>
可以使一个路径显示出 所有的组件
{ // 命名视图
path: '/comthree',
components: {
default: Comone,
sider: Comtwo
}
}
组1
组2
组3
其特点就是要在 router-link 中书写跳转链接,然后通过生成 a 标签的形式来进行跳转。
内容1
就是 vue-router 中给我们提供的一堆方法,让我们可以通过在 js 中编写代码来实现导航切换
方法包括:back、forward、go、push、replace
router.push 方法,会向 history 栈 **添加 **一个新的记录
// 向当前的 history 栈推入一个新的路由
this.$router.push('/user/two');
类似push,但不会向 history 添加新记录,而是跟它的方法名一样:**替换 **掉当前的 history 记录
// 替换当前 history 栈中的路由
this.$router.replace('/user/two');
当有带有id的组件时,可以通过动态路由来找到相对应的路径,来进行对应的渲染。
在路由后面添加 /:id,表示路由后面接收一个参数
path: '/user/:id',
想要有无参数都可以映射到 User 组件,可以在后面添加一个问号(?)
path: '/user/:id?',
在组件中书写 wathch 方法来进行监听
在组件中,添加 watch 监听方法,当 $route 后面的参数发生改变时会触发此方法
// 之后对路由进行监听,如果后面的参数发生变化,会触发 $route 方法
// to 为新的路由,from 为旧的路由
watch: {
$route(to, from) {
let id = to.params.id;
this.userInfo = userData.filter((item)=>{
return item.id == id;
})
console.log(this.userInfo);
}
}
就是 vue-router 的生命周期钩子函数,主要用来通过跳转或取消的方式来守卫导航
方式:
全局的, 单个路由独享的, 或者组件级的
参数或查询的改变并不会触发进入/离开的导航守卫
可以通过观察 $route
对象响应路由参数的变化)来应对这些变化,或使用 beforeRouteUpdate
的组件内守卫。
使用 router.beforeEach
注册
当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于 等待中。
to: Route
: 即将要进入的目标 路由对象from: Route
: 当前导航正要离开的路由next: Function
: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next
方法的调用参数。next()
:进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
next(false)
:中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from
路由对应的地址。
next('/')
或者 next({ path: '/' })
:跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。
next(error)
:(2.4.0+) 如果传入 next
的参数是一个 Error
实例,则导航会被终止且该错误会被传递给 router.onError()
注册过的回调。
注意:确保 next
函数在任何给定的导航守卫中都被严格调用一次。它可以出现多于一次,但是只能在所有的逻辑路径都不重叠的情况下,否则钩子永远都不会被解析或报错
// BAD
router.beforeEach((to, from, next) => {
if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
// 如果用户未能验证身份,则 `next` 会被调用两次
next()
})
// GOOD
router.beforeEach((to, from, next) => {
if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
else next()
})
router.beforeResolve
注册一个全局守卫
区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。
进入路由之后触发
钩子不会接受 next
函数也不会改变导航本身
router.afterEach((to, from) => {
// ...
})
在对应的路由配置上直接定义 beforeEnter
守卫
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
在路由组件内直接定义
beforeRouteEnter
beforeRouteUpdate (2.2 新增)
beforeRouteLeave
const Foo = {
template: `...`,
beforeRouteEnter(to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不能!访问/获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate(to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave(to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
//用来禁止用户在还未保存修改前突然离开
const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
if (answer) {
next()
} else {
next(false)
}
}
}
beforeRouteLeave
守卫。beforeEach
守卫。beforeRouteUpdate
守卫 (2.2+)。beforeEnter
。beforeRouteEnter
。beforeResolve
守卫 (2.5+)。afterEach
钩子。beforeRouteEnter
守卫中传给 next
的回调函数,创建好的组件实例会作为回调函数的参数传入。专为 Vue.js 应用程序开发的状态管理模式,也称为 状态机
采用 集中式存储管理 应用的所有组件的状态,组件就直接都和 store 通讯
在构建中大型的单页面应用程序时使用
只负责保存仓库的状态(数据)
可以将对仓库值的修改统一写在 Getter 所对应的函数里面,通过它来获取数据
其他组件中要使用修正后的数据的话,直接从 this.$store.getters 中拉取数据即可
通过它组件可以更新仓库里面的数据
mutations: {
changeCount(state, payload) {
state.count += payload;
}
},
当其他的组件中,出发了点击事件等,那么在触发事件 methods 中会 commit 在 store.js 中所定义的 mutation
methods: {
clickHandle() {
//如何修改仓库的数据
//其实就是调用mutation中的方法
// 2 作为第二个参数,对面的 payload 会接收此参数
this.$store.commit("changeCount",2);
},
},
在 Mutation 中混合异步调用会导致你的程序很难调试,异步回调太多,不容易区分时候回调和哪个先回调。
所以在 Vuex 中,将全部的改变都用同步方式实现。将全部的异步操作都放在 Actions 中
组件 使用 dispatch 来调用在 store.js 中的 action
this.$store.dispatch("ageChange", age);
首先视图先触发action,然后 action再来触发 Mutation
Mutation:专注于修改 State,理论上是修改 State 的唯一途径。
Action:业务代码、异步请求。
Mutation:必须同步执行。
Action:可以异步,但不能直接操作 State。
将 store 分割成模块,减少代码臃肿
每个模块有自己的 state、mutation、action、getter
在 store文件中 使用 modules 整合上面的状态模块
export default new Vuex.Store({ // 使用 modules 整合上面的状态模块 modules: { students: moduleA, teachers: moduleB }})
// 组件
f01() {
// this.$store.state 指向 modules
return this.$store.state.teachers.f01;
},
简化代码,减少重复和冗余
// 使用之前,需要从 vuex 中引入辅助函数
import { mapState } from "vuex";
// 使用 mapState 辅助函数之后,一行代码即可获得所有的状态
...mapState(["stu1", "stu2"])
前台: 游客、用户能看到的界面
后台: 游客和用户不能够看到的页面,管理员界面,如外卖商家添加商品的界面
前后 与 后台 都是属于 前端的
前端: 就是客户端 ,用HTML CSS JavaScript写的直接看到的界面。如果是三层架构,那就是界面表现层
后端: 就是服务端 ,处理逻辑的处理数据的,如果是三层架构,就是业务逻辑层和数据访问持久层
是一个后台前端解决方案,基于 vue 和 element-ui实现,使用了最新的前端技术栈
内置了 i18 国际化解决方案,动态路由,权限验证,提炼了典型的业务模型,提供了丰富的功能组件
build 构建相关
mock 项目mock 模拟数据
plop-templates 基本模板
public 静态资源
favicon.ico favicon图标
index.html html模板
src 源代码
api 所有请求
assets 主题 字体等静态资源
components 全局公用组件
directive 全局指令
filters 全局 filter
icons 项目所有 svg icons
lang 国际化 language
layout 全局 layout
router 路由
store 全局 store管理
styles 全局样式
utils 全局公用方法
vendor 公用vendor
views views 所有页面
App.vue 入口页面
main.js 入口文件 加载组件 初始化等
permission.js 权限管理
tests 测试
.env.xxx 环境变量配置
.eslintrc.js eslint 配置项
.babelrc babel-loader 配置
.travis.yml 自动化CI配置
vue.config.js vue-cli 配置
postcss.config.js postcss 配置
package.json package.json
实现页面之间的进行跳转,
路由和侧边栏是组织起一个后台应用的关键骨架。
路由的写法:
{
path: 'index',
name: 'Stu',
component: () => import('@/views/stuboard/index'),
meta: { title: 'Stu', icon: 'form', breadcrumb: false,affix: true,noCache: true },
}
路由的配置项目:
当设置 true 的时候该路由不会在侧边栏出现
hidden: true // (默认 false)
当设置 noRedirect 的时候该路由在面包屑导航中不可被点击
redirect: 'noRedirect'
可以设置 alwaysShow: true,这样它就会忽略之前定义的规则,一直显示根路由
alwaysShow: true
处理流程
UI 组件交互操作
调用统一管理的 api service 请求函数
使用封装的 request.js 发送请求
获取服务端返回
更新 data
统一的请求处理都放在 @/api 文件夹中,并且一般按照 model 纬度进行拆分文件
通过环境变量设置多个 baseURL,从而请求不同的 api 地址
功能:
添加标签
复制 *admin* 项目中的文件
修改文件
传统的前后端不分离的开发中,权限管理主要通过过滤器或者拦截器来进行
权限管理框架本身通过过滤器来实现功能
前端所有的菜单显示或者隐藏目的不是为了实现权限管理,而是为了给用户一个良好的体验,不能依靠前端隐藏控件来实现权限管理,即数据安全不能依靠前端。
真正的 数据安全管理 和 权限校验 是在后端实现的,前端则是起到了辅助作用,只要是为了提高用户体验**
流程:
用户登录成功之后,可以查询到用户的角色,
再根据用户角色去查询出来用户可以操作的 资源,
然后把这些可以操作的资源,组织成一个 JSON 数据,返回给前端,
前端再根据这个 JSON 渲染出相应的菜单。
在前端把所有页面都在路由表里边定义好,然后在 meta 属性中定义每一个页面需要哪些角色才能访问
仅用于简单的项目,
弊端:
菜单和角色的关系在前端代码中写死,不方便日后调整
提升突破权限的门槛,手动输 url、控制台发请求、开发者工具改数据这种级别的入侵可以防范掉
过滤越权请求,减轻服务端压力,不该发的请求干脆就让他发不出去
提升用户体验,避免在界面上给用户带来困扰
所有的请求发起都触发自前端路由或视图
路由方面:
用户登录后只能看到自己有权访问的导航菜单,也只能访问自己有权访问的路由地址,否则将跳转 4xx 提示页
视图方面:
用户只能看到自己有权浏览的内容和有权操作的控件
请求方面:
最后再加上请求控制作为最后一道防线,路由可能配置失误,按钮可能忘了加权限,这种时候请求控制可以用来兜底,越权请求将在前端被拦截。
比模板更接近编译器,减少模板的代码冗余
通过 render 函数来实现渲染函数
Vue 的 执行流程:
首先是模板通过编译生成 AST,
再由 AST 生成 Vue 的 render 函数(渲染函数),
渲染函数结合数据生成 Virtual DOM 树,
Diff 和 Patch 后生成新的 UI。
解释:
模板: Vue 的模板基于纯 html 和 Vue 的模板语法,我们可以比较方便地声明数据和 UI 的关系。
AST: AST 是 Abstract Syntax Tree(抽象语法树)的简称,Vue 使用 html 的 Parser 将 html 模板解析为 AST,并且对 AST 进行一些优化的标记处理,提取最大的静态树,以便更快的生成 Virtual DOM。
**渲染函数:**渲染函数是用来生成 Virtual DOM 的。Vue 推荐使用模板来构建我们的应用界面,在底层实现中 *Vue* 会将模板编译成渲染函数,当然我们也可以不写模板,直接写渲染函数,以获得更好的控制。
**Virtual DOM:**虚拟 DOM 树,Vue 的 Virtual DOM Patching 算法是基于 Snabbdom 的实现,并在些基础上作了很多的调整和改进。
**Watcher:**每个 Vue 组件都有一个对应的 watcher,这个 watcher 将会在组件 render 的时候收集组件所依赖的数据,并在依赖有更新的时候,触发组件重新渲染。
函数被调用的时候就会渲染并且返回一个虚拟 *DOM* 的树。
当重新进行渲染之后,会生成一个新的树,将新的树与旧的树进行对比,就可以最终得出应施加到真实 *DOM* 上的改动。最后再通过 *Patch* 函数施加改动。
Server Side Render 服务器端渲染
就是服务端渲染好 html 字符串直接返回给前端浏览器展示
前端发送请求,服务端完成 html 字符串的渲染直接返回给前端,每个页面的请求都如此,浏览器拿到的是全部的 dom 结构,开发模式上前后端不分离
Single Page App 单页,整个项目就一个html页面,通过 js 去监听地址栏的变化来实现页面的dom切换
客户端向服务端发送url请求,服务端返回html空壳,客户端再加载JS ,然后向服务发送AJAX请求,拿到服务端返回的json以后,再将其渲染在页面上。
后端渲染出完整的首屏 dom 结构返回,前端拿到的内容包括首屏及完整 spa 结构,应用激活后依然按照 spa 方式运行。
客户端向服务端发送url请求,服务端通过url ,确定要展示的组件并返回,返回有内容的HTML(首屏),客户端拿到后展示页面,激活spa。
优点:
在服务端生成对应的 html 字符串,客户端接收到对应的 html 字符串,能立即渲染 dom,这可以将首屏耗时降到最低。
更好的 SEO (搜索引擎),服务端直接生成了对应的 html 字符串,对 SEO 也非常友好,因为搜索引擎爬虫抓取工具可以直接查看完全渲染的页面。
更快的内容到达时间,无需等待所有的 JavaScript 都完成下载并执行,才显示服务器渲染的标记,可以产生更好的用户体验
缺点:
开发条件所限,一些外部扩展库(external library)可能需要特殊处理,才能在服务器渲染应用程序中运行
涉及构建设置和部署的更多要求,服务器渲染应用程序,需要处于 Node.js 的服务器运行环境
更多的服务器端负载
是一个 Vue 的通用框架,最常用的就是用来做 SSR(服务器端渲染)
补充:next.js ,是一个用于 生产环境的 React 框架
.nuxt Nuxt自动生成,临时的用于编辑的文件,build
assets 用于组织未编译的静态资源入LESS、SASS 或 JavaScript
components 用于自己编写的Vue组件,比如滚动组件,日历组件,分页组件
layouts 布局目录,用于组织应用的布局组件,不可更改。
middleware 用于存放中间件
pages 用于存放写的页面,我们主要的工作区域
plugins 用于存放JavaScript插件的地方
static 用于存放静态资源文件,比如图片
store 用于组织应用的Vuex 状态管理。
.editorconfig 开发工具格式配置
.eslintrc.js ESLint的配置文件,用于检查代码格式
.gitignore 配置git不上传的文件
nuxt.config.json 用于组织Nuxt.js应用的个性化配置,已覆盖默认配置
package-lock.json npm自动生成,用于帮助package的统一性设置的,yarn也有相同的操作
package.json npm包管理配置文件