# Vue后台管理端2 **Repository Path**: HuanRi/vue_manager2 ## Basic Information - **Project Name**: Vue后台管理端2 - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2019-01-09 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ### Day1 #### 项目前期准备 ##### 1、检查是否有安装nodejs npm -v ##### 2、安装Vue-cli3.0 npm install -g @vue/cli ##### 3、初始化项目: vue create <项目名> ##### 4、vue.config.js配置 项目路径下新建vue.config.js ·由于前端应用和后端服务器没有运行在同一个主机上,所以需要在开发环境下将 API 请求代理到 API 服务器。可以通过 vue.config.js 中的 devServer.proxy 选项来配置。 ##### 5、了解项目的结构 图 1网上资料图,仅供参考 注:特别说明 ###### 5.1 src文件 src:放置组件和入口文件。 assets:主要存放一些静态图片资源的目录。 components:这里存放的是开发需要的的各种组件,各个组件联系在一起组成一个完整的项目。  router:存放了项目路由文件。  App.vue:是项目主组件,也是项目所有组件和路由的出口,之后它会被渲染到项目根目录的 index.html 中显示出来,我们可以在这里写一些适合全局的css样式。 main.js:入口文件,引入了vue模块和app.vue组件以及路由router,我们需要在全局使用的一些东西也可以定义在这里面。             ###### 5.2 static文件 static: 存放的是项目的静态文件,用于存放需要使用的一些外部的js、css文件,需要使用的时候从这里引到文件内。 (这里主要是区分一下与assets的存放意义的异同点)。 #### 6、安装ElementUI npm i element-ui -S ### Day2 router 路由插件 ##### 1、router安装 npm i vue-router -S ##### 2、路由的定义 ###### (1)创建router.js ###### (2)路由的定义 创建router.js ( 最好是放在router文件夹下 ); Router.js 内容配置如下: ###### (3)路由的应用 在 main.js 引入定义好的路由,并在vue例子中扩展 至此,路由的定义便以完成,在组件模板中,便可以使用这些路由。 例如: 首页1 首页2 router-view 是路由出口,点击不同的路由link,就会在router-view中替换成对应的组件内容。 ### Day3 ##### Axios的重封装 ##### 1、引入axios   npm install axios ##### 2、新建axios.js 新建axios.js,可放置在util文件夹中(公共工具文件夹); ##### 3、重封装axios.js ### Day 4 ##### Login页面的布局 ##### 1、安装sass-loader依赖包 npm i --save-dev sass-loader npm i --save-dev node-sass (注:sass-loader依赖于node-sass ) ##### 2、安装vuex状态管理模式 npm i --save-dev vuex (注:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。 它是集中式存储管理应用的所有组件的状态。) ##### 3、引入静态文件 本地静态资源我们一般放置在assets文件夹下,一般放置的资源是图片资源或其他资源文件(css/sass之类的)。 ##### 4、编写公用js工具 (1)昨天封装过的axios.js (2)用于处理公共配置的config.js (3)扩张elementUI的提醒组件:plugin.js ##### 5、编写状态管理模块 store.js 在views下新建store文件夹,并创建store.js 。 ###### (1)vuex的概念(官方)   Vuex 应用的核心就是 store(仓库),store包含着的应用中大部分的状态 (state) 。 Vuex 和单纯的全局对象有以下两点不同: 1、Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中 的状态发生变化,那么相应的组件也会相应地得到高效更新。 2、不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。 ###### (2)具体例子如下: 注: 每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler),这个回调函数就是我们实际进行状态更改的地方并且它会接受 state 作为第一个参数。 ###### (4)修改status Commit的第一个参数是调用的方法,根据mutation 中是否有定义而定。 例如:store.commit(‘ACTIVE_NAV’,module); (1)第一个参数是为mutations 中定义的ACTIVE_NAV方法; (2)第二参数是为ACTIVE_NAV方法中定义的第二个参数进行传参。 ###### (5)在main.js中写是否已登录判断,如上图所示。 ##### 6、编写login.vue ### Day 5 #### 系统首页布局 ##### 1、vue-cli3 一直运行 /sockjs-node/info?t= 解决方案(假设有出现)  sockjs-node 创建了一个低延迟、全双工的浏览器和web服务器之间通信通道。 vuecli3 运行 npm run serve 之后 network 里面一直调一个接口:http://localhost:8080/sockjs-node/info?t=1462183700002 由于本项目没有用到 sockjs,需要关闭这个调用: 1. 找到/node_modules/sockjs-client/dist/sockjs.js  2.找到代码的 1605行   try { // self.xhr.send(payload); 把这里注掉 } catch (e) { self.emit('finish', 0, ''); self._cleanup(false); } 3.重启服务。 ##### 2、index页面分析,拆分模块 根据页面元素布局,我们可以讲页面分为三个模块拆分,分别是一级头部导航栏,二级侧边菜单栏,以及三级的内容展示区域; 拆分完成,思考怎样将这三级进行联动(点击一级导航栏,二级菜单栏变化,点击二级菜单,内容对应变化。) 思路: 1:根据二级路由的概念,我们可以利用router-link结合router-view来实现父级与子级之间对应内容的转换; 但是这里有三级, 1、如果将导航栏作为router-link ,router-view就只能是侧边菜单栏,那么内容展示怎么办,这条路走不通; 2、Ok,转换思路,从后往前走,如果我将内容展示区作为router-view,菜单栏就要作为router-link,那么问题来了,导航栏怎么办?我们怎么操作才能将导航栏与菜单栏关系起来,可以用点击事件监听吗?好像可以,点击导航栏时设置路由的导航守卫。 Ok,走得通,选中设计思路2。 ##### 3、设计二级路由 参考day2的内容 ##### 4、设计导航栏与菜单的级别关联 (1)于util文件夹下新建nav.js,设计这个的目的是因为,我们可以将所有数据在一个文件中展示,方便管理,若后期有增删模块,可直接在这个文件中增删。例如后期我们会做到商品模块,我们只要开发好商品的相关component组件,在这个文件中增加商品的导航数据即可,而不需在index组件中修改了。 具体内容如下: ##### 5、设计index页面 ###### (1)template ###### (2)Js <1>、在computed计算属性中: menu事件是为了时时改变menu的值; <2>、在methods中定义: switchNav事件是监听导航栏的点击事件,并将改导航项的默认路由进行跳转。 ###### (3)在main.js中设置导航守卫 至此,便实现了三级菜单的动态转换。 ### Day 6 组件 (以分页元素为例子) #### 1、 注册组件 组件的注册分为两种:全局注册及局部注册,一般我们是使用局部注册。 为了让组件更加通用,生产上我们一般采取的是组件注册是,创建一个component管理目录,将每个组件放置在此文件目录下。当模块系统(即vue模块)需要注册时,使用import或者require导入所需的组件,再使用components属性注册。 #### 2、定义组件(以分页pagination组件为例) ##### <1>、创建 在src目录下,创建components管理目录,再创建具体组件(pagination.vue) ##### <2>、布局及样式渲染(略,就是普通的template+css) ##### <3>、父组件向子组件传递数据: 父组件通过v-bind 动态绑定数据,子组件使用Prop接收。 图 2 子组件使用props属性接收数据 图 3 父组件使用v-bind动态绑定数据 注:父组件绑定的变量名(即冒号后的名称)需要和子组件的声明的变量一致(即props中定义的变量)。如父组件使用:isBatch,则子组件的props定义的变量需为isBatch。 ##### <4>子组件向父组件传递数据 子组件通过v-on绑定事件监听,使用 $emit 来传送数据;父组件监听子组件定义的事件即可接收子组件传递过来的数据。 注: $emit( eventName, […args] ) : $emit 的第一个参数是事件名,第二个参数是所需传递的数据。 具体如下: #### 3、组件实现具体效果如下: 注: 组件编辑完成后并且逻辑功能正常,但是出现了样式问题的话,可在main,js中添加: import './assets/css/element-variables.scss' 这是elementUI的分页样式设置。 element-variables的内容如下: $--color-primary: #5BC0BF; $--font-path: '~element-ui/lib/theme-chalk/fonts'; @import "~element-ui/packages/theme-chalk/src/index"; (剩下一个subTitle组件可以根据这套流程进行练习!) ### Day 7 #### 数据对接方式 #### 1、采用axios的原因 vue中的$http服务,Vue 原本有一个官方推荐的 ajax 插件 vue-resource,但是自从 Vue 更新到 2.0 之后,官方就不再更新 vue-resource。 目前主流的 Vue 项目,都选择Axios 来完成 ajax 请求,所以搭建vue项目的时候,我们一般用  Axios。 #### 2、axios简介 Axios 是一个基于Promise 用于浏览器和 nodeJs 的Http 客户端。 它本身具有以下特征: · 从浏览器中创建 XMLHttpRequest · 从 node.js 发出 http 请求 · 支持 Promise API · 拦截请求和响应 · 转换请求和响应数据 · 取消请求 · 自动转换JSON数据 · 客户端支持防止 CSRF/XSRF #### 3、axios的使用 axios并没有install 方法,所以是不能使用vue.use()方法的。 为了让页面共用,而不需要每个文件都import,通常有三种方式: · 结合 vue-axios使用 · axios 改写为 Vue 的原型属性 · 结合 Vuex的action ##### (1)vue-axios使用 首先在主入口文件main.js中引用 之后就可以使用了,在组件文件中的methods里去使用了 ##### (2)axios 改写为 Vue 的原型属性(此次项目采用的是这种) 首先在主入口文件main.js中引用,之后挂在vue的原型链上 在组件中使用 ##### (3)Vuex的action(这种较少用到) 在vuex的仓库文件store.js中引用,使用action添加方法: 在组件中发送请求的时候,需要使用 this.$store.dispatch #### 4、例子:以请求登录接口为例子。 ##### (1)设置proxyTable实现跨域请求 由于我们开发时一般是本地开发组件页面,而数据是放置于服务器应用上的,本地的局域网想要请求线上(不管是正式还是测试)服务器,都是存在跨域请求的问题。所以需要利用webpack的proxyTable 来代理服务器。具体的做法可参考 Day1 的第 4 点 。 ##### (2)登录接口请求事件设计 ### Day 8 #### ElementUi的使用 #### 1、简介 目前对vueJs开发应用比较热门的开源UI框架主要有两个,ElementUi和iView。 本次主讲ElementUI。它是由饿了么前端团队推出,生态环境较 iView 而言更加系统(暂时);它的组件也很全面,基本适用于普遍的PC管理端系统。 #### 2、安装 习惯使用 npm 安装: npm i element-ui -S #### 3、引入ElementUI 在项目入口文件main.js中编辑:(完整引入) 注:由于我们需要自定义主题,所以在这里不需要引入element的css文件。 #### 4、自定义主题 ElementUI提供的默认主色是淡蓝色,这是ele的前端主色,一般我们自己的项目有自己的主色要求,所以需要自定义主题。 ##### (1)在assets目录的css文件夹下,新建一个样式文件(element-variables.scss): $--color-primary: 这个是定义主题色的变量 ; $--font-path :这是改变 icon 字体路径的变量,是必需项,一般默认为 ('~element-ui/lib/theme-chalk/fonts' ); @import 的这个导入主题样式 ; ##### (2)在main.js 中直接引入创建好的样式文件即可。 #### 5、表格布局(使用el-table) 1、v-loading:是用来做数据加载时的友好样式的; 2、:data:是绑定table的动态数据; 3、Cell-style:是用于定义表格行头和行的样式; 4、Column中使用solt 插槽的原因是:我们引用的是 Element 封装好的table组件, 这里相当于一个父组件,数据的获取需要从子组件数据中获得,所以使用了solt。 #### 6、message消息提示的使用 这里我们按需引入就好,因为主要是用于数据请求时的返回提示,我们已经将axios重封装了,只需在axios,js文件或者其他有用到的地方按需引入。 它调用方法为 Message(options),也可以使用type定义的方法。 例如在我们这次项目使用的是error主题type,可直接写 Message.error(“错误信息!”); 。 注:1、其他的组件就不一一详细介绍了,可参考官方文档 (http://element.eleme.io/#/zh-CN/component/installation ) 2、具体写法可参考 /index/conLog ,登录日志的应用。 ### Day 9 #### 商品模块的应用 #### 1、路由的导航守卫 通常情况下,我们做路由跳转时是需要做一下验证判断的,例如是否已登录验证,这是就出现了路由导航守卫的概念。顾名思义,就是路由跳转(路由正在发生改变)时起保护作用,只有执行了守卫中的验证判断才能继续后续操作。 ##### (1)导航守卫的方式:有三种。 官方文档链接: https://router.vuejs.org/zh/guide/advanced/navigation-guards.html#%E5%85%A8%E5%B1%80%E5%AE%88%E5%8D%AB ###### <1>、全局守卫 (官方) router.beforeEach((to, from, next) =>{}) :全局前置守卫 router.beforeResolve((to, from, next) =>{}) :全局解析守卫 router.afterEach((to, from) =>{}) :全局后置钩子 每个守卫方法接收三个参数: to: Route: 即将要进入的目标 路由对象 from: Route: 当前导航正要离开的路由 next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。 next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。 next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。 next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。可以向 next 传递任意位置对象,且允许设置诸如 replace: true、name: 'home' 之类的选项以及任何用在 router-link 的 to prop 或 router.push 中的选项。 next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。 ###### <2>、路由独享的守卫 在路由配置上直接定义 beforeEnter 守卫。 ###### <3>、组件内的守卫 在路由组件内直接定义以下路由导航守卫。 做导航守卫还有另外一个目的,由于本次项目的菜单目录是三级,需要实时更新菜单之间的联动性。 如果不做导航守卫的话,在点击页面按钮进行路由跳转是可以正常地处理菜单之间的联动,因为我们做了点击监听事件 ;但是当我们人为地使用浏览器的回退按钮,这时我们没有做浏览器回退的监听事件,一级导航栏的nav 状态是监测不到的,又由于浏览器路径上的路由已经发生了变化,就会出现一级导航未正确跳转到,而二级菜单router-link和三级内容router-view却是正确显示。 此次项目中使用的是全局守卫中的全局前置守卫router.beforeEach,具体操作是:在入口文件main.js 中,引入router插件,并编写router.beforeEach的执行逻辑,主要是为了做用户登录验证操作。如下图所示: #### 2、商品模块具体应用(以商品列表为例) ##### (1)创建模块组件文件 为了方便后期维护,我们创建项目目录时是根据自身对于产品的理解来进行的。例如此时我们做到商品模块了,那我们就在views 目录下重新新建一个属于商品模块的管理目录goods,不管是商品列表、添加商品还是其他的功能组件,都统一放置在此管理目录下。 以商品列表为例,在goods 管理目录下新建list.vue 文件。如图所示: ##### (2)编辑template ###### <1>、确定页面布局结构 从内容区域展示的页面上来分析,我们大致可以将商品列表页面分为两个大块,头部和body。Body部分又可以分为筛选栏和数据列表。数据列表里又可以细分为表格头部,表格列表和底部分页。所以template 可以设计为: ###### <2>、编辑结构内容 A、头部 头部是公用组件,我们可直接使用components。 B、筛选栏 筛选栏这里有个‘打开筛选’功能,也就是会在筛选栏的下方布局一个筛选内容编辑弹框。 C、表格头部 D、数据表格 表格我们可以使用ElementUi的组件 el-table 来辅助展示。 E、分页 使用我们之前已做好的分页组件。 F、库存编辑弹窗 这是库存编辑的弹窗,可使用ElementUi的el-dialog 组件编辑。 至此,template的布局就可以了。 ##### (3)mixins(混入) 写js前先介绍一下Mixin , ###### <1> 、简介(官方) 混入 (mixins) 是一种分发 Vue 组件中可复用功能的非常灵活的方式。混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被混入该组件本身的选项。 说简单点就是,将可以复用的功能(基本功能是一样)都集合在一起,可复用的对象是任何组件选项,例如data中有变量可复用,就将可复用的变量提取出来处理;methods方法可复用,那也可以提出来。 ###### <2> mixins的使用(以本次项目功能为例子) 将可复用的功能和组件都提取出来,集合在mixin.js 中,并将mixin.js暴露出去。 在具体组件中,用import 引入集成好的 mixin.js ,使用mixins属性定义。 图 4 编辑mixins 图 5 在list.vue中使用mixins ##### (4)编辑js ###### <1>引入组件和功能:使用import ,并做对应的属性定义 注:vue组件的功能和数据选项都需写在export default中!!! ###### <2> 定义data ###### <3>定义mounted 这是vue生命周期的钩子函数,el 在 被 vm.$el(虚拟的Dom)替换,并挂载到实例上去之后调用该钩子。 ###### <4>、定义methods 注: 其他接口: (1)merchantGoods/merchant_goods_put:商品上架接口; (2)merchantGoods/merchant_goods_pull:商品下架接口; (3)merchantGoods/merchant_goods_update_sku:库存信息修改 (4)merchantGoods/delete_batch:商品删除 ##### (5)css样式:使用sass编辑(自定义,这边就忽略不写了) ### Day 10 #### 商品添加|编辑模块 #### 1、原型分析 图 6 添加商品 从原型上看,<添加商品>这个页面有四个选项导航,分别为选择商品分类、填写商品信息、填写商品操作和选择商品关联。 ##### (1)选择商品分类 从上图中,<选择商品分类>总共有二级选项框,只有选择了一级分类,二级分类选项框展示相应的分类内容,再进行二级分类选择。选择完毕,下方提示用户所选择的类别,并提供可进行下一步的操作入口。 ##### (2)填写商品信息 图 7 填写商品信息 <填写商品信息> 头部的导航第二项自动变高亮,并更换为<填写商品信息>的内容,商品信息主要有两块,一为基本信息,二为库存规格。 这里的参数分为两种,一种是必填项,一种为非必填项,必填项需要进行红点标注。若用户不填写必填项便点击了下一步,此时应该阻止下一步的操作,并有必填项的填写提示。 ##### (3)填写商品属性 图 8 商品属性 图 9 属性和参数的相应变化 <填写商品属性> 头部的导航第三项自动变高亮,并更换为<填写商品属性>的内容,商品属性主要有四块,商品属性、商品参数、商品相册、商品详情。 <商品属性> 是一个下拉框选择,<商品参数> 是以表格可填写形式,<商品相册> 分为上传图片和从图片库选择图片,而<商品详情> 则是一个富文本编辑框。 从图8和图9可看出,当选择商品类型时,<商品属性> 中的商品规格是动态出现;<商品参数>的填写内容是动态变化的;选择<商品规格>中的添加。 ##### (4)选择商品关联 图 10 商品关联 <商品关联> 为一个非必填项,主要是可以选择商品关联的类目,若需要关联类目,则需要选择两级类目。 #### 2、页面设计 图 11 页面设计 从1中的原型分析中,我们可将<商品添加>分为两个大模块,一个是头部的导航条,一个是内容变化展示区域。 头部的导航条,可利用ElementUI的el-steps 组件来实现,使用el-steps的active 属性来控制高亮区域。 内容展示区域分别有四个内容,由于不是一次性呈现,所以可以使用v-if 来控制内容的展示,这里我们定义了一个 stepActive 来区分步骤。 ##### (1)选择商品分类 图 12 选择商品分类页面设计 这里主要是v-for 以及 v-if的联合使用,就不过多讲解。 ##### (2)填写商品信息 图 13 填写商品信息页面设计 这里我们使用ElementUI 的 Form表单组件。使用el-form 和 el-form-item的组合形成表单。 主要是运用Form的两个属性: · model:表单数据对象; · rules :表单验证规则。 ##### (3)选择商品属性 这块主要介绍下富文本编辑器的应用。富文本用的是 Vue-Quill-Editor 。 ###### <1> 下载Vue-Quill-Editor插件 npm install vue-quill-editor --save ###### <2> 下载quill(Vue-Quill-Editor需要依赖) npm install quill --save ###### <3> template 如上图所示。 · quill-editor V-model :是将富文本编辑器中的编辑内容 保存在表单对象中; :options :是修改编辑器功能的默认值 · el-upload 这是ele的文件上传,使用这个的原因是通过富文本编辑器上传的图片是base64的格式 ,需要将其上传至后台服务器,通过后台的处理转换成图片链接。 ###### <4> js 设计 ~1、mian.js 全局引入:由于富文本编辑器多处用到,所以这里使用了全局引入quill-editor; 如果非多处用到,可使用局部引入。 ~2、组件内定义 ~2.1 定义 quill-editor ~2.2 定义el-upload ##### (4)选择商品关联 #### 3、js设计 ##### (1)模块引入 关于事件的监听和控制可以参看上传的代码,代码已重新更新至gitee。 ### Day 11 #### Vuex 的学习 源码分析到此就告一段落了,因为后面的应用基本都是表格数据,跟前面的index和goods 模块类似,可以借鉴参考,有问题的话可以提问,源码已经上传至gitee。 接下来几节会回归到一些比较重点的知识点学习。 #### 一、简介 Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。(官方) 简单来说,它就是使用一个 store 对象来包含所有的应用层级状态,也就是数据的来源,它是一个组件外部状态管理。 “所有组件的状态”,这个其实是组件中data里的属性。在一般的组件间传输数据,我们会采用props,但是这种处理方式在“非父子组件”和“父组件与后代组件”之间需要使用同一个数据变量时,是比较冗余繁琐的,所以这个时候就需要使用vuex 来将组件使用到的状态进行统一管理。 #### 二、使用场景 ##### (1)多个视图(即组件)依赖于同一个状态; ##### (2)来自不同视图的行为需要变更同一状态。 对于(1),使用props 传参的方法对于多层嵌套的组件(即父组件与后台组件)有些繁冗,而且面对兄弟组件(即非父子组件)间的状态传递是无法使用的。 对于(2),如果不使用vuex,一般的做法是通过事件监听来获取达到状态的同步和变更。 对于这两种方式,一旦逻辑的某一步发生错误,或者某一步需要进行变换逻辑时,代码的维护将变得很臃肿和脆弱。 所以,我们需要将组件的共享状态进行提取,用一种全局单例的模式进行管理,这就产生了vuex了。 #### 三、Vuex的属性(Vuex核心) Vuex的属性我们一般概括为四个: · State:单一状态树; · Getter:可认为是store的计算属性(类似computed); · Mutation:更改store的提交方法; · Action:类似于 mutation。 注:vuex的安装可参考上文Day 4的内容。 ##### 1、State State上存放的,简单而言就是变量(也就是所有组件的状态)。 Vue组件中使用state有以下三种方式: ###### (1)直接使用$store.state.xxx (不推荐) 图 14 定义Vuex 图 15 使用state ###### (2)通过组件中computed计算属性直接赋值 图 16 通过computed计算属性赋值 ###### (3)通过mapState 辅助函数 通过computed属性可以获取到状态值,但是组件中的每个属性都是函数,假设组件中需要N个状态值,那么就需要写N个函数,函数中重复写 return this.$store.state,代码写起来有点重复,所以当组件中需要用到多个计算属性的状态值时,可以借助vue提供的mapState函数,它会把state直接映射进组件中。 mapState有两种用法,一种是接受对象,一种是接受数组。 图 17 mapState接受一个对象 图 18 接受一个数组 ##### 2、Getters Getters 简单来说就是存放一些公共函数供组件调用。 Getters 会暴露为store.getters 对象,所以可以通过store.getters.xxx 来让组件调用。 像这次项目中,index组件中的状态值获取便是根据Getters获取的。 图 19 通过getters获取状态值 ##### 3、Mutations Mutations 与事件类似,它存放的是一般我们需要改变state的方法; 更改Vuex的store 中的状态值的唯一方法是提交mutation。 例如,我们在本项目中store.js 定义Mutations,里面的方法接受两个参数,一个是state,一个是组件通过commit 传递的形参。 ##### 4、Action mutation 像事件注册,需要相应的触发条件。而 Action 就那个管理触发条件的。 Action 提交的是 mutation,而不是直接变更状态。 Action 可以包含任意异步操作。 ###### (1)注册一个简单的Action: Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此可以调用context.commit 提交一个mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters。 ###### (2)使用ES6 的参数解构简化代码 ###### (3)分发 action 分发action 就是 给定某个动作来进行触发action。 Action 通过 store.dispatch 方法触发。它有两种写法: · 在组件中使用 this.$store.dispatch('xxx')  来分发action ; · 使用 mapActions 辅助函数将组件的 methods 映射为 store.dispatch 调用 图 20 网络图片 ### Day 12 #### Vue 的深入了解 #### 1、Vue.js的数据驱动原理 根据官方文档介绍: · Vue.js 是一个构建数据驱动的web界面的框架; · Vue.js 的目标是实现响应的数据绑定和组合的视图组件; · Vue.js 的核心是一个响应的数据绑定系统。 这个介绍中,我们发现 Vue.js 是一款轻量级的以数据驱动的前端JS框架,这个和我们以前用的JQuery最大的不同就是:JQuery 是通过操作DOM来改变页面的显示;而Vue 是在一个的虚拟DOM通过操作数据来实现页面的更新。 图 21 Vue 数据驱动的概念模型 从模型图中可看出,Vue基于MVVM的一个框架。 · M:是Model层,也就是JS逻辑层; · V :是View层,也就是DOM层 ; · VM: 是ViewModel,是数据中间件。 上图中,Vue主要负责的就是绿色方块的ViewModel部分, 在View层与Model层之间通过ViewModel, 其绑定了 DOM Listeners 与 Data Bingings 两个类似监听器的东西,进行数据处理后对view和Model层双向传递; ViewModel层的DOM Listeners 监听到 View 的数据有变化时,就会通知Model层并将data 传递给Model并处理数据; 相反,Model层数据发生改变理后,通过VM的Data Bindings 来监听并渲染进View层。这样VM就实现了数据的双向绑定功能,也就是我们常说的Vue的data是双向响应的。 #### 2、Vue实例 图 22 Vue 实例 通过new Vue() 可以构建一个Vue的实例。 在实例中,包含挂载元素(el)、数据(data)、模板(template)、方法(methods)和生命周期钩子(created)等等。 · el:表明Vue需要操作的元素区域,例如 ”#demo” 表示要操作Id 为demo的元素下的区域; · data:它表示Vue实例的数据对象,只有在data中声明的数据才能够实现数据的响应变化,在data外定义的数据是不具备响应数据变化的; #### 3、v-model指令 在vue.js 中,指令是最关键的一环,常用到的指令有: v-if、v-for、v-show、v-text、v-html、v-on、v-bind、v-model等等。 这里我们挑v-model数据绑定指令来讲。 ##### (1)v-model 解析过程 v-model 最常见的用法是可以将指定的data对象中的属性绑定到一个form元素中: 从上图中,我们在data 对象中创建了一个text属性,在标签中使用 v-model 绑定到 text ,这时输入框会和 text属性进行同步。当修改input 中的值,text属性会随之改变,并将这个改变绑定到元素的value 值上。 它的内部原理其实是使用了 html5 的oninput 事件,我们试着将上面的代码处理成传统html5 写法,可以表示为: Vue就是这样通过v-model的解析,在@input 事件中设置响应,在响应中修改text 的值,再通过绑定属性v-bind 绑定同步value值。 ##### (2)v-model 绑定组件 V-model 不仅可以绑定form 元素,它还可以绑定组件: 从代码中,我们使用vue-component定义一个组件,叫demo-el , 它接受一个prop 属性,接收的是value,但是我们在中并没有定义value属性,这是为什么。 根据(1)中的分析,我们可以将看成: 所以,v-model解析demo-el 时,绑定的就是value 属性,传入组件用props接受的就是value了。 #### 4、VueJs的技术栈 构建中大型项目的时候,我们一般不使用直接在html中引入Vue.js 的cdn来写代码,所以我们用到了Vue提供的相关技术栈来构建前端项目。 图 23 构建项目的技术栈 · vue.js · vue-cli : Vue的脚手架工具,用于自动生成Vue 项目的目录和文件; · vue-router : Vue的前端路由工具,可以实现页面的路由控制,局部刷新及按需加载,构建单页面应用。 · vuex:Vue提供的状态管理工具,用于统一管理项目中的各种数据的交互和重用,存储需要用到的数据对象。 · ES6: ECMAScript6,利用它可以快速实现js逻辑; · NPM: node.js的包管理工具,用于统一管理前端项目中需要用到的包、插件、工具及命令等; · webpack: 文件打包工具,将前端项目统一打包压缩到js中,并可通过vue-loader等加载器实现语法转化和加载; · Babel : 是将ES6 代码转化为浏览器兼容可读取的ES5 代码 的插件。 未完待续! ### Day 13 #### Vue 的深入了解2 #### Vue的生命周期 #### 1、前言 Vue的生命周期在初学vue文档时都会碰到,初学时我们一般都是冲冲略过,又或者是不清楚其中真正的意义。Vue的生命周期不仅仅是那几个生命周期钩子函数,也不是简简单单的创建--> 挂载 --> 更新 ---> 销毁 如此简单。 为什么要学习Vue的生命周期,不仅是对于我们对于Vue的生态更加了解,在开发项目时,更好地的利用Vue的生命周期来编写合适的操作代码;更为重要的,面试的时候,资深的面试官很喜欢面试者对于Vue生命周期的回答来判断对于Vue的理解程度! #### 2、Vue的生命周期 图 24 vue生命周期流程图注解 ##### (1)Vue启动应用,需要创建一个实例,在 new Vue() 的对象过程当中,首先执行了init ,这是vue 组件默认执行的,在init 的过程中首先调用了beforeCreate,之后在 injections (注射) 和 reactivity (反应性)的时候,它再去调用created 。 所以,在init 时,时间已经调用了,我们在beforeCreate 的使用不能修改data中的属性,修改data 的属性值需要去created 中去执行; ##### (2)当created 完成之后,Vue 会判断instance(实例)里是否含有 “el” option(元素选项),如果没有,它会调用vm.$mount(el) 这个方法,然后执行下一步;如果有,直接执行下一步。 之后,会判断是否含有”template”这个选项,如果有,它会把template 解析成一个 render function ,这是一个template 编译的过程,结果会解析成 render函数: render 函数里面的传参h 就是Vue 里面的createElement 方法,return 返回一个createElement 方法,其中需要有三个传参: ·第一个参数是创建的元素标签; ·第二个参数是一个对象,里面可以是组件的props、事件之类的东西; ·第三个参数是标签中的内容,就是data中的属性内容; ##### (3) reader函数是发生在beforeMount 和 mounted 之间的,说明在 beforeMount 时,$el 还只是在HTML 里写的节点,但当到了mounted时,它就把渲染出来的内容挂载到DOM节点上了。这中间的过程其实是执行了 render function 的内容。 在使用 .vue文件开发的过程中,其中写了template 模板,在经过 vue-loader的处理之后,就变成了render function ,最终放到了 vue-loader 解析过的文件里面。这是由于解析template 变成 render function 的过程中,是一个很耗时的过程,vue-loader帮我们处理了这些内容之后,当我们在页面上执行vue 代码时,效率会变高。 beforeMount 在有了 render function 的时候才会执行,当执行完 render function之后,就会调用 mounted ,在mounted 挂载完毕之后,这个Vue实例其实已经走完了; ##### (4)后续的钩子函数执行的过程是需要外部的触发才会执行。例如: · 当数据有变化时,会调用beforeUpdate ,经过Virtual DOM ,最后updated 更新完毕; · 当组件销毁时,它会调用beforeDestroy和destroyed。 这就是vue实例从新建到销毁的一个完整流程,以及在这个过程中它会触发哪些生命周期的钩子函数。 钩子函数,其实和回调是一个概念,当系统执行到某处时,检查是否有hook,有则回调。说的更直白一点,每个组件都有属性,方法和事件。所有的生命周期都归于事件,在某个时刻自动执行。 ### Day 14 #### Vue的计算属性 #### 为什么要学习计算属性? 我们有内联表达式,有methods定义的方法,有watch 侦听数据变化,我们拥有如此多的手段来判断数据发生变化时让数据产生对应的结果,为何还要学习computed 计算属性?原因,我们来一一对比: ##### 1、计算属性与内联表达式 我们以字符串反向输出来做解释。 图 25 内联表达式 上图中,我们在div 中写了内联表达式,当textValue 发生变化时,div中的内联表达式变回开始计算,将textValue 进行反写操作。 这样看起来好像很方便,但是,我们要知道,这种只适用于简单的逻辑处理, 一旦我们的代码量很大或者需要多处用到这种计算方式,这样写内联表达式就会让我们的项目变得很臃肿和不好维护。 所以,对于任何复杂的多复用的逻辑,我们可适当使用计算属性computed。 ###### (1)computed 计算属性是用来声明式的描述一个值依赖了其他的值,当依赖的值发生变化时,其值才会的发生更改并更新相关的DOM 。 其结果如下图,当文本框中的值发生变化时,计算属性的值也发生了相应的的更改并触发DOM更新: ###### (2)computed 的 getter 计算属性默认只有 getter ,用于获取依赖值并做相应处理;不过,我们也可以根据需要提供一个setter 。 上图中,如果我们要提供setter,那么便不能写默认写法(即直接return 返回值),而是应该提供对应的getter和setter。 这里写的setter是初始化 textValue 的值为 传参(message ) + ”--HELLO--” 。 此时,我们可以点击页面button 元素,通过methods中的方法来执行computed 中reversedMessage 的 set方法: 所以,文本框中输入 ‘message’ ,点击set按钮,这时会执行: (1)、methods 中的computedSet方法,将 ’message’ 赋值给reversedMessage (2)、计算属性reversedMessage先执行set方法,得到(message--HELLO--),紧接的就会执行get 方法,将(message--HELLO--)进行翻转 ,并更新到DOM中。最终的结果如下: ##### 2、computed 与 methods 利用methods同样可以达到跟computed 一样的改变数据的效果。 可以看出,使用methods 是执行了方法, 那为什么不用methods,而更推荐computed? 这里要说道computed的缓存。 ###### (1)计算属性是基于他们的依赖进行缓存的。只有在相关依赖发生改变时它们才会重新求值。根据上面的例子,也就是说,只有textValue 如果没有发生改动,多次访问reservedMessage 计算属性会返回之前的计算结果,而不会再一次执行函数。 ###### (2)相比的,当页面重新渲染是,调用方法是每次都要执行函数的。这在大型项目需要多次运用改变数据时,会大大增加应用的计算性能 ##### 3、computed 与 watch(侦听属性) 侦听属性:vue的一种更为通用的方式来观察和响应Vue实例上的数据变动。 Watch监听的属性必须是在data中有声明的,不然无法侦听。 当textValue 发生改变时,就会执行watch操作。 computed 与 watch 各有所长,使用情况视实际情节而定 : 当我们所需的数据需要随其他数据变动而改变,并且在数据变化时需要执行异步或者开销较大的操作时,我们更推荐watch,因为watch是在vue实例上进行观察的,而computed是根据data中的依赖而言。