9、ui框架以及vuex

一、.ui框架

  • element-ui:pc端【后台管理系统】推荐使用 饿了么开发的
    • 布局(栅格系统,容器)
    • 表格
    • 表单
    • js反馈
    • js模块(轮播图,手风琴,选项卡)
  • iview :pc端【后台管理系统】
  • mint-ui:移动端【几乎不用】 饿了么开发
  • vant:移动端 推荐

1、1 element-ui(pc端)

  • Element,一套为开发者、设计师和产品经理准备的基于Vue2.0的桌面端组件库
  • 官网:https://element.eleme.cn/#/zh-CN
  • 下载安装(最新版本时间库上有bug)
      npm i element-ui@2.15
    
  • 引入使用
    //全局引入elementui框架
    import ElementUI from 'element-ui;
    
    //全局引入elementui样式
    import 'element-ui/lib/theme-chalk/index.css';
    //注册elementuiVue.use(ElementUI);
    
    //在官网找到对应的代码
    
    

1、2 vant-ui(移动端)

  • 轻量、可靠的移动端Vue组件库
  • 官网:https://youzan.github.io/vant/v2/#/zh-CN/
  • 下载注意版本
      npm i vant@latest-v2
    
  • 引入使用
    在main.js中全局引入vant样式
    import Vue from 'vue'
    import App from './App.vue'
    import router from './router'
    
    Vue.config.productionTip = false
    
     //全局引入vant组件库
     import Vant from 'vant';
    //全局引入vant样式
     import 'vant/lib/index.css';
     //注册vantui
     Vue.use(Vant);
    
     new Vue({
         router,
         render: h => h(App)
     }).$mount('#app')
    

1、3 css 预处理器

  • css预处理器:less,sass,stylus
  • 在脚手架创建项目的时候,选中css预处理器
  • 使用:在组件中使用 less.vue
    <template>
       <div>
         <h1>less的使用</h1>
         <div class="box">
            <p>我是一段文字</p>
         </div>
       </div>
    </template>
    
    <script>
        export default {
        }
    </script>
    
    <!-- 
    <style lang="less">  设置lang,就可以使用less语法
    -->
    <style lang="less">
        @import "../assets/less/index.less";
    
       .box{
         width: 300px;
         height: 300px;
         background: @bg1;
       p{
         width: 100px;
         height: 100px;
         background: pink;
         color:@bg1;
        }
      &:hover{
         background: orange;
      }
    }
    </style>
    
  • 可以提取总共的样式值(主题背景颜色,主题字体颜色,字号)
    • 目录
      其中index.css文件是用来管理color.less以及size.less文件的
      在这里插入图片描述
      • color.less文件
       @bg1:red;
       @bg2:yellow;
       @bg3:teal
      
      • size.less文件
      @size20:20px;
      @size30:30px;
      @size40:40p
      
      • index.css
      @import "./color.less";
      @import "./size.less;
      
      • 组件中使用
        在这里插入图片描述

如果一开始创建项目的时候没有选择less,可以后期安装

   npm i less@4.0.0 less-loader 8.0.0 -D
   "less": "^4.0.0",
   "less-loader": "^8.0.0
  • 安装好就和上面一样使用就可以了

二、vuex

  • 组件的通讯方式
  • 父传子:父组件自定义属性,子组件props接收
  • 子传父:父组件自定义事件,子组件$emit触发
  • 非父子:EventBus中央事件管理、本地存储、vuex
    在这里插入图片描述

2、1 vuex介绍

  • 概念:
    共享数据
    Vuex是一个专门为Vue.js应用程序开发的状态管理模式
    它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化
    
    注意点:vuex不是永久性存储,当刷新的时候会回到初始状态。
    所以它在应用同步操作的时候(没有调用接口),要结合离线存储去实现
    

vuex和离线存储的区别?

1、相同点:都可以去实现数据共享
2、不同点:
     vuex不是永久性存储,一刷新就会回到初始状态,但是它是响应式的数据变化
     离线存储它是永久性存储,但是它没有响应式的数据变化,当数据发生变化,它不刷新,页面是不会改变的
