vue笔记9
21.Vuex
vuex是一个专为Vue.js应用程序开发的状态管理模式。它借鉴了redux,采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
Vuex的特点:
-
能够在vuex中集中管理共享的数据,易于开发和后期维护
-
能够高效地实现组件之间的数据共享, 提高开发效率
-
存储在 vuex中的数据都是响应式的,能够实时保持数据与页面的同步
-
一般情况下,只有组件之间共享的数据,才有必要存储到vuex中;
对于组件中的私有数据,依旧存储在组件自身的data中即可.
vuex的使用场景:
vue可以帮助我们管理共享状态,并附带了更多的概念和框架。这需要对短期和长期效益进行权衡。如果不打算开发大型单页应用,使用Vuex可能是繁琐冗余的。确实是如此——如果您的应用够简单,您最好不要使用Vuex。一个简单的store模式足够所需。但是,如果需要构建一个中大型单页应用,您很可能会考虑如何更好地在组件外部管理状态,Vuex将会称为自然而然的选择。
vuex的引入方式:
- 下载引入:
npm i vuex
; - vue-cli,创建开发环境时引入;
Vuex的引入使用:
//导入 在main.js文件中
import Vuex from 'vuex'
Vue.use(Vuex);//use方法内部实现了将组件绑定到原型上,所以在所有组件中才能通过this.$store访问到Vuex中的数据
const store = new Vuex.Store({//创建vuex仓库
state:{msg:'我是数据'}
})
//挂载到vm对象
new Vue({
render(h){return h(app)},
router,
store//挂载以后 所有的组件就可以直接从store中获取全局数据
}).$mount( "#app")
//创建单独的Vuex文件,再引入的方式
//创建单独的store文件夹,在文件夹下创建index.js文件:
import Vue from 'vue'//引入vue
import Vuex from 'vuex'//导入vuex
Vue.use(Vuex)//启用vuex
//创建vuex实例 存放数据等操作在这里进行
const store = new Vuex.store({
state:{},
mutations:{},
actions:{},
modules:{}
})
export default store;//导出vuex实例
//在main.js中引入
import store from './store'
//挂载到vm对象上
new Vue({
router,
store,
render:h=>h(App),
}).$mount('#app')
vuex的属性:
-
state:state状态,用来保存所有数据;
const store=new Vuex.store({ state:{msg:"我就是所有共享的数据"} }); //在组件中访问数据 this.$store.state.msg
-
getter:getter类似于计算属性,会传入state对象,可以在其内部对state对象的数据进行操作
//设计 store文件中 const store = new Vuex.Store({ state: { arr: [ { id: 1, text: '...', birth: "1997-02-03" }, { id: 2, text: '...', birth: "2019-10-03" } ] }, getters: { bigMans(state) { return state.arr.filter((man)=>{ let manY=new Date(man.birth).getFullYear() let nowY=new Date().getFullYear() return (nowY-manY)>=18 }) } } }) //在组件中使用 this.$store.getters.bigMans
-
mutation:组件中更改store中的状态的唯一方法时提交mutation进行更改,不能直接使用赋值表达式设置store的数据。因为只有当通过mutation来更新数据,才会使所有使用该数据的组件刷新,更新UI。
//设计 const store = new Vuex.Store({ state: { count: 1 }, mutations: { //默认传第一个参数传state increment (state,obj) { // 变更状态 state.count=obj.n } } }) //在组件中使用 直接触发并传值(提交载荷) this.$store.commit('increment',{n:100}) //以对象的形式传入: this.$store.commit({ type: 'increment', n:100 }) //需要注意的是,mutation处理数据的方式是同步的,不能进行异步操作 mutations: { increment (state,obj) { //如果fnAsync函数是一个异步业务函数,就会导致更新失败 fnAsync(() => { state.count=obj.n }) } }
-
action:如果要进行异步修改store中状态的操作,可以使用action属性。action并不是直接操作store更改状态,而是提交到mutation。
//设计 const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state,obj) { state.count=obj.n } }, actions: { //默认第一个参数传一个跟store一样的对象 increment (context,obj) { //假设fnAsync是一个异步业务函数 fnAsync(() => { context.commit('increment',obj) }) } } }) //使用: //1.直接分发 this.$store.dispatch('increment',{n:100}) //2.以对象形式分发: this.$store.dispatch({ type: 'increment', n:100 })
-
module:业务分块开发。将store分割成模块(module)进行开发,每个模块拥有自己的state、mutation、action、getter
//分块设计: const moduleA = { namespaced: true,//局部命名空间(让state的中变量与其他模块中的同名变量不冲突) state: { msg:1 }, mutations: { change(state,n){state.msg=n} }, actions: { change(context,n){context.commit("change",n)} }, getters: { x(state){return state.msg} } } const moduleB = { namespaced: true,//局部命名空间 state: { msg:1 }, mutations: { change(state,n){state.msg=n} }, actions: { change(context,n){context.commit("change",n)} }, getters: { x(state){return state.msg} } } const store = new Vuex.Store({ modules: { a: moduleA, b: moduleB } }) //建立单独的文件夹存放独立的模块,然后在index.js文件夹中,将各模块汇总 //文件a: let a={ namespaced:true, state:{ msg:"a的msg" }, getters:{}, mutations:{}, actions:{} } export default a; //文件b let b={ namespaced:true, state:{ msg:"b的msg" }, getters:{}, mutations:{}, actions:{} } export default b; //在index.js中引入,汇总 import a from "./a.js" import b from "./b.js" const store = new Vuex.Store({ modules:{ a, b } }) export default store; //组件中的使用: this.$store.state.a.msg // -> moduleA 的状态 this.$store.state.b.msg // -> moduleB 的状态 this.$store.commit("a/change",100)-> moduleA 的mutations this.$store.commit("b/change",200)-> moduleB 的mutations this.$store.getters["a/x"]-> moduleA 的getters this.$store.getters["b/x"]-> moduleB 的getters this.$store.dispatch("a/change",100)-> moduleA 的actions this.$store.dispatch("b/change",200)-> moduleB 的actions
22.UI框架在vue项目中的使用
element框架的引入:
-
安装:
npm i element-ui -S
-
引入:
-
引入组件库:
import ElementUI from 'element-ui'
-
引入全局css样式:
import 'element-ui/lib/theme-chalk/index.css'
//elementUI的引入方式可以局部导入,只引入需要的组件 import {Button,Input} from "element-ui" import 'element-ui/lib/theme-chalk/index.css'; //按需导入/局部导入1. Vue.component(Button.name,Button) Vue.component(Input.name,Input) //按需导入/局部导入2. Vue.use(Button) Vue.use(Input) //全局引入 import ElementUI from 'element-ui' Vue.use(ElementUI)
-
23.打包流程
在vue环境中将代码编写完成后,使用webpack打包工具,将项目整体打包,托管到后端服务器。
-
项目托管到服务器后就不存在跨域问题了,所以需要在打包前将配置的跨域方案删除,避免出现路径问题。
-
打包指令:npm run build;
-
将打包后生成的文件复制到服务器的public文件夹下进行托管。
-
vue-router的模式不同会导致服务器托管处理方式不同:
-
如果router是在hash模式下,访问页面的路径会变成/#/hash,需要在服务器的路由中配置路由:
router.get("/*",controller.home.all)
,调用controller中的all方法```async all(){let data=fs.readFileSync(__dirname+"/…/public/index.html")
this.ctx.body=data.toString()
}```给前端返回托管的页面。网页会根据对应的路径读取JS文件然后运行,当前网页的路由匹配到JS代码的路由,则会渲染相应的组件,网页并不会刷新。还需要在服务器的node_modules>egg-static>config>config.default.js文件中,将prefix属性配置为"/",让打包托管后的文件路径读取正确。
- hash模式的优点是兼容性好,不需要在后端进行任何设置和开发,并且不会发送除ajax和资源加载之外的其他请求;
- hash模式的缺点是无法准确捕获路由的信息,对于需要锚点功能的需求会与当前路由机制发生冲突,对于需要重定向的操作,后端无法获取url全部内容,导致后台无法得到url数据。
-
使用history模式:这种模式每次更改路由都会向后端发送请求,也需要在服务器的路由文件中配置"/*"路由,使前端每次请求时,都给前端返回相同的页面,由该页面运行JS代码,再通过对应的路由渲染相应的组件。当服务器路由与页面JS文件内部路由重名时,在直接访问服务器的路由,给前端返回JS代码,而不是页面。——解决:避免重名。
-
vue开发注意事项
-
在开发的过程中,前后端是分开的,所以进行测试时需要请求服务器时,需要进行跨域的配置。
-
vue做代理服务器时:
-
下载axios模块
npm i axios
,在main.js中引入import axios from 'axios'
-
将axios绑定在vue的原型对象上:
Vue.prototype.$axios = axios
,在调用时使用this.$axios来进行ajax请求, -
main.js中的axios配置:
axios.defaults.baseURL="/api"
,给axios请求网址上加上’/api’,打包时只需删掉这一句代码,避免单独给每个请求设置;axios.defaults.withCredentials=true
,允许代理服务器进行请求时携带cookie -
vue.config.js文件中的代理配置:
module.exports={ lintOnSave:false,//关闭严格模式,避免因空格换行等导致报错 devServer:{ port:"8080",//设定请求方端口号 host:"localhost",//设定请求方网址 proxy:{ "/api":{//关键词,axios请求中含/api的网址会被代理 target:"http://127.0.0.1",//代理目标网址 changeOrigin:true,//允许改变来源网址 pathRewrite:{"^/api":""}//进行代理请求时,将网址中的关键词'/api'去掉 } } } }
port:"8080",//设定请求方端口号 host:"localhost",//设定请求方网址 proxy:{ "/api":{//关键词,axios请求中含/api的网址会被代理 target:"http://127.0.0.1",//代理目标网址 changeOrigin:true,//允许改变来源网址 pathRewrite:{"^/api":""}//进行代理请求时,将网址中的关键词'/api'去掉 } } }
}
-
-