七、Vuex、映射函数、自定义插件、代理服务器

① Vuex

1.安装

npm install vuex --save

2. 引入Vuex并创建状态管理对象

1.state选项,定义状态(状态就是数据)

2.getters类似计算属性

3.mutations选项,定义操作状态的方法(注意:这里面只能定义同步方法)

它有两个参数,第一个参数是状态,第二个参数是新值。

4.actions选项也是定义操作状态的方法(这里的方法可以定义异步方法)

第一个参数是上下文对象(就是当前store对象),第二个参数是新值

注意:actions最好不要直接操作state,通过mutations操作state所以,actions直接操mutations。

为什么要这么设计,因为我们可能要跟value值发送请求,获取对应的值

5.modules选项用来导入模块

import Vue from 'vue'
import Vuex from 'vuex'  //导入vuex插件
Vue.use(Vuex)  //使用vuex插件
import phone from './phone'  //导入手机模块 
//创建状态管理对象
let store = new Vuex.Store({
  state: {
    planeName: '波音747',
    planePrice: '10亿',
    car: {
      carName: '奔驰',
      carPrice: '100w'
    },
    //汽车数组
    cars: [
      {
        name: "奔驰",
        price: 50,
      },
      {
        name: "宝马",
        price: 40,
      },
      {
        name: "奥迪",
        price: 30,
      },
    ],
  },
  getters: {
    //汽车的总价
    totalCarPrice(state) {
      return state.cars.reduce((p, c) => p + c.price, 0)
    }
  },
  mutations: {
    //修改飞机的名称
    updatePlaneName(state, value) {
      state.planeName = value
    },
    //修改飞机的价格
    updatePlanePrice(state, value) {
      state.planePrice = value
    },
    //修改汽车的名称和价格
    updateCar(state, value) {
      state.car = value
    },
    //添加汽车
    addCar(state, value) {
      state.cars.push(value)
    }
  },
  actions: {
    // 这里我们使用定时器,默认异步过程。
    updatePlaneName(store, value) {
      setTimeout(() => {
        store.commit("updatePlaneName", value);
      }, 2000);
    },
    //添加汽车
    addCar(store, value) {
      store.commit("addCar", value);
    },
  },
  //模块
  modules: {
    //手机模块
    phone
  },
})
export default store 

3.手机模块 

namespaced:true是设置私有命名空间,默认情况下该属性是false。非私有命名空间的模块,只有

state是私有的,getters、mutations、actions仍然提升到全局中,私有命名空间的模块,所有成员

都是私有的(局部的)

export default { 
    namespaced: true,
    state: {
        //手机数组
        phones: [
            {
                name: "iphone13",
                price: 6999,
            },
            {
                name: "华为",
                price: 5999,
            },
            {
                name: "小米",
                price: 4999,
            },
        ],
    },
    getters: {
        // 计算手机总价
        totalPhonePrice(state) {
            return state.phones.reduce((p, c) => p + c.price, 0);
        },
    },
    mutations: {
        addPhone(state, value) {
            state.phones.push(value);
        },
    },
    actions: {
        addPhone(store, value) {
            setTimeout(() => {
                store.commit("addPhone", value);
            }, 2000);
        },
    }
};

4.注册给Vue

import Vue from 'vue'
import App from './App.vue'
import store from './store/index01'
Vue.config.productionTip = false
new Vue({
  render: h => h(App),
  //使用全局状态管理
  store,
}).$mount('#app')

5.使用 

<script>
export default {
  name: "Home",
  computed: {
    //返回汽车数组
    cars() {
      return this.$store.state.cars;
    },
    //返回汽车总价
    totalCarPrice() {
      return this.$store.getters.totalCarPrice;
    },
    //返回手机数组信息
    phones() {
      // 注意:手机数组数据在phone模块中
      // $store.state返回的是全局状态,根据全局状态获取指定模块,再获取该模块中具体的状态。
      return this.$store.state.phone.phones;
    },
    //返回手机总价
    totalPhonePrice() {
       // 注意:总价在phone模块中,获取模块中的计算机属性的方式:
       // 1.return this.$store.getters.计算属性名
       // return this.$store.getters.totalPhonePrice;
 //使用这种方法必须是非私有命名空间的模块即模块的namespaced: false,因为getters被提升到全局了
       // 2.return this.$store.getters['模块名/计算属性名']
       // 使用这种方法必须是私有命名空间的模块即模块的namespaced: true,
       return this.$store.getters["phone/totalPhonePrice"];
    },
  },
  methods: {
    fun1() {
      //commit()方法,用于执行指定的mutations里面的方法
      this.$store.commit("updatePlaneName", "轰炸机777");
      this.$store.commit("updatePlanePrice", "25亿");
    },
    fun2() {
      this.$store.commit("updateCar", {
        carName: "兰博基尼",
        carPrice: "1000w",
      });
    },
    //同步方法添加car
    fun3() {
      this.$store.commit("addCar", {
        name: "保时捷911",
        price: 150,
      });
    },
    //异步方法添加car
    fun4() {
    //dispatch()方法,调用的是actions里面的方法
      this.$store.dispatch("addCar", {
        name: "法拉利",
        price: 1000,
      });
    },
    fun5() {
      this.$store.commit("addPhone", {
        name: "三星",
        price: 9999,
      });
    },
    fun6() {
      this.$store.dispatch("addPhone", {
        name: "vivo",
        price: 5999,
      });
    },
  },
};
</script>