3、使用场景:一般都会结合使用,比如登录、购物车等
  • 五大核心
     state            状态(唯一的数据源)
     getters          缓存数据
     mutations        变化 (需要commit提交)(修改数据的唯一方法)
     acctions         行动(需要dispatch派遣)(发起异步请求,交给mutations修改数据)
     modules          模块
    
  • 数据操作过程
    在这里插入图片描述
    过程在这里插入图片描述
  • 总结:如果想要异步改变仓库中的数据,必须dispatch触发一个actions(actions中是异步),actions请求完数据后,提交一个commit去触发mutations(mutations中是同步),mutations去修改state,当state一发生变化,依赖它的getters也发生变化,视图就改变。

2、2 vuex的基础使用

  • 官网地址:https://v3.vuex.vuejs.org/zh/

  • 使用场景:只有复杂的中大型项目才会考虑使用vuex去管理一些共享数据,
    一般的普通项目不需要调用vuex

    1)手动下载使用

    • 下载
      npm i vuex@3
      + vuex@3.6
      

    注意这里使用的是3的版本,对应的是vue2
    vue2–>vuex3
    vue3–>vuex4

    • 在src下创建store文件夹,创建index.js文件
      //1.下载  npm i vuex@3
      //2.引入
      // 引入vue核心库
      import Vue from 'vue'
      // 引入vuex核心插件
      import Vuex from 'vuex'
      // 调用vuex插件
      Vue.use(Vuex)
      
      // console.log(Vuex); //是一个对象,里面包含一个Store的构造函数,用来创建实例
      
      //3.实例化vuex仓库,并导出
      export default new Vuex.Store({
         //唯一的数据源
          state:{
             name:"李云龙",
             age:20
          },
         //充当视图层和状态层的中间层,具有缓存作用
          getters:{},
         //修改数据的唯一方式
          mutations:{},
        //异步操作--请求数据
          actions:{},
          modules:{}
      })
      //4.在main.js中引入,挂载到vue实例上
      
    • 把封装好的仓库模块,注入到vue实例上(main.js中)
         import Vue from 'vue'
         import App from './App.vue'
         import router from './router'
         import store from "./store"
      
         Vue.config.productionTip = false
      
      
      
         new Vue({
           router,
           store,
           render: h => h(App)
         }).$mount('#app')
      
      至此,在所有的组件实例上,就可以见到一个$store对象,它下面就有state、getters等属性
      • 创建好one.vue组件,并配置好路由及路由出口
      • 在组件中使用数据
          <template>
            <div class="box">
                <h1>this is one组件</h1>
                <p>姓名:{{$store.state.name}}</p>
                <p>年龄:{{$store.state.age}}</p>
            </div>
          </template>
        
          <script> 
              export default {
                   mounted(){
                        console.log(this.$store.state);
                   }
             }
          </script>
        
          <style>
        
         </style>
        

    2)脚手架使用vuex

    • 安装时选择vuex
    • 项目初始化
       1、初始化vue.app
       2、初始化路由配置 router/index.js
       3、删除文件components、assets、views后期需要再加
    
    • 创建组件one.vue,设置路由以及出口
    • 在store->index.js的state下面创建数据
       import Vue from 'vue'
       import Vuex from 'vuex'
       Vue.use(Vuex)
    
       export default new Vuex.Store({
          //唯一的数据源
           state:{
              name:"李云龙",
              age:20
           },
           getters:{},
           mutations:{},
           actions:{},
           modules:{}
       })
    
    • 组件中使用数据,同上面一样
       <p>姓名:{{$store.state.name}}</p>
      

三、vuex核心模块

3、1 state

  • state(状态):唯一的数据源,用于管理共享数据
  • 概念:
      官方:
      Vuex使用单一状态树,用一个对象就包含了全部的应用层级状态。
      至此它便作为一个“唯一数据源(SSOT(opens new window))”而存在
    
      vuex本身也是响应式的数据变化
    
  • 用法
    {
         state:{
          //定义的数据源
          }
    }
    
  • 组件中取值
       $store.state.属性名
    

