一、简介

1.1什么是Vuex

官方的定义如下:

Vuex是一个专为Vue.js应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件状态,并以相应的规则保证状态以一种可预测的方式发生改变。

官方的解释看的一团迷雾,简单来说就是把一堆可能很多地方(各组件)会用到的数据管理起来,可以对这些变量进行修改,需要的时候就去取。

2.两个小例子:

1) 在项目中很多地方都要进行请求,vue中一个页面的每个组件都可能会有请求,服务器每次请求都需要判断用户的权限、token等信息,这里就可以把用户的权限信息、token等放入一个单独的仓库里面进行管理,每个组件都能对其状态(说白了就是值)进行读取、修改。

说到这里,可能有很多人就会说,这些信息直接放进cookies和session里面就行了啊,干嘛还要单独弄一个空间来存放这些信息。实际上,更多的时候是使用cookie与vuex配合一起使用,vuex获取信息,cookie控制时间和token的销毁。

2) 基于Vue的组件开发,肯定避免不了组件间的传参,父子传参还好说,直接使用prop传,或者父组件调用子组件的函数(使用emit/on)。但涉及到非父子组件之间的传参,常规的办法是建立一个空组件event bus,通过这个中间组件来传参,但这种方式只适用于不涉及到大量的信息传递,涉及到多个组件之间传参的时候,显然event bus就不适用了,这时候vuex就派上用场了,后面会对比vuex和event bus的区别。

所以,说白了,你可以把vuex看做一个数据库,把可能多个组件会用到的共享的参数放到里面,每个组件都可以获取和修改这些数据,用来解决多组件共享一个数据和组件间的通信问题。

说起存储数据,可能有些小伙伴或会想起localstorage,需要注意的是,vuex适用于单页面开发的,如果刷新页面了,或者页面跳转了(注意,是跳转页面,不是页面中组件改变),那vuex中的数据就自动清空了。而localstorage是一种物理存储,是针对于整个应用(application)的,页面刷新数据依然存在。后面也会介绍vuex和localStorage的区别。

二、应用原理

1.原理简述

既然说到vuex相当于一个数据库,那肯定就要定义里面存储那些信息、如何读取或者使用里面的变量,定义的这个文件就是store.js,现在来讲这个store.js里面是如何定义要用到的变量和使用变量的方法的。

store.js里面主要分为了一下几个模块:

1)state: 这里面就定义了我们存入的变量,它可以是任何类型的变量,在此定义之后,才能在vue的组件里面获取。

2)mutation: 定义更改state中变量状态的函数,所有对state中变量的修改只有一条途径,就是通过调用mutation中定义的对变量的操作方法,通过在组件中使用storage.commit(“定义的函数名”,参数)来修改、提交、删除state中的变量。

3)action:刚才说的mutation中定义的方法是同步的,假若想支持异步,比如在其中加入axios请求,就需要在action中定义函数,然后将mutation中的函数作为回调,执行storage.commit(“定义的函数名”,参数),达到异步的效果。关于mutation和action后面会单独分析。

4)getter类似于组件中的计算属性,当需要对state里面的变量进行一些计算再返回的时候,就要使用getter。他会接受state作为顶一个参数,然后从state中获取相应的变量进行计算,返回计算值。

5)module

当state中的变量越来越多,共享参数涉及到的组件也越来越多,如果不进行分类,就会显得比较臃肿,不利于维护,module的作用就是将store分模块,每个模块拥有自己的state/mutation/action,便于维护。

2.了解了以上之后,来看一个简单的例子:

准备好环境之后(搭建vue项目),引入vuex:

npm install vuex --save

src目录下建立store文件夹,文件夹中新建store.js文件,下面是一个简单的store,js:

这样,就可以在组件中引入store,

通过使用store.state.user获取user,

使用store.commit(“setUser”,”fanrui”)修改属性值;

使用dispatch(“commitUser”,”fanrui”)来进行异步的操作。

3.模块化