② 映射函数

1. 导入映射函数

// 从vuex中,导入映射函数
import { mapState, mapGetters, mapMutations, mapActions } from "vuex";

2. 使用映射函数生成计算属性

如果vuex里面state的数据名称跟页面中的计算属性名称相同,就可以使用mapState映射函数,

自动生成页面中的计算属性。

注意:如果要映射模块里面的state,函数的第一个参数设置为模块的名称

如果vuex里面getters的数据名称跟页面中的计算属性名称相同,就可以使用mapGetters映射函

数,自动生成页面中的计算属性。

注意:如果要映射模块里面的getters,函数的第一个参数设置为模块的名称。

//使用映射函数生成计算属性
  computed: {
    ...mapState(["firstName", "lastName"]),
    ...mapState("phone", ["phones"]),
    ...mapGetters(["totalCarPrice", "totalPhonePrice1", "fullName"]),
    ...mapGetters("phone", ["totalPhonePrice"]),
  },

3. 使用映射函数生成方法

生成的方法名跟mutations里面的方法名相同。生成的方法会带有一个参数,通过参数传递数据。

 注意:如果要映射模块里面的方法,第一个参数传递模块的名称。

  //使用映射函数生成方法
  methods: {
    ...mapMutations(["updateFirstName", "updateLastName"]),
    ...mapActions(["updateFirstName2", "updateLastName2"]),
    ...mapActions('phone',['addPhone'])
  },
<template>
  <div>
    <p>列表页</p>
    <p>
      {
  { firstName }}--{
  { lastName }}===={
  { fullName }}--{
  { phones }}--{
  {
        totalPhonePrice
      }}
      <button @click="updateFirstName('李')">修改姓1</button>&nbsp;
      <button @click="updateLastName('元霸')">修改名1</button>&nbsp;
      <button @click="updateFirstName2('王')">修改姓2</button>&nbsp;
      <button @click="updateLastName2('羲之')">修改名2</button>
      <button @click="addPhone({ name: '三星', price: 4999 })">添加手机</button>
    </p>
    <p>汽车总价:{
  { totalCarPrice }}W--手机总价:¥{
  { totalPhonePrice1 }}</p>
  </div>
</template>

③ 自定义插件

1. 自定义指令

// 全局自定义指令 `v-focus`
Vue.directive('focus', {
  // 当被绑定的元素插入到 DOM 中时……
  inserted: function (el) {
    // 聚焦元素
    el.focus()
  }
})

局部指令,组件中也有一个directives 的选项
directives: {
  focus: {
    // 指令的定义
    inserted: function (el) {
      el.focus()
    }
  }
}

钩子函数bind(指令第一次绑定到元素时调用)、inserted(被绑定元素插入父节点时调用 )、

update(所在组件的虚节点更新时调用)。钩子函数的参数:el 、binding等 。

el:指令所绑定的元素,可以用来直接操作 DOM

binding:一个对象,包含以下 属性:

      1.name-指令名,不包括 v- 前缀

      2.value-指令的绑定值 ,oldValue-指令绑定的前一个值

      3.expression-字符串形式的指令表达式。例如 v-my-directive=”a+b” 中,表达式为 “a+b”。

      4.arg-传给指令的参数,可选。例如 v-my-directive:foo ,参数为 “foo”。

2. 自定义插件

定义一个插件,插件就是将给Vue添加的全局成员,归类到一起去,这样做利于后期维护。

插件中必须包含一个install方法,方法的第一个参数是Vue,后面的参数是可选的