3、2 getters

  • 概念:
    它类似于计算属性,具有缓存的效果
    一般我们会将它作为state和视图的中间层所存在
    当然大量的计算逻辑也可以放在getters中
    
  • 用法
    {
         getters:{
            名称(state){
              return state中的内容
            }
         }
    }
    
  • 例:如下这个name属性,它在state中的层级比较深,直接获取要写好几层,而我们通过getters处理之后,层级简单很多。
    当然,它更重要的是对state中的数据做逻辑处理返回,整体而言,它的使用比较简单
    在这里插入图片描述

3、3 mutations

  • mutations(变化):是修改state的唯一方式,且它只能操作同步方法
  • 概念:
    官方概念:
     更改Vuex的store中的状态的唯一方法是提交mutation     
    
  • 用法
    // 组件视图中的逻辑:commit去触发mutations中的方法。commit中的type类型传入到mutations中做为函数名
       {
             methods:{
                   自定义方法名(){
                         this.$store.commit('type类型',参数);
                   }
            }
       }
     //仓库代码:type类型就是逻辑中的type类型。参数state就是数据仓库,参数payload即commit传过来的参数
        {
             mutations:{
                   type类型(state,payload){
                      //state即唯一的数据源
                      //payload代表参数
                   }
             }
        }
    

  • 在这里插入图片描述

3、4 actions

  • actions(行动):它和mutations一样都是方法,但是有以下不同
    • 它不能直接修改state(只有mutations可以修改state,但它可以提交commit让mutations修改state)
    • 它可以实现同步或异步操作
  • 概念
        官方概念:
         action类似于mutation,不同于:
              action提交的是mutation,而不是直接变更状态
              action可以包含任意异步操作
    
  • 用法
     // 组件视图中的逻辑:actions要用dispatch触发,它里面的type类型传到actions当函数名使用。actions中触发mutations
     //总之:先到actions,再到mutations
      {
            methods:{
                自定义方法名(){
                  this.$store.dispatch('type类型',参数)
                }
           }
      }
      //仓库代码:actions中处理后,再调用
      {
           mutations:{
                mutations中的type类型(type,payload){
                         //修改state
                        //payload代表的参数
                }
           },
           actions:{
                type类型(context,payload){ // 此context是整个仓库对象,包含所有方法
               // 异步操作得到结果后,再调用commit
                context.commit(mutation中的type类型, payload)
               }
              //或者利用解构
              type类型({commit},payload){
                 // 异步操作得到结果后,再调用commit
                 commit(mutation中的type类型, payload)
              }
           }
      }
    

  • 请添加图片描述
  • 总结:mutations只能操作同步,而actions可以异步操作。但是actions它又不能直接操作state中的数据,必须要借助mutations。
    actions中的方法,必须要用dispatch调用,然后在actions中用commit方法调用mutations中的方法。
    关于仓库中命名建议
    如仓库中有一个列表叫list,则以此类推定义出getters、mutations、actions中的名字
 state:list
 getters:get_list
 mutations:mutation_list
 actions:action_list

3、5 modules

1、概念

因为state是唯一的数据源,所以所有的数据都在这一个大的对象树上。导致state臃肿
modules的出现就是为了解决state臃肿的问题。
它可以把仓库切割成为一个个的小模块,每一个模块中都含有state,getters,mutations,actions,
甚至当项目过于复杂的时候我们还可以再嵌套子模块
命名空间:namespaced
模块中的state会被挂载到主的state对象树中并携带模块名称防止冲突
但是其他的核心属性,比如getters、mutations、actions,都是直接未区分挂载到当前对象树中,为了
防止冲突,我们通过设置命名空间为其携带模块名称
使用了命名空间之后,我们再用映射去取时,就不能用数组了,要用对象重命名来取值

2、操作方法

将stroe->index.js中的内容拆分到一个个模块中,每个模块都有自己的state、getters、
mutations、actions
它还有 namespaced: true 启用命名空间
// store->modules->list->index.js里的内容
export default {
state: {
name: 'list'
},
getters: {
getTitle(state) {
return state.name;
}
},
mutations: {},
actions: {},
namespaced: true // 命名空间
}

