Skip to content

Commit

Permalink
更改多个视图
Browse files Browse the repository at this point in the history
  • Loading branch information
Eyes22798 committed May 29, 2020
1 parent d9a0f0c commit 26451f6
Show file tree
Hide file tree
Showing 77 changed files with 2,338 additions and 865 deletions.
358 changes: 358 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ view 目录中更新不需要写文档
>> 第五次更新 + untils目录 新增 cookieUntil.js 文件 untils.js 文件
>> 第六次更新 + components目录 新增 Loading.vue Snackbars.vue 两个组件
>> 第七次更新 + components目录 新增 Header.vue Footer.vue 两个组件
>> 第八次更新 + components目录 新增 svg-icon 组件
>> 第九次更新 + common目录 新增 ifEmety.js ifLogin.js两个全局方法
>> 第十次更新 + views目录 新增 两个页面
```

## 2. 封装 `axios`
Expand Down Expand Up @@ -815,6 +818,71 @@ export function delCookie (cName) {
};
```

### 3.2 判断表单是否缺省

> form数据格式为数组的情况下
```js
import Vue from 'vue'
// 拿到 Vue 原型上的 $toast 对象
const prototype = Vue.prototype
export function ifEmety (data) {
for (let key in data) {
if (!data[key]) {
prototype.$toast('请完整填写表单', {
x: 'right',
y: 'top',
icon: 'info',
dismissable: false,
showClose: true
})
return false
}
}
return true
}

```

### 3.3 判断是否登录

> 判断localStorage是否有用户信息,没有则提示登录并跳转
```js
import Vue from 'vue'
import router from '@/router'

// 拿到 Vue 原型上的 $toast 对象
const prototype = Vue.prototype

export function ifLogin () {
// 判断是否登录
if (!localStorage.getItem('userInfo')) {
prototype.$toast('请先登录!', {
x: 'right',
y: 'top',
icon: 'info',
dismissable: false,
showClose: true
})
// 跳转到登录页
setTimeout(() => {
router.replace({
path: `/login`,
query: {
redirect: router.currentRoute.fullPath
}
})
}, 1000)
return false
}
return true
}

```



## 4. 路由封装