上面是一个简单的小例子,刚才说了,对于涉及模块比较多,那这里可以引入module,结构目录如下:

一个一个来看,这里将所有状态量分为了六个模块(对应modules下的六个文件),每个文件里面都自定义了自己的state、mutation,action,例如user.js文件下:

然后在统一的一个index.js(这里的index.js就是store.js,可以自己命名)文件中设置每个模块的对外输出:

在组件中使用时只需要引入外层store文件夹即可调用:

Store.state.user.token获取user中的变量

Store.state.user.commit() 调用user中的mutation方法修改变量

Store.state.user.dispatch()调用user中的action的方法异步执行

这就是采用module的方法,有些同学可能觉得每次调用都要写Store.state.user这么长一串比较麻烦,别担心,vuex提供了一个mapActions辅助函数,解决这个问题。具体使用方法在后面解释。

最后一个,解释一下这个getter.js,刚刚说了这个getter相当于计算属性,其实看一下这个getter.js文件,你可能就明白了

getter里面定义了各种计算变量,默认传入的参数就是整个store的state变量,可以利用state中的任意变量来进行计算,得到想要的属性进行输出,在组件中只需引入getter.js,就可以获取相应状态。

三、补充说明

1.Vuex和eventbus

先来看看各组件的传参:

1.1 父—>子:

每个子组件上都有一个prop,需要传递的参数放入其中,父组件可以把参数传给子组件,例如:

父组件中使用子组件,并定义想要传过去的参数:

子组件通过prop接收:

1.2 子—>父:

子组件可以用vue.$emit传递往上传递消息,父组件通过vue.$on回应子组件穿过来的消息:

子组件中:

this.$emit(“todo”,{

res: ”子组件发送的消息”
)

父组件中:

this.$on(“todo”,function(data){

data为传的消息,对data进行处理

})

1.3 兄弟组件间的传递:

emit/on只能在上下层之间传递消息,兄弟之间使用事件总线event bus传递。Evnetbus就相当于一个顺丰快递,将参数在组件传递;首先新建一个传递的媒介bus.js,为空就行,在需要传递的组件中引入bus.js,在一个组件间传出:

bus.$emit(“queryParam”,message)

在另一个组件中接受:

bus.$on(“queryParam”,message=>{…….})

这里多个组件都可以接受同一个组件发出的消息,只要第一个参数名相同就行。

1.4 Eventbus缺点:

这就是组件间的传参,既然已经实现,哪位什么还要引入vuex?

在最开始,我们的项目可能比较简单,但当项目越来愈大,组件越来越多,组件之间的交互也越来越多,组件里就会不断出现$emit这样的代码,主要产生以下几个问题:

1)代码变的冗余,可读性下降(总之就是看着好累,不舒服)

2)对于每一个组件都需要使用emit或者on来处理,设置不同的通信函数(emit、on的第一个参数)

2)很难查找每个事件是从哪里触发的,因为到处都是关于传参的业务逻辑

1.5 小例子说明:

说到这里可能对两者的区别有了些了解,但具体到应用中的区别还不是特别清楚,下面来举一个计数器的小例子。

有一个根组件,姑且叫做S,里面有一属性count。

需求1,写一个组件A作用是实现其中的按钮一次,然后将count计数加一,并在自身的组件中展示当前count的数字;这个比较好办,点击时count计数加1,同时使用event bus将参数count传递到根组件中,进行根组件的展示。

需求2,写一个组件B,作用是将组件S中的count数值为0,这个也好办,直接使用event bus向S组件发起$emit,S接收后,将count置为0;

问题在于,当你点击A组件时,在S组件和A组件上的count都会加1,但是当点击B时,S组件中的count变为0了,但是A组件的count不会发生变化,因为B组件只通知了S,并不知道到A组件会展示count,这就是问题的所在。

有的小伙伴会说,这不简单,在B中在写一个emit传给A就可以了;的确,这是一个办法,但上面说过了,这只适用于组件较少的情况,当你的组件比较多的时候,就会出现问题