3、6 banner实战

  • 实战:vuex调用小U的banner接口
  • 需求:本来这个banner只在首页用了。但是如果有这样的需求,banner在其他的页面也需要使用,这样就要多次发起ajax请求,就会浪费性能。我们把它放在vuex中,只在仓库中调用一次,其他的页面就都可以使用。
  • 1.起后端服务
  • 2.前端安装axios npm i axios@0
  • 3.解决跨域 —在package.json同级的目录下创建vue.config.js,全局配置解决跨域(注意,一定要重启 前端服务)
module.exports = {
    devServer: {
       proxy: 'http://localhost:3000'
    }
}
    1. 封装request请求模块
    • request–>index.js
    import axios from 'axios';
    let http = axios.create({
         baseURL: '/api'
     });
    // 请求拦载
    http.interceptors.request.use(req => {
          return req;
    })
    // 响应拦载
    http.interceptors.response.use(res => {
        return res.data; // 这里做了数据过滤
    })
    export default http;
    
    • request–>api.js
     import http from './index';
     // 获取banner
     export function getBanner() {
          return http.get('/getbanner');
     }
    
    1. 封装banner.vue组件
    1. 定义banner路由
    1. 在响应拦载哪里,做数据过滤,把一些不需要的去掉,只返回需要的数据
    1. 在banner.vue中,使用返回过来的数据并渲染页面
    1. banner.vue一加载,就只需要数据,因此,把数据放入到仓库中,并通过getters传给组件
    1. 页面一加载,就要调取接口,但是调取接口是一个异步,将调取接口放到actions中。在
      banner.vue的mounted的钩子函数中调用
      在这里插入图片描述
      store->index.js
        import  Vue from "vue";
        import Vuex from "vuex";
        import { getbanner } from "../request/api";
      
        Vue.use(Vuex);
        
        export  default new Vuex.Store({
           state: {
               list: [], // banner数据
           },
           getters: {
               // 数据返给前端
               get_list(state) {
               return state.list;
               },
           },
           mutations: {
                mutation_list(state, payload) {
                       state.list = payload;
                },
           },
           actions: {
                 action_list({ commit }) {
                        // 发起ajax请求(异步)
                        getbanner()
                         .then((res) => {
                           if (res.code == 200) {
                              // 成功了,commit发起一个mutations
                              commit("mutation_list", res.list);
                            }
                          })
                         .catch((err) => {
                              console.log(err);
                          });
                        },
                  },
           modules: {},
         });
      
      banner.vue
        <template>
          <div>
           <h1>banner组件</h1>
           <ul>
               <li v-for="item in $store.getters.get_list" :key="item.id">
                   <img class="img" :src="item.img" alt="" />
               </li>
           </ul>
          </div>
        </template>
        <script>
           export default {
               mounted() {
               // 加载完成之后,触发actions中的方法
                    if (!this.$store.state.list.length) {
                       this.$store.dispatch("action_list");
                    }
                },
           };
        </script>
        <style scoped>
          .img {
              width: 300px;
          }
        </style>
      
      先看这里辅助性函数,再看上面的模块
      • 辅助性函数的目的
      辅助性函数最大的作用就是映射
      
      如果直接在视图中取vuex中的数据或者调用方法,需要 $store.state.name 等这样的写法
      而用辅助性函数,可以直接将值映身到视图的计算属性或方法中,直接调用,就省了$store.state
      

四、辅助性函数

4、1 mapState()

state它是vuex的唯一数据源

mapState(很少用,因为一般都把数据放在getters中,用mapGetters)

因为都是属性,所以拿回来之后,都放在computed计算属性中

 <template>
      当取回来了state中的数据之后,就可以直接在这里渲染了,而不用像之前要$store.state.值
      {{映射仓库中state值}}
</template>
// 视图逻辑中
import { mapState } from 'vuex'; // mapState它是一个函数,调用时传入数组或对象,数组或
对象都是state中的属性名