### 4.1 `Vue.router`介绍
Expand Down Expand Up @@ -1027,3 +1095,293 @@ router.beforeEach((to, from, next) => {
})
```

## 5. vuex

### 5.1 前端模块化

> 在讲解本项目vuex前了解一下原始JS开发中会遇到的问题。特别是大型项目中,我们经常遇到我们需要使用一些全局变量或者全局方法,但想从一个js文件中到另外一个js文件中取值是一个很头疼的事情。
>
+ 命名冲突:如果你在a.js定义了一个`a()`方法或者函数,你想把其引入到b.js使用。但是你不小心也在b.js中写了一个a(),那么问题来了来了这个a()是谁的方法的?

+ ```js
// a.js
<script>
let a = fun => {
console.log('额是a')
}
</script>
```

+ ```js
//b.js
<script src="a.js"></script>
<script>
let a = fun => {
console.log('额是b')
}
a()
</script>
```

+ 输出结果:'额是b'

+ 全局变量污染:同样的道理,如果你在a.js中定义了一个a变量(全局变量),你把a.js引入到了b.js中!然后你又在b.js中定义了一个全局变量a,这个a变量将会是哪里的呢?

+ ```js
// a.js
<script>
let a = '额是a'
</script>
```

+ ```js
<script src="a.js"></script>
<script>
let a = '额是b'
console.log(a)
</script>
```

+ 输出结果:'额是b
+ 文件相互依赖:我们使用jquery插件时,需要先把jquery引入,把jquery.js放到最前面,再把插件放到jQuery的后面
+ ```js
<script src="lib/jquery/jquery.js"></script>
<script src="lib/jquery/jquery.appear.js"></script>
```
解决这几个问题,前端提出了**模块化**的思想。什么是模块化?模块化就是**将一个复杂的系统分解成多个独立的模块的代码组织方式**。
在前端没有正确引入模块化机制前,有很多社区版的模块化方案
+ IIFE(自执行函数)
+ AMD(require.js)
+ CMD(sea.js)
+ ES6(module)
+ 现阶段模块化解决方案
+ Common.js
+ 每个文件就是一个模块,都有自己单独一个作用域。
+ 同步
+ 服务端
### 5.2 vuex作用
> Vuex 是一个专为 Vue.js 应用程序开发的**状态管理模式**。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
>
> 翻译一下:现如今的web应用大多就是操作数据,对数据进行保存、操作和**管理**就是web应用的核心思想。
>
> 那这些数据我们怎么保存呢?全局变量?localstorage?显然这两种方式能够保存数据。那我们也要操作和管理数据怎么办呢?比如后端返回的JSON数据需要我们做一下什么什么预处理,我们想保存数据的同时就做了这些数据处理。如果使用全局变量或者localStorage我们需要写配套的数据处理逻辑,那么问题来了,localStorage里面的内容改了你组件数据会改吗? (可以做一下onStorage监听,恭喜你要做出一个类vuex的东西了)。
>
> 这样的数据有了个100、1000个会怎么办!这里面的数据如果还有的相互依赖我们有会怎么办?那就需要花费大量的时间和精力进行分析封装和管理。
>
> 而Vuex就是把数据和数据处理逻辑全部集中到一个单独的模块管理对象上,让这个对象进行管理。
>
> 此外由于Vue是单向数据流,因为用户一些行为(Actions)导致了数据发生了变化(State),数据驱动页面视图(View)改变,视图更新后又有会有一些行为(Actions)用户可以触发,以此循环。
>
> - **state**,驱动应用的数据源;
> - **view**,以声明方式将 **state** 映射到视图;
> - **actions**,响应在 **view** 上的用户输入导致的状态变化。
>
> ![image.png](http://aliyun.image.eyesky.site/images/2020/05/29/image.png)
>
> 在这种单向数据流的模式下,如果多个组件视图中都依赖同一个状态(state),这个状态(state)改变需要更改多个视图或怎么样?同样的,多个视图的一些行为会更改同一个状态又会怎么样?
>
> 在这种多组件共享状态的情况下,其实Vue中仍然有一些方法可以解决。
>
> 如果一个状态(state)改变需要更改多个视图,可以利用组件传值的方法:就是如果我这里数据发生了改变,我把它传给同时需要这个数据状态的组件,告诉他需要的这个state发生了改变,让其更改视图。
>
> 组件间的传值主要有
>
> + 兄弟组件 ---兄弟组件(bus.js)
> + 父组件---子组件(props down)
> + 子组件---父组件(emit on)
>
> 如果多个视图Actions更改同一个状态,可以利用本地化存储localStorage以及监听或变更和同步多个拷贝状态。
>
> 以上都比较麻烦且不容易维护,所以Vue把这种共享状态分离出来,用一个全局对象状态树管理,这就是状态管理模式Vuex。
本项目的状态管理分为了两个部分,为什么要分为两个部分,因为使用一个状态树想要把状态全部集中起来太过繁琐复杂且臃肿。目录结构如下。
```
.
|-- global
| |-- actions.js
| |-- getters.js
| |-- index.js
| |-- mutation-types.js
| |-- mutations.js
| `-- state.js
|-- index.js
`-- modules // 每个模块都有其对应的 state getters action mutations
|-- disease.js
|-- index.js
`-- pest.js
```
本项目使用vuex主要是为了解决组件传值问题和管理多个组件的共享状态,
+ 全局状态管理 global
+ 局部状态管理
+ 病害
+ 植物
+ 天敌
来看一下store文件夹顶端index.js做了什么事情。
Store是Vuex的一个核心方法(仓库),这个仓库装着你大部分的state。
```js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import vuetify from './plugins/vuetify'
import untils from './common/untils/untils'
import api from './api'
import './assets/icon/index'
Vue.use(api)
Vue.prototype.$untils = untils
Vue.config.productionTip = false
new Vue({
router,
store, // 注入到Vue实例里
vuetify,
render: h => h(App)
}).$mount('#app')
```
new Vuex.Store({}) 表示创建一个Vuex实例,通常情况下,他需要注入到Vue实例里。
Vuex Store是响应式的,当Vue组件从store中读取状态(state选项)时,若store中的状态发生更新时,他会及时的响应给其他的组件(类似双向数据绑定) 而且不能直接改变store的状态,改变状态的唯一方法就是,显式地提交更改(mutations选项)
```js
import Vue from 'vue'
import Vuex from 'vuex'
import state from './global/state'
import getters from './global/getters'
import actions from './global/actions'
import mutations from './global/mutations'
import disease from './modules/disease'
import pest from './modules/pest'
Vue.use(Vuex)
export default new Vuex.Store({
state,
getters,
mutations,
actions,
modules: {
disease,
pest
}
})
```
+ state:Vuex 使用**单一状态树**,用一个对象就包含了全部的应用层级状态。至此它便作为一个“唯一数据源 ([SSOT](https://en.wikipedia.org/wiki/Single_source_of_truth))”而存在。这也意味着,每个应用将仅仅包含一个 store 实例。
+ ```js
import { stroage } from '@/common/untils/strogeUntil.js'
// 引用封装好的 stroage 构造器
const local = stroage.local
// 从 localStorege 中获取用户的详细信息
const userInfo = '' || local.get('userInfo')
// 创建唯一标识判断,判断登录状态
const sessionID = stroage.local.get('JSESSIONID')
// 从注册到登录信息
const namePassword = null
// 分页 name 属性
const pageName = null
export default {
namePassword,
userInfo,
sessionID,
pageName
}
```
+ getter: 有时候我们需要从 store 中的 state 中派生出一些状态
+ ```js
// getters 只会依赖 state 中的成员去更新
const getters = {
userData: (state) => state.userInfo,
sessionID: (state) => state.sessionID,
namePassword: (state) => state.namePassword,
pageName: (state) => state.pageName,
category: (state) => state.category,
diseaseName: (state) => state.diseaseName,
pestDiseaseName: (state) => state.pestDiseaseName,
imageName: (state) => state.imageName,
searchText: (state) => state.searchText
}
export default getters
```
+ mutation: 更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 **事件类型 (type)** 和 一个 **回调函数 (handler)**。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数
+ ```js
import * as types from './mutation-types'
import { stroage } from '@/common/untils/strogeUntil.js'
const mutations = {
// 定义一些突变的方法 如果不通过 commit('SET_ADDRESS', address) 会报错
[types.SET_USERINFO] (state, data) {
try {
state.userInfo = data
stroage.local.set('userInfo', state.userInfo)
} catch (err) {
console.log(`保存用户信息失败,${err}`)
}
},
[types.REMOVE_USERINFO] (state) {
state.userInfo = ''
stroage.local.set('userInfo', state.userInfo)
}
}
export default mutations
```
+ Action: Action 类似于 mutation,不同在于:
- Action 提交的是 mutation,而不是直接变更状态。
- Action 可以包含任意异步操作。
- 多个 `state` 的操作 , 使用 `mutations` 会来触发会比较好维护 , 那么需要执行多个 mutations 就需要用 `action` 了
- ```js
import * as types from './mutation-types'
export default {
// 异步 导出某些行为对象,业务逻辑
setUserInfoData ({ commit }, param) {
commit(types.SET_USERINFO, param)
},
removeUserInfoData ({ commit }) {
commit(types.REMOVE_USERINFO)
}
}
```
Loading

0 comments on commit 26451f6

Please sign in to comment.