比如在这里有多了个C组件、D组件同样是对count进行操作,也要展示count,那我们是不是得在这些组件之间为每一个组件都写一个emit进行传递,假设有N各组件,那是不是就总共得写N*N+1个emit/on?

第二个问题在于,你在添加组件的时候,你可能并不知道有哪些组件使用到了count,就像上面的例子一样,B只通知了S,而没有通知A。假设在一个项目开发过程中,突然有一个需求让你添加一个对count的操作,暂且不说你要写多少个emit,问题在于你首先得知道在之前有哪些组件用到了count,这也是个问题。

所以针对这种类似的问题,使用vuex是不是更加合理呢,下面来看看vuex是怎么解决上面的问题的吧:

第一个解决的是上面通知组件的问题:

引入vuex之后,将我们的countState放进store的state中作为共享变量,将countState映射到count中,这样每个组件中的count就会随着countState的改变而改变(数据是响应式),任何地方对countState的操作都会映射到各组件中,只要仓库中的countState改变了,各组件中的count也随着更新。

第二个是解决所有组件对状态的操作问题:

比如在需求的增加中,突然对count的大小做个规定,小于50,那对应是不是每个组件对countState进行操作的时候都要先判断其值是不是小于50?这个时候vuex提供了mutation方法,提供对countState变量统一的处理方法,此时就可已在这个方法中加入其值小于50的判断,就不用了在每个组件中单独判断了,将这个逻辑放到vuex中处理,组件只需要调用相应commit方法就行,例如下面的方法:

mutation:{

setCountState(state){
            if(state.countState < 50)
             {
                state.countState+=1;

}

else{

state.countState = 0

}
    }

1.6 结论

在大型应用方面,vuex是一个比eventBus好的解决方案。

Vuex式结构更加清晰,更易调试。

若果不涉及到大量的共享数据、组件通信,其实eventbus就足够了,但是。。。。个人还是觉得vuex用着舒服点。

  1. Vuex、LocalStorage:

Vuex和LocalStorage都可以用存储数据,对于LocalStorage我会另写一篇文章来详细的描述其原理,这里只单纯的讲一讲这两者的区别:

2.1 区别:

先说说存储方式,Vuex是存在内存中的,而localStorage是存在文件中的,并且localStorage的存储到小有限制,为5M

LocalStorage以文件形式存到本地,主要用于页面间的传参,不同页面通过访问storage记性传参;而vuex主要实在单页面内进行组件间的传值,为响应式数据(重点),各组件可以对其进行修改。

由此可以得出结论,在数据是静态不变的情况下,可以使用LocalStorage;当数据被多个组件共同使用,且要求数据改变后达到响应数据的变化的要求,则使用vuex。

2.2常见用法:

其实一般这两者可以搭配使用,由于LocalStorage不能相应数据的变化,所以一般将LocalStorage的操作写在vuex的mutation里面,使其随着vuex的变化而进行够改变;而对于多页面或者页面刷新之后,vuex将会被清空,这个时候就需要从LocalStorage里面取数据,填补vuex;不过需要注意的是:

vuex和LocalStorage要进行同步更新,这个就是在vuex数据改变之后,在mutation对应的方法中把值传到LocalStorage中;

存入vuex和LocalStroage是否有失效时间,比如像存储用户名、密码、token等这样的字段,就要控制这些变量失效时间;

不是所有放在vuex里面的变量都要在放到LocalStorage里面一份,对于刷新页面或者页面跳转(注意是页面跳转而不是组件跳转)涉及到需要保存内的数据存到LocalStorage里面就行了。

以上仅为个人理解。

3.mutations和actions

在vuex中,操作state中的变量为方法就是使用mutation中的方法,即调用commit()方法,action中修改的方法实际上也是在其中调用commit的方法来完成state的修改。

mutation只能进行同步

action可以进行异步

这两点区别带来的使用方式就在于action里面可以写回调函数,可已将mutation中的方法写进回调函数中。

有些同学可能对js的同步和异步问题有些模糊,这边我也会整理一个文档简述一下js的同步和异步。

4.mapSatete/ mapMutation/ mapAction辅助函数

之前说到,若果使用了module方法,可以将store中的变量模块话,便于管理;但是在调用国的时候显得比较臃肿,如

Store.state.user.token获取user中的变量

Store.state.user.commit() 调用user中的mutation方法修改变量

Store.state.user.dispatch()调用user中的action的方法异步执行

mapXXX系列就是解决这个问题的,画布是多说,基于上面之前讲到的架构,直接上代码解释首先在需要用到的组件中引入并定义:

之后就可在组件中使用this.方式来进行调用了,特别方便:

五 实例:使用cookies+vues+localstorage 实现用户的登录管理和token

1.要求

1)匹配用户名正确之后,进入系统,否则提示用户名会密码不正确

2)登录成功后,组件中所有的请求都需要进行登录状态和token的验证(使用vuex实现)

3)登录成功后,一小时内可以直接进入,不需要重新登录(使用vuex和cookies实现,1小时时间使用cookies控制)

4)登陆过的用户,下次登录时保存了当前的用户名,只需要输入密码即可(使用LocalStorages实现)

5)其中登录状态变量用来管用户的登录状态,token是用户发起请求的权限验证问题;这两个也有交叉的地方,比如登录状态过期了,token没过期;token过期了登录状态没过期,都有对应的处置办法。(所以我是不是应该。。。先分开写)

2.先来理一下思路:

用户登录:

登录状态,token存入vuex

将用户名、token存入LocaStorage(这里token为什么存在localstorage里而不是cookies里,后续说明)

登录状态存入cookies

用户请求:

每次请求,判断两个参数:

第一是否处于登录状态,若处于,则可请求,否则退回登录页面,登录状态失效时间由cookies控制

第二,从vuex中获取token,在请求header中携带token发送请求,

第三、服务段要进行token的验证,要判断token是否失效,失效了则转到登录页面(token失效时间由服务端控制)

用户登出:

清空vuex中的token和登录状态置为未登录,且把loacalsorage中的token清楚

一小时之后或登出之后的登录:

从localstorage中获取用户名填入,不需用户在进行填写

关于登录状态:

使用cookies来进行登录状态的,在其失效时写入vuex中,每次请求要从vuex中进行判断,若果失效,则重新登录

token失效日期:

请求前从vuex中获取token放入请求的header中,由服务端返回判断是否失效,失效转到登录页面

刷新页面问题:

因为vuex是单页面的,所以页面刷新后数据清空,需要从localstroage中从新获取token和登录状态,获取登录状态之前同样要判断登录状态是否失效,失效或需重新登录。

这里的问题是登录状态失效了、token失效了都要重新登陆。问题在于如果登录状态没失效,token失效了,那刷新页面之后不会重新登录,但紧接着如果有一个请求事件,由于token失效,那就会回到登录界面,给用户的体验不太好。关于这一点和token的安全性问题,也是为什么这里token要放到localstorage里面的原因,放到之后再说。

3.代码:

先写好需要用到的cookies、localstorage和stroage

3.1 Cookies的封装

这里主要简单封装一下js-cookies

import Cookies from "js-cookie";

const token = "token";

const name = "userName";

const login_state = false;

export function getoken(){

return Cookies.get(token);

}

export function setToken(userToken){

return Cookies.set(token,userToken)

}

//另写一个设置登录有效时间的函数

export function setTimeLoginState(state,time){

return Cookies.set(login_state,state,{expires:time})

}

export function getUserName(){

return Cookies.get(name);

}

export function setUserName(userName){

return Cookies.set(name,userName)

}

export function getLoginState(){

return Cookies.get(login_state);

}

export function setLoginState(state){

return Cookies.set(login_state,state)

}

export function removeCookies(param){

return Cookies.remove(param);

}