// 计算属性中(因为它也是属性)
computed:{
   // 传入数组
   ...mapState(['仓库中state值1', '仓库中state值2'])
   // 传入对象,用于给state中的属性设置别名(改名),在这个视图中就用这个别名渲染数据
   ...mapState({
        想要渲染的名字: 仓库中state值1,
        想要渲染的名字: 仓库中state值2,
   })
}

4、2 mapGetters()

getters相当于计算属性。它作为state和视图的中间层存在。它具有缓存效果
因为都是属性,所以拿回来之后,都放在computed计算属性中

  import {mapGetters} from 'vuex'
  computed:{
      ...mapGetters(['仓库中getters值1', '仓库中getters值2', ...])
      ...mapGetters({
                想要渲染的名字:仓库中getter的值1,
                想要渲染的名字:仓库中getter的值2,
      })
  }
<template>
   <div>
     <h1>one</h1>
     <h2>直接使用state中的数据:{{ $store.state.name }}</h2>
     <h2>使用getters转换的数据:{{ $store.getters.getName }}</h2>
     <hr />
     <h1>使用辅助函数</h1>
     <h2>使用辅助函数取得state中的数据:{{ name }}</h2>
     <h2>使用辅助函数取得getters中的数据:{{ getName }}, 今年{{ getAge }}岁</h2>
   </div>
</template>
<script>
   // mapState, mapGetters因为是数据属性,所以放在computed中
   // mapMutations, mapActions因为是方法,所以放在methods中
   import { mapState, mapGetters } from "vuex";
   export default {
        data() {
           return {};
        },
   computed: {
    ...mapState(["name"]),
    ...mapGetters(["getName", "getAge"]),
   }
};
</script>
<style scoped>
</style>

4、3 mapMutations()

它是修改state的唯一方式,同步的

  import {mapMutations} from 'vuex'
  // 因为它们都是方法,因此要放在方法里面
  methods:{
    ...mapMutations(['mutations名字一致']),
    ...mapMutations({
         '自定义函数名称':'mutations名字'
    })
}

它的好处是,映射过来之后,定义在mutations中的方法名,可以在视图中直接调用且传参,而不用commit提交

4、4 mapActions()

它不能直接修改state,它只能commit一个mutations。它可以操作异步方法

 import {mapActions} from 'vuex'
    methods:{
          ...mapActions(['actions名字一致']),
          ...mapActions({
                  '自定义函数名称':'actions名字'
          })
 }

它的好处是,映射过来之后,定义在actions中的方法名,可以在视图中直接调用并传参,而不用dispatch提交

案例

<template>
 <div>
  <h1>one</h1>
  <hr />
  <h3>使用辅助性函数--state</h3>
  <p>{{ uname }}</p>
  <p>{{ uage }}</p>
  <hr />
  <h3>使用辅助性函数--getters</h3>
  <p>{{ get_name }}</p>
  <p>{{ get_age }}</p>
  <hr />
  <h3>使用辅助性函数--mutations</h3>
  <p>
  <button @click="mutation_name('辉哥')">修改名字</button>
  </p>
  <hr />
  <h3>使用辅助性函数--actions</h3>
  <p>
    <button @click="action_age(3)">异步修改年龄</button>
  </p>
 </div>
</template>
<script>
import { mapState, mapGetters, mapMutations, mapActions } from "vuex";
// console.log(mapState); // 函数,调用时传入数组或对象,数组或对象都是state中的属性名
// console.log(mapState(["name", "age"]));
export default {
// 计算属性
computed: {
// ...mapState(["name", "age"]), // 用仓库中的原名
// 改名
...mapState({
   uname: "name",
   uage: "age",
}),
...mapGetters(["get_name", "get_age"]),
},
// 方法,
methods: {
   ...mapMutations(["mutation_name"]),
   ...mapActions(["action_age"]),
},
};
</script>

总结:
不论是映射数据,还是映射方法,最终的目的是减少在视图层的代码,映射的数据在视图直接使
用,映射的方法在视图中直接调用且可以传参。
减少代码量,这是目的

  • 35
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值