let myPlugin = {
     install(Vue) {
        //自定义指令
        Vue.directive("myHtml", (el, binding) => {
            el.innerHTML = binding.value
        })
        Vue.directive('red', (el) => {
            el.style.color = 'red'
        })
        Vue.directive('color', (el, binding) => {
            el.style.color = binding.value
        })
        //全局混入,之后所有的Vue实例,都将拥有里面定义的成员
        Vue.mixin({
            data() {
                return {
                    myName: '张三',
                    myAge: 25
                }
            },
            methods: {
                sayHi() {
                    alert('大家好哦')
                }
            },
        })
        //给Vue的原型对象添加成员,之后所有的Vue实例,都将共享这些成员
        Vue.prototype.$bus = new Vue()
        Vue.prototype.address = "北京市朝阳区1001号";
        //全局过滤器
        Vue.filter('toFixed2', (val) => {
            return val.toFixed(2)
        })
        //注册全局组件
        Vue.component('a-button', {
            render: (h) => h('button', { style: { border: 'none', borderRadius: '10px', padding: '5px 10px', cursor: ' pointer' } }, '按钮')
        })
    }
}
export default myPlugin

3.$nextTick

watch: {
    isShow(nval) {
//$nextTick()有一个回调函数,它里面的代码会在页面挂载完成后执行,一般在处理原生dom时会用到
    this.$nextTick(() => {
       if (nval) {
       //显示时输入框得到焦点
       document.querySelector("#input").focus()
       }
    })
  }
},

4.过渡 

    <button @click="isShow = !isShow">显示/隐藏</button>
   <!-- 将需要做动画或过渡效果的内容,用transition包起来 -->
    <transition name="box1">
      <div v-show="isShow" class="box">112</div>
    </transition>
   <!-- 给列表添加动画或过渡效果,用transition-group ,tag属性是设置显示标签-->
    <transition-group tag="div" name="box2">
      <ul v-for="(item, index) in list" :key="item.id">
        <li>{
  { item.name }}</li>
        <li>{
  { item.sex }}</li>
        <li>{
  { item.age }}</li>
        <li><button @click="del(index)">删除</button></li>
      </ul>
    </transition-group>
/* 进入时的样式和离开时的样式 */
.box1-enter-active,
.box1-leave-active {
  transition: all 1s;
}
/* 进入前的样式和离开后的样式 */
.box1-enter,
.box1-leave-to {
  opacity: 0;
  transform: translateY(20px);
}
/* 进入时的样式和离开时的样式 */
.box2-enter-active,
.box2-leave-active {
  transition: all 1s;
}
/* 进入前的样式和离开后的样式 */
.box2-enter,
.box2-leave-to {
  opacity: 0;
  transform: translateX(20px);
}

④ 代理服务器

ajax请求数据,必须要遵循同源策略,即请求地址的协议名,主机名(域名或ip地址),端口号,必

须跟当前地址相同,否则就是跨域请求。解决跨域有两种途径:

1.后端允许跨域,2.前端想办法骗过后端实现跨域(jsonp技术,代理服务器技术)

vue,config.js文件中配置代理服务器:

module.exports = {
    //取消eslint语法检查
    lintOnSave: false,
    //devServer是脚手架中的开发服务器
    devServer: {
        //配置主机名
        // host: 'localhost',
        //配置端口号
        // port: '8840',
        //在开发服务器中,配置一个代理服务器地址。
        //注意:在开发阶段,通过向当前开发服务器发送ajax请求,当前服务器会将请求转发给配置的代理服务器地址。
        // proxy: 'http://localhost:8840',
        // 配置多个代理服务器地址
        proxy: {
            // /api1是前缀
            '/api1': {
                target: 'http://localhost:8840',
                //因为路径加了前缀,本身前缀是不需要的,所以要重写路径
                pathRewrite: {
                    '^/api1': ''
                }
            }
        }
    }
}

后端服务器:

// 导入express
let express = require('express')
// 创建一个服务器对象
let app = express()
// 开启一个端口号
app.listen(8840, () => {
    console.log("服务器已开启,端口号是8840");
})
//配置中间件,拦截所有的请求
app.use((req, res, next) => {
    //允许跨域
    // res.setHeader("Access-Control-Allow-Origin", "*");
    console.log("服务器已发送请求");
    next()
})
//学生数组
let stus = [
    {
        no: "1001",
        name: "张三",
        age: 20,
        sex: "男",
    },
    {
        no: "1002",
        name: "李四",
        age: 22,
        sex: "女",
    },
    {
        no: "1003",
        name: "王五",
        age: 24,
        sex: "男",
    },]
app.get('/list', (req, res) => {
    res.send(stus)
})

组件中: 

      //配置多个代理服务器地址,这里要加上前缀
      axios.get("http://localhost:8080/api1/list").then(({ data }) => {
        this.students = data;
      });
    原文作者:默默229
    原文地址: https://blog.csdn.net/qq_63011146/article/details/122786486
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