3.2 Locastorage的封装

引入vue自带的good-storage:

import storage from 'good-storage'

export function get(key)

{

return storage.set(key)

}

export function set(key,value)

{

return storage.set(key,value)

}

export function remove(key){

return storage.remove(key)

}

//其他的方法用到了再来封装

3.3 store仓库

目录架构如下,主要用到user里面的信息,ws是为了体现module的模块化

第一个是store.js,主要是将user、getters、ws抛出:

import Vue from 'vue';

import Vuex from 'vuex';

import user from './modules/user'

import ws from './modules/ws'

import getters from './getters'

Vue.use(Vuex)

const store = new Vuex.store({

modules:{

user,

ws

},

getters

});

export default store;

然后是getters,这里面主要定义了一些计算属性,使在外部拿到user或ws里面的state属性时更加方便:以下是将user中的token和登录状态定义,外界在获取时通过store.getters.token(其实这样做没必要,我只是想简单的体现一下getters的作用)

const getters = {

token:state=>state.user.token,

login_state:satte=>state.user.login_state

}

下面就是重点了,user.js,首先是状态,这里面主要存了两个状态:token和登录状态。

因为登录状态要到cookies里面进行超时的设置,所以这里的登录状态是从cookies里面获取,以保证拿到的登录过期时能够一致。

state :{

token:"",

login_state:cookies.getLoginState(),

},

然后就是对状态的操作mutations,这里主要是对token的设置;token同时会放进lostorage中,在页面刷新后vuex中的token丢失后可以总localstorage中获取

mutations:{

setToken:(state,token)=>{

state.token =token;

localStorage.set("token",token);

},

最后就是action,这里面主要定义了登录、登出的方法,第一个是登录,登录成功后会把后台返回的token存入vuex和localstorage中,并将登录状态设置为true,时间限制为一个小时,放到cookies中,将用户名放入localstorage中,在重新登录时就不用了输入用户名了,直接输入密码。登录失败则提示登录错误,重新尝试。

login({

dispatch,

commit},userInfo){

return new Promise((resolve,reject)=>{

userLogin.login(userInfo)

.then(({

code,

data,

message

})=>{

if(code == 200){

let {token,isInitPassword} = data;

commit("setToken",token);

cookies.setTimeLoginState(true,1/24);

localStorage.set("userName",userName);

this.$router.replace("/userInformation");

resolve();

}else{

reject({

data,

message

});

}

}).catch(()=>{

reject({

data:0,

message:"登录错误,请重新尝试!"

});

});

});

},

然后就是登出,登出主要是把登录状态、token给清理掉:

logOut({

commit

}){

return new Promise((resolve,reject)=>{

userLogin.loginOut().then(()=>{

commit("setToken","");

cookies.setLoginState(false);

resolve();

})

.catch(error =>{

reject(error);

})

})

}

}

}

3.4 配置界面

首先在App.vue中设置,如果已经登录井进入主页面,否则转到登录页面:

<template>

<div id="app">

<!-- 如果一登录,则进入主页面 -->

<el-container v-if="isLogin">  </el-container>

<!-- 没登录,则进入登录页面,在router中配置 -->

<router-view v-else></router-view>>

</div>

</template>

<script>

export default {

name: 'App'

}

</script>

路由配置为:

import Vue from 'vue'

import Router from 'vue-router'

import userInformation from '@/components/init/userInformation'

import login from '@/components/login'

Vue.use(Router)

export default new Router({

routes: [

{

path: '/',

redirect:"/login"     //跳转到登录页面

},

{

path:'/login',

name:login,

component:login

},

{

path:"userInformation",

name :"userInformation",

component:userInformation   //进入个人主页

}

]

})

为了避免用户直接输入个人主页的路由(即/userInformation)进行访问,所以在main.js中设置对路由的控制,凡是直接访问个人主页路由的,先判断登录状态,若是已登录,则直接进入个人主页,否则跳转到登录页面进行登录:

// The Vue build version to load with the `import` command

// (runtime-only or standalone) has been set in webpack.base.conf with an alias.

import Vue from 'vue'

import App from './App'

import router from './router'

import cookies from  './util/useCookies'

Vue.config.productionTip = false

/* eslint-disable no-new */

router.beforeEach(function(to,from,next){

let  login_state = cookies.getLoginState();

if(to.path == '/login'){

next();

}else if(!login_state){

next({path:'/login',replace:true});

}else{

next();

}

})

new Vue({

el: '#app',

router,

components: { App },

template: '<App/>'

})

然后就是登录的页面,直接调用store中的action方法进行登录即可:

import request from '../util/request'

/*

*@description:登录

*@author: fanrui

*@date: 2019-11-30 15:59:32

*@version: V1.0.0

*/

export function login(data){

return request({

url:"/login",

method:"post",

data

});

}

export function logOut(){

return request({

url:"/loginOut",

method:"get"

})

}

最后就是个人主页,个人主页在用户如果刷新后,vue中的数据不见了,这时候就要重cookies和localstorage中获取登录状态和token;若果获取刅的登录状态已经过期,则跳转到登录页面。

<script>

import store from  '../../store'

import localstorage from '../../util/localStorage';

import cookies from '../../util/useCookies'

export default{

name:"userInfromation",

mounted(){

let isLogin = islogin();

if(isLogin){

store.getters.login_state = cookies.getLoginState();

store.getters.token = localstorage.get("token");

}

else{

store.dispatch("loginOut");

this.$router.replace("/login");

}

},

method:{

isLogin:function(){

return cookies.getLoginState();

}

}

}

</script>

3.5请求拦截、响应拦截

除此之外,在每次发送请求的时候,都要判断登录状态是否过期,若是过期则会到登录页面;若没过期,则取出vuex中0的token放入请求头部发送给服务端

在得到服务端相应后,根据服务端的会傅token是否过期,若是过期则同样回到登录界面,重新登录吗,以获取最新token.

以上的实现是放在axios中请求拦截器和相应拦截器中:

我这里是将axios封装成了一个request.js,并配置拦截器,详细的封装方法见另外一篇文档:封装axios成request。

以上就是用户登录及请求的管理,可能会存在很多有问题的地方,毕竟我对这个的认知也有限,尤其是登录状态和token这一块,其实有很多方法,这里只是简单的介绍了相关的其中一种用法。

六、本文涉及到的其他问题会在另外的文章中说明:

  1. cookies、sessioin、token的区别
  2. 关于token和浏览器访问安全问题
  3. 有些小伙伴可能还不清楚为什么要区分mutation/action,一个是同步一个是异步,所有后面会有一篇专门写前端js的同步和异步

完成日期:2019年12.03

Vuex到底如何使用相关推荐

  1. Vuex白话教程第一讲:Vuex到底是个什么鬼?

    Vuex白话教程第一讲:Vuex到底是个什么鬼? Vuex白话教程第二讲:Vuex旗下的State和Getter Vuex白话教程第三讲:Vuex旗下的Mutation Vuex白话教程第四讲:Vue ...

  2. vuex到底是什么?什么情况下使用?

    vuex到底是什么?什么情况下使用? 一.vuex是什么? vuex是vue的状态管理器,是介于客户端与服务端之间的一个桥梁. 自己大致的画了个草图辅助理解 在vuex中有五个对象属性:state.m ...

  3. Vuex教程第一讲:Vuex到底是个什么--01

    先说两句 官方已经有教程了,为什么还要写这个教程呢?说实话,还真不是我闲着蛋疼,官方的教程真的是太官方了,对于刚入门 Vuex 的童鞋来说,想必看官方的教程,很多地方就如同看圣经一样,比如「欧玛尼玛尼 ...

  4. Vuex 白话教程第一讲:Vuex 到底是个什么鬼?

    转载出处:简书作者 大宏说 作者链接:大宏说 先说两句 官方已经有教程了,为什么还要写这个教程呢?说实话,还真不是我闲着蛋疼,官方的教程真的是太官方了,对于刚入门 Vuex 的童鞋来说,想必看官方的教 ...

  5. vuex与全局变量区别_挑战全网最幽默的Vuex系列教程:第一讲 Vuex到底是什么鬼

    先说两句 官方已经有教程了,为什么还要写这个教程呢?说实话,还真不是我闲着蛋疼,官方的教程真的是太官方了,对于刚入门 Vuex 的童鞋来说,想必看官方的教程,很多地方就如同看圣经一样,比如「欧玛尼玛尼 ...

  6. 挑战全网最幽默的Vuex系列教程:第一讲 Vuex到底是什么鬼

    先说两句 官方已经有教程了,为什么还要写这个教程呢?说实话,还真不是我闲着蛋疼,官方的教程真的是太官方了,对于刚入门 Vuex 的童鞋来说,想必看官方的教程,很多地方就如同看圣经一样,比如「欧玛尼玛尼 ...

  7. 10分钟让你学会使用Vuex

    Table of Contents 1.为什么要用Vuex? 组件之间共享数据的方式 2.Vuex概述 3.Vuex 基本使用 1.安装vuex包 2.导入Vuex包 3.创建store对象 4. 将 ...

  8. 关于Vuex的简单理解和使用

    1.什么是Vuex? 在使用vue作为框架的前端项目开发中,我们经常会碰到Vuex,那么Vuex到底是什么东西呢? 根据官方文档给出的解释是:Vuex 是一个专为 Vue.js 应用程序开发的状态管理 ...

  9. 状态管理模式 - vuex 的使用介绍

    前言 大家好,不知道大家在用 vue 进行开发过程中有没有遇到这样一种场景,就是有些时候一些数据是一种通用的共享数据(比如登录信息),那么这类数据在各个组件模块中可能都会用到,如果每个组件中都去后台重 ...

最新文章

  1. 要懂得利用和筛选友情链接
  2. Window ChromeDriver(简单4步完成)
  3. 超市买苹果变量的定义和使用
  4. 解决spark-shell输出日志信息过多
  5. 查看linux服务器下接设备,linux下如何查看设备信息_网站服务器运行维护
  6. Java 练习:编写 Java 程序,输入年份和月份,使用 switch 结构计算对应月份的天数。月份为 1、3、5、7、8、10、12 时,天数为 31 天。月份为 4、6、9、11 时,天数为 3
  7. 《机器学习实战》程序清单3-4 创建树的函数代码
  8. Spark代码生成技术之现象CodeGenerator
  9. 关于Hive中case when不准使用子查询的解决方法
  10. appium部分操作
  11. 用python开启相机_使用“打开”编辑相机设置
  12. opencv︱图片与视频的读入、显示、写出、放缩与基本绘图函数介绍
  13. css与jquery、图标字体、常用数据
  14. 公告栏文本横向循环滚动
  15. 如何书写批处理文件?(批处理文件的介绍及编写规范)
  16. dubbo入门之异步调用
  17. 建模计算机处理器,实战建模渲染,用锐龙7 5800X拒绝拖稿
  18. Android 系统时间自动更新机制
  19. 程序员mac开发环境配置
  20. 人工智能产业盛宴:2019 AIIA开发者大会即将揭幕

热门文章

  1. Win10系统下如何更改磁盘盘符
  2. Oracle表数据被锁定及查看解决
  3. 搭建一个页面并备份用户上传的文件项目作业
  4. 我知道你不知道我知道你不知道我知道你不知道
  5. 种树C语言,种树能让你不玩手机吗?#Forest #app
  6. Autodesk CAD Mac下载与安装百度网盘链接
  7. Intel官网资料下载链接
  8. linux中大于等于符号 特殊字符,Linux 特殊字符、符号
  9. Office ❀ 编辑文档、表格、PPT通用快捷键梳理
  10. macOS清除beta版本系统提示命令