前端下载文件(exe,zip,js等)的几种方式

闲来无事,总结一下这些东西:

前端一般通过创建a标签下载文件

图片:分为本地和后端传,本地直接require引入路径后创建a标签下载:

private downFun() {
    let a=document.createElement('a')
    a.style.display = 'none'
    a.setAttribute('download', 'bg.jpg')
    a.href = require('@/assets/bg.jpg')
    document.body.appendChild(a)
    console.log('href', a.href)
    a.click()
    document.body.removeChild(a)
  }

后端传的话需要调用get接口。

其它文件类型下载基本都是一样的 调用后端get接口,使用blob类型

responseType: ‘blob’。进行下载

注意:如果要是本地下载一些静态资源(除图片外) 资源要放在public目录文件下,不然打包后路径你会发现很多报错,下载找不到路径。@这个不会被解析。

附下载代码:

async download(){
    console.log(this.urlName)
    let res = await axios.get(`jt/${this.urlName}`, { responseType: 'blob' })
    const url = window.URL.createObjectURL(res.data)
    const link = document.createElement('a')
    link.href = url;
    link.setAttribute('download', `${this.urlName}`)
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
  }

jt/${this.urlName}

jt是public下的一个文件夹, this.urlName是你要下载的文件的名字。

vue项目权限,路由设计

现在我项目用的方法

路由设计:路由表中会定义两个路由表,一个为公共路由表,一个为动态路由表。动态路由根据登录账户的权限去获取。取到权限后,根据roles中的字段,去遍历动态路由表中的对应的路由表。

最后将获取到的符合权限的路由,通过router.addRouter()合并到固定路由下面,,再用到router.beforeEach()去做路由判断,让权限更牢靠

常用方法

第一种

1.对路由跳转进行判断,如果符合权限就允许,反之就不行

2.对跳转页面进行逻辑请求判断,就是页面数据需要一定的权限才能发送请求(这样需要后端人员给你做,个人感觉不太现实,后端估计想干你)

3.根据权限,动态生成对应的路由,什么权限拥有什么路由(vue-element-admin)就是这么做的,动态生成路由

前端常用方法一般是:  v-if + router.beforeEach()

由于后端管理界面涉及到,对登陆用户的权限判断,可能做的好点的后端管理页面,要么把相对应的跳转事件进行隐藏或判断,或者把跳转页面进行隐藏,我之前也是这样做的,对跳转的路由按钮进行  v-if  判断,然后再在router.beforeEach()进行路由判断,这样就可以防止部分用户,根据请求地址来实现跳转

第二种

对跳转的按钮事件进行权限判断


对跳转页面的路由事件,添加一个方法,然后根据权限判断,if和else,满足就跳转,不满足就return,如果想要提升一下用户体验度,就弹出一个消息提示框,说您暂无权限

但是呢,用户体验度不是很好,而且权限是写死的,不具备灵活性

第三种

根据权限动态生成路由

第一步:

就是在你登陆以后,后端返回token,然后在请求成功的回调里面,又发送token去后端去获取当前用户的详细信息,信息中包括了你这名用户的权限,是否为管理员身份,还是次级管理员身份,然后将token存入cookie,将请求获取到的数据存入vuex!假设这个存储你权限的字段交roles,是个数组,类似:[’admin’] or [‘Secondary’] 

第二步:

这里要说明的是,路由表中会定义两个路由表,一个为公共路由表,一个为动态路由表,公共路由表就是不需要权限也能去访问,动态路由表顾名思义就是需要权限去获取了!然后根据获取到你的权限之后,会根据roles中的字段,去遍历动态路由表中的对应的路由表,然后将符合条件的路由表保存起来

第三步:最后将获取到的符合权限的路由,合并到固定路由下面,通过router.addRouter(),当然了这里还是要用到router.beforeEach()去做路由判断,让权限更牢靠一点

参考文献:

http://events.jianshu.io/p/1bbecc010fae

return返回html标签的问题

当你使用return返回如:<span class=’mtClass’>标签</span>

此类的话,返回时可能由于你的js运行在vue的实例化之后,这样它的渲染是无法渲染组件标签的。如elementUI的el-button.

若这时你返回<el-button>按钮</el-button>,在页面渲染时,它会直接标签化渲染成
<el-button>按钮</el-button>

正确应该是要渲染成<button class=’el-button’>按钮</button>

解决办法:

1.你直接用html的标签 然后自己写样式改

2.用render函数 写jxs代码

JSX是JavaScript XML的简写,表示在JavaScript代码中写XML ( HTML)格式的代码。


Vue渲染组件底层用的是render函数

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>lesson 31</title>
  <script src="https://unpkg.com/vue@next"></script>
</head>
<body>
  <div id="root"></div>
</body>
<script>
  // render function
  // template -> render -> h -> 虚拟DOM(JS对象)-> 真实 DOM -> 展示到页面上
  const app = Vue.createApp({
    template: `
      <my-title :level="2">
        hello dell
      </my-title>
    `
  });

  app.component('my-title', {
    props: ['level'],
    render() {
      const { h } = Vue;
      return h('h' + this.level, {}, [
        this.$slots.default(),
        h('h4', {}, 'dell')
      ])
    }
  })

  const vm = app.mount('#root');
</script>
</html>

vue+echarts大屏地图以及在大屏上画线和数值(最新echart5.0)

最近公司要求开发一个大屏项目做到 :

直接上代码

首先做出地图效果

https://datav.aliyun.com/tools/atlas/#&lat=30.332329214580188&lng=106.72278672066881&zoom=3.5

上面链接里获取你想要的城市,省份json数据,再将其放入你的项目文件中

下面核心代码:

 
  <div class="echart_map" ref="hunan_map">
 
 
 
 
var hunan = require(`../../assets/js/湖南省.json`)  // 引入json
methods: {
 
 // echart单位换算
    nowSize (val,initWidth) {
      initWidth = 1920
      return val * (this.c_width / initWidth);
    },
 huNanMap (val) {
      var that = this
      this.$echarts.registerMap('hunan', hunan); // 取数据
      var myChart = this.$echarts.init(this.$refs.hunan_map)
 
      var data = json.data;
      var series = [];
 
        // 画线,点的函数
        var convertLineData = function (data) {
        var res = [];
        for (var i = 0; i < data.length; i++) {
          var dataItem = data[i];
          var coordS = dataItem.lineS; // 线起点
          var coordM = dataItem.lineM; // 线中间点
          var coordE = dataItem.lineE; // 线尾点
          if (coordS && coordM && coordE) {
            res.push({
              coords: [coordS, coordM, coordE]
            });
          }
        }
        return res;
      };
      var convertValData = function (data) {
        var res = [];
        for (var i = 0; i < data.length; i++) {
          var dataItem = data[i];
          res.push({
            name: dataItem.areaName,
            value: dataItem.lineE.concat(dataItem.value)
          });
        }
        return res;
      };
        
        // 这里是你要在地图上画的点,线配置,往data里面加就行
        var json = {
        data: [{
          areaName: '长沙市',
          value: 94,
          lineS: [113.482279,28.19409],
          lineM: [113.441, 28.4242],
          lineE: [113.8648, 29.2891]
        }]
            };
 
      series.push(
            {    // 这是画的线配置
          name: '',
          type: 'lines',
          zlevel: 2,
          symbol: 'none',
          // silent: true, //不响应鼠标点击或事件
          effect: {
            show: false // 关闭特效
          },
          tooltip: {
            show: false
          },
          labelLayout: {
            draggable: true
          },
          polyline: true, // 支持多点连线
          itemStyle:{
            normal:{
              lineStyle:{
                width: that.nowSize(2),
                type:'dotted' //'dotted'虚线 'solid'实线
              }
            }
          },
          lineStyle: {
            normal: {
              color: 'green',
              opacity: 0.9,
              curveness: 0
            }
          },
          data: convertLineData(data)
        },
        {   // 这里是点还有点旁边的内容
          name: '',
          type: 'scatter',
          coordinateSystem: 'geo',
          zlevel: 2,
          hoverAnimation: false, // hover时不高亮点
          cursor: 'default', // 鼠标设置为箭头
          itemStyle: {
            normal: {
              color: 'red'
            }
          },
          tooltip: {
            show: false,
          },
          label: {
            rich: {
              //自定义样式a
              a: {
                fontFamily: 'lcd',   //字体名称
                color: '#fff',  //字体颜色
                fontSize: that.nowSize(12),  //字体大小
                borderColor: 'rgba(30, 157, 222, 1)',
                borderWidth: that.nowSize(1.2),
                padding: [8, 8, 8, 8]
              },
              //**自定义样式b**
              b: {
                color: '#fff',
                fontSize: 16
              }
            },
            // normal: {
            show: true,
            position: 'right',
            fontSize: that.nowSize(14),
            fontWeight: 'bold',
            color: '#f5a623',
            formatter: function (param) {
              return '{a|' + param.value[2] + '/工单' + '}' // 此处用到自定义样式
            },
           
          },
          data: convertValData(data)
        }
        )
 
        var option = {  // 这里是地图内容配置
        // backgroundColor: '#404a59', // 背景色
        title: {
          text: '全省人工服务概况',
          left: 'center',
          textStyle: {
            color: '#2b9de0',
            fontSize: that.nowSize(18)
          }
        },
        tooltip: {
          trigger: 'item'
        },
        legend: {
          show: false,
          selectorLabel: {
            backgroundColor: 'black'
          }
        },
        geo: {
          map: 'hunan',
          label: {
            color: 'black',
            fontSize: that.nowSize(14),
            emphasis: {
              show: true,
              color: 'green',
              areaColor: 'yellow'
            },
          },
          roam: false,
          selectedMode: 'single',
          itemStyle: {
            areaColor: 'red',
            normal: {
              // areaColor: 'black', // 地图整体的颜色
              borderColor: '#404a59' // 边缘线颜色
            },
            emphasis: {
              itemStyle: {
                areaColor: 'red' // hover 的背景色
              }
            }
          },
          select: [{
            itemStyle: {
              areaColor: 'black' // hover 的背景色
            }
          }
          ],
          regions: [{ // 默认选择
            name: val.name,
            selected: true,
            itemStyle: {
              normal: {
                areaColor: '#AADDFF'
              }
              // areaColor: 'red', // 地图背景色
              // backgroundColor: 'black',
              // opacity: 0
            }
          },],
        },
        series: series
      };
      myChart.setOption(option);  // 应用配置
 
       // 加个点击事件
      myChart.on('click', function (e) {
        // e.color = '#d50000'
        if (e.hasOwnProperty('region')) {
          option.geo.regions[0].name = e.region.name
          myChart.setOption(option);
        } else {
          return false;
        }
        console.log(e.region,option)
      });
}

建议线画地图出来,再一步步移植代码。

线,点或者其它什么样式基本都是label里面能改,字体样式什么的就是itemStyle里面改。

反正2个互相用就能解决大部分问题

最后formatter是个很有用的东西,在这是编辑点右边的数据。你们可以自己定义。

最后放个echart文档地址

https://echarts.apache.org/zh/option.html#title

vuex模块化管理在正式项目中的运用及其注意事项

写下平时在心目中用的比较多的vuex标准化用法和介绍

vuex一般用于中大型项目,其内容有

state 存放状态
mutations state成员操作(处理数据,更改保存到state中。用法this.$store.commit )
getters 加工state成员给外界
actions 异步操作(一般用于处理请求逻辑之后将数据给mutations,用法this.$store.dispatch )
modules 模块化状态管理
modules 的每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割。

简单基础使用就不说了,说重点。

在项目中一般是以模块化管理为主。为了方便每个模块的管理和维护大多使用modules模块化状态管理。

上目录

这里面的actions.js和mutation是公共的方法(我自己的习惯)

getters.js和store.js是让外界得到state,公共数据。

index.js是将所有模块集合到一起。然后挂载到main.js上。

//index.js内容
 
import Vue from 'vue'
import vuex from 'vuex'
 
 
import getters from './getters'
import actions from './modules/actions'
import mutations from './modules/mutation'
import user from './modules/user.js'
import user2 from './modules/user2'
import state from './store'
Vue.use(vuex)
export default new vuex.Store({
 
  getters,
  state,
  //模块vuex
  modules: {
    //公共vuex2个模块
    actions,
    mutations,
 
    //各个单独模块使用的vuex
    user,
    user2
  }
})

使用modules后外面不要再加actions和mutations(会报错)

上其中一个单独模块的代码

//这里是user.js的代码
 
 
//某个模块专门使用的vuex。调用时加上该模块名字。如this.$store.commit('user/方法名')
 
const state = {
  userName:''
}
 
const getters = {
  userName:(state) => state.userName
}
const actions = {
  add_name({commit},name){
    commit('ADD_NAME',name);
    console.log('这里是user1的actions',name)
 
  },
}
const  mutations = {
  ADD_NAME(state,name){
    state.userName=name;
    console.log('这里是user1',name)
    return true;
  }
}
export default {
  namespaced: true,            //记住一定要加这个
 
  state,
  getters,
  actions,
  mutations
}

namespaced是告诉vuex给它搞个看见出来。默认false. 开启后就是提示打开了命名空间。这样2个模块有同样的方法也不会报错。

当你要调用某个模块的方法时记得写法是

this.$store.commit(‘模块名/方法名’)

this.$store.dispatch(‘模块名/方法名’)

一切弄完之后记得挂载到main.js上

import Vue from 'vue'
import App from './App'
import router from './router'
import Vuex from 'vuex'
import store from './store/index'
Vue.config.productionTip = false
Vue.use(Vuex)
 
 
/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  store,    //这就是挂载了
  components: { App },
  template: '<App/>'
})

有时候报错说未找到该模块有这个方法

报错信息为:

[vuex] unknown action type: user/add_name

你可以删除命名空间试试。

下面放其他js的代码

//actions.js代码
 
//公共actions异步方法
 
export default {//在action中可以进行异步操作。
  namespaced: true,
 
  actions:{
    add_book({commit},book){
      commit('ADD_BOOK',book);
    },
    delete_book({commit},book){
      commit('DELETE_BOOK',id);
    }
  }
}
 
 
 
//mutations.js代码
//公共mutation方法
export default {//这里要注意不要在mutations里面进行异步操作
  namespaced: true,
 
  mutations:{
    ADD_BOOK(state,book){
      state.bookList.push(book);
      return true;
    },
    DELETE_BOOK(state,id){
    }
  }
}

我觉得这样写便于管理,有的人喜欢给mutations加一个mutations_type的文件。其实就是将他们的方法名都注册一下。我不喜欢这样。

vue+element弹出框设置可以上下左右拉伸,移动,双击放大效果

在网上找了很多,移到项目后总不满意,然后结合着自己改了一个

直接放注册指令代码,需要自己生成一个js文件放进去,并在main.js里面引入


```javascript
Vue.directive('dialogDrags', {
  bind(el, binding, vnode, oldVnode) {
    // 弹框可拉伸最小宽高
    const minWidth = 400
    const minHeight = 300

    // 初始非全屏
    let isFullScreen = false

    // 当前顶部高度
    let nowMarginTop = 0

    // 获取弹框头部(这部分可双击全屏)
    const dialogHeaderEl = el.querySelector('.el-dialog__header')

    // 弹窗
    const dragDom = el.querySelector('.el-dialog')

    // 给弹窗加上overflow auto;不然缩小时框内的标签可能超出dialog;
    dragDom.style.overflow = 'auto'

    // 清除选择头部文字效果
    // dialogHeaderEl.onselectstart = new Function("return false");

    // 头部加上可拖动cursor
    dialogHeaderEl.style.cursor = 'move'

    // 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
    const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null)
    const moveDown = e => {
      // 鼠标按下,计算当前元素距离可视区的距离
      const disX = e.clientX - dialogHeaderEl.offsetLeft
      const disY = e.clientY - dialogHeaderEl.offsetTop

      // 获取到的值带px 正则匹配替换
      let styL, styT

      // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px

      if (sty.left.includes('%')) {
        styL = +document.body.clientWidth * (+sty.left.replace(/\%/g, '') / 100)
        styT = +document.body.clientHeight * (+sty.top.replace(/\%/g, '') / 100)
      } else {
        styL = +sty.left.replace(/\px/g, '')
        styT = +sty.top.replace(/\px/g, '')
      }

      document.onmousemove = function(e) {
        // 通过事件委托,计算移动的距离
        const l = e.clientX - disX
        const t = e.clientY - disY

        // 移动当前元素
        dragDom.style.left = `${l + styL}px`
        dragDom.style.top = `${t + styT}px`

        // 将此时的位置传出去
        // binding.value({x:e.pageX,y:e.pageY})
      }

      document.onmouseup = function(e) {
        document.onmousemove = null
        document.onmouseup = null
      }
    }

    dialogHeaderEl.onmousedown = moveDown
    // 当前宽高
    let nowWidth = 0
    // let nowHight = 0
    // 双击头部全屏效果
    dialogHeaderEl.ondblclick = e => {
      if (isFullScreen === false) {
        // nowHight = dragDom.clientHeight
        nowWidth = dragDom.clientWidth
        nowMarginTop = dragDom.style.marginTop
        dragDom.style.left = 0
        dragDom.style.top = 0
        dragDom.style.height = '100VH'
        dragDom.style.width = '100VW'
        dragDom.style.marginTop = 0

        isFullScreen = true

        dialogHeaderEl.style.cursor = 'initial'
        dialogHeaderEl.onmousedown = null
      } else {
        dragDom.style.height = 'auto'
        dragDom.style.width = nowWidth + 'px'
        dragDom.style.marginTop = nowMarginTop

        isFullScreen = false

        dialogHeaderEl.style.cursor = 'move'
        dialogHeaderEl.onmousedown = moveDown
      }
    }
    var llqWidth = document.body.clientWidth

    dragDom.onmousemove = function(e) {
      // let moveE = e

      if (
        e.clientX > dragDom.offsetLeft + dragDom.clientWidth - 10 ||
        dragDom.offsetLeft + 10 > e.clientX
      ) {
        dragDom.style.cursor = 'w-resize'
      } else if (
        el.scrollTop + e.clientY >
        dragDom.offsetTop + dragDom.clientHeight - 10
      ) {
        dragDom.style.cursor = 's-resize'
      } else {
        dragDom.style.cursor = 'default'

        dragDom.onmousedown = null
      }

      dragDom.onmousedown = e => {
        const clientX = e.clientX
        const clientY = e.clientY
        const seeCK = window.innerWidth
        
        const elW = dragDom.clientWidth
        const elH = dragDom.clientHeight
        const EloffsetLeft = dragDom.offsetLeft
        const EloffsetTop = dragDom.offsetTop

        dragDom.style.userSelect = 'none'
        dragDom.style.posiiton = 'absolute'
        const ELscrollTop = el.scrollTop

        // 判断点击的位置是不是为头部
        if (
          clientX > EloffsetLeft &&
          clientX < EloffsetLeft + elW &&
          clientY > EloffsetTop &&
          clientY < EloffsetTop + 100
        ) {
          // 如果是头部在此就不做任何动作,以上有绑定dialogHeaderEl.onmousedown = moveDown;
        } else {
          document.onmousemove = function(e) {
            // 移动时禁用默认事件
            e.preventDefault()

            // 左侧鼠标拖拽位置
            if (clientX > EloffsetLeft && clientX < EloffsetLeft + 10) {
              console.log('左边',clientX,e.clientX,elW)
              dragDom.style.left='auto'
              // 往左拖拽
              if (clientX > e.clientX) {
                dragDom.style.right=llqWidth-clientX-elW + 'px';
                let sp = llqWidth-clientX-elW;
                dragDom.style.width = elW + (clientX - e.clientX)  + 'px'
                // console.log('左边加',nowWidth,llqWidth,seeCK,sp,clientX)
              }

              // 往右拖拽
              if (clientX < e.clientX) {
                if (dragDom.clientWidth < minWidth) {
                  dragDom.style.width = minWidth
                //   console.log('youbian')
                } else {
                //   console.log('右边')
                  dragDom.style.right=llqWidth-clientX-elW + 'px';
                  dragDom.style.width = elW - (e.clientX - clientX)  + 'px'
                }
              }
            }

            // 右侧鼠标拖拽位置
            if (
              clientX > EloffsetLeft + elW - 10 &&
              clientX < EloffsetLeft + elW
            ) {
                dragDom.style.right='auto'
              // 往左拖拽
              if (clientX > e.clientX) {
                if (dragDom.clientWidth < minWidth) {
                //   console.log('左')
                } else {
                  dragDom.style.width = elW - (clientX - e.clientX)  + 'px'
                //   console.log('左336666')
                }
              }

              // 往右拖拽
              if (clientX < e.clientX) {      
                dragDom.style.left=EloffsetLeft + 'px';    
                dragDom.style.width = elW + (e.clientX - clientX) + 'px'
                // console.log('右',EloffsetLeft)
              }
            }

            // 底部鼠标拖拽位置
            if (
              ELscrollTop + clientY > EloffsetTop + elH - 20 &&
              ELscrollTop + clientY < EloffsetTop + elH
            ) {
              // 往上拖拽
              if (clientY > e.clientY) {
                if (dragDom.clientHeight < minHeight) {
                //   console.log('上')
                } else {
                  dragDom.style.height = elH - (clientY - e.clientY)  + 'px'
                //   console.log(3333)
                }
              }

              // 往下拖拽
              if (clientY < e.clientY) {
                // console.log('下')
                dragDom.style.height = elH + (e.clientY - clientY)  + 'px'
              }
            }
          }

          // 拉伸结束
          document.onmouseup = function(e) {
            document.onmousemove = null
            document.onmouseup = null
          }
        }
      }
    }
  }
})

使用的时候记得这里设置:close-on-click-modal=“false”,避免影响

<el-dialog   v-dialogDrags :close-on-click-modal="false"  title="转账" :visible.sync="isVisibles" align='left' @close="closeDialogs" class="transfer">
   </el-dialog>     

vue优化,解决bug: Waiting for update signal from WDS…时间过长,keep-alive包裹的navtab切换组件不断切换导致页面卡顿以及浏览器内存过高

keep-alive包裹的navtab切换组件不断切换导致页面卡顿以及浏览器内存过高

当这个navtab不断切换时,js heap size就会慢慢变高。

解决办法:

1:查找一下setTimeout定时器有没有清除

2:keep-alive缓存是否清除

3:是否用了iframe (很大嫌疑)

当你的页面上的iframe是直接引用而不是隐藏在组件弹出框中的话,就会造成:每次切换到这个页面,除非秒切,不然会触发webpack的dev机制,引发 Waiting for update signal from WDS…。
而在 Waiting for update signal from WDS…中时,你必须等待它加载完毕再运行,不然任何操作都会让浏览器内存暴涨,而这个想让它释放掉很困难。

vue打包报错 ERROR in static/js/0.4403c1dd262870db3c27.js from UglifyJs TypeError: Cannot read property ‘

打包报错
ERROR in static/js/0.4403c1dd262870db3c27.js from UglifyJs
TypeError: Cannot read property ‘sections’ of null

网上有很多种方法,比如在webpack.base.conf.js的路径种添加框架的css,js什么的,一一试过都不好使
下面是重点

打开你的 webpack.prod.conf.js 文件,找到 plugins 下面的

new UglifyJsPlugin({
uglifyOptions: {
compress: {
warnings: false,
}
},
sourceMap: config.build.productionSourceMap,
parallel: true
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
drop_debugger: true,
drop_console: true
},
sourceMap: true
}),

将其注释掉 再打包 报错没了

原因: 有时候你把版本放上去(没放node_modules文件),自己拉下来install的时候。会根据脚手架等环境不同安装些与当时放上去时多余的东西,其实也就是它版本更新了什么的。所以注销掉就可了。

vuex的5个核心及封装接口函数

5个核心分别为:state , getter , mutation , action , module

satae:

为单一状态树,在其中定义我们所需要管理的数组,对象 ,字符串等等。定义后在vue.js组件中才可获取你定义的这个对象状态

getter:

有点类似vue.js的计算属性,需要从store的state中派生出一些状态,我们就要用getter,它接收state作为第一个参数,而且getter的返回值会根据它的依赖被缓存起来,只有getter中的依赖值(state中某个需要派生状态的值)发生改变时才会被重新计算。

(注意,getter 在通过方法访问时,每次都会去进行调用,而不会缓存结果。

mapGetters 辅助函数:

 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性:

mutation:

更改store中state状态的唯一方法就是提交mutation,类似于事件。每个mutation都有一个字符串类型的事件类型和一个回调函数,要改变state的值就在回调函数中改变,要执行这个回调函数,我们需要一个相对应的调用方法:store,commit (必须是同步函数)

commit是仅仅用来提交mutation的,这个过程是同步进行的

dispatch:含有异步操作,例如向后台提交数据,写法: this.$store.dispatch(‘action方法名’,值)

commit:同步操作,写法:this.$store.commit(‘mutations方法名’,值)

Store就是把它们联系到一起的对象。Store有以下职责:

维持应用的state:
提供getState( )方法获取state;
提供dispatch(action)方法更新state;
通过subscribe(listener)注册监听器;
通过subscribe(listener)返回的函数注销监听器

提供dispatch(action)方法更新state;
store.dispatch(‘TOGGLE_LOADING’)

这个其实是在store中触发改变它里面的值!

action:

重点:action可以提交mutation,在action中执行store,commit且action中可以又任何异步操作(异步函数写这里)在页面要调用这个action则需执行store,dispatch(还用commit来提交mutation)

module:

它解决了当state中很复杂,囊肿时,module可以将store分割成一个个模块,每个模块都有自己的state,mutation,action,getter。

在封装函数时你先要在一个js文件中建立
state , mutation , action , getter 这4个模块。如:

import Vue from 'vue'

const state = {
  userId: '',
  // 登录状态
  loginStatus: fal
  queryUserInfoHttp: null
}
const getters = {
  getUser: state => {
    return state
  },
  getLoginStatus: state => {
    return state.loginStatus
  }
}
const mutations = {
setQueryUserInfoHttp (state, http) {
    state.queryUserInfoHttp = http
  }
}
const actions = {
  helpCenter_sj: ({commit}, data) => {
    return new Promise((resolve, reject) => {
      let shuju = Vue.http.get('/help/listUI', {params: {type: data.type}})
      resolve(shuju)
      reject(shuju)
    })
  }
}

export default {
  state,
  getters,
  actions,
  mutations
}

这 helpCenter_sj函数是我的处理跳转函数

注意:

Vuex 中 使用 Action 处理异步请求时,常规写法如下:

   getMenuAction:(context) =>{
            context.commit('SET_MENU_LIST',['承保2','核保2'])
        }
    }

我们也可以使用如下简化写法,如下:

   actions:{
        getMenuAction:({commit}) =>{
            commit('SET_MENU_LIST',['承保2','核保2'])
        }
    }

为了更好理解我们来看看
 Vuex 中 注册 Action的源码如下

红圈起来的都是它的属性,它每次都接受2个参数。

再来解释 return new Promise((resolve, reject) => {}这条语句

先 打印出来看看

Promise是一个构造函数,自己身上有all、reject、resolve这几个眼熟的方法,原型上有then、catch等同样很眼熟的方法。这么说用Promise new出来的对象肯定就有then、catch方法

Promise的构造函数接收一个参数,是函数,并且传入两个参数:resolve,reject,分别表示异步操作执行成功后的回调函数和异步操作执行失败后的回调函数。其实这里用“成功”和“失败”来描述并不准确,按照标准来讲,resolve是将Promise的状态置为fullfiled,reject是将Promise的状态置为rejected。 (这是简单的解释,更详细解释看https://blog.csdn.net/Wbiokr/article/details/79490390)

这条语句 let shuju = Vue.http.get(‘/help/listUI’, {params: {type: data.type}})

意思是调用 /help/listUI 这个接口,接受条件是type是 data.type 并把得到的值给局部变量shuju

resolve(shuju)
reject(shuju)

分别表示了当 成功/失败 时传回去什么值。

然后在调用界面

this.$store.dispatch('helpCenter_sj', {
type: 1
}).then(response => {

}

这样来调用调用store里的dispatch然后这个属性特效可以调用你刚刚写在js文件里面的某个函数(这个js文件一定要引入,我这是全局引入 import user from ‘./modules/user’ )

这样的话就调用成功了。

后续会继续更新。

Vue循环实现多个div盒子展示和其中button按钮等跳转路径设置

 
<div>
<div v-for="item in Arr" :key="item.id">
<p>{{item.name}}</p>
<button @click="gopage" ><span>查看详情</span></button>
</div>
</div>

直接在你要循环的盒子上写 v-for=”item in Arr”。在<script>中写Arr数组,给button一个点击事件,当点击button跳转到它相应的页面。

 
methods:{
gopage:function () {
alert(this.Arr[2].url)
this.$router.push({ path:this.Arr[2].url })
}
}

一定要注意!path后面如果是单纯不变的路径要加单引号,如

 
this.$router.push({ path:'@/pages/account/dialog/contact' })

还要注意,你要跳转的页面,一定要在你的index.js中配置过的。如:

 
{
path: 'contact',
name: 'contact',
component:
resolve => require(['@/pages/account/dialog/contact'],resolve),
meta:{
title:'联系我们',
group: 'Dialog'
}
}

跳转语句还可以这么写,前提是你一定要在路由中写了name

 
this.$router.push({name: 'contact'})

最主要的!!如果你的路径是个变量,一定不要加单引号! 一定不要加单引号! 一定不要加单引号! 

说多了都是泪,顺便一提,当你用img的src路径时,当src路径是变量,可能会出现路径解读问题,说undefind,那是因为你的路径第一次解读就被解读成为了字符串,解决方法要加require。如:

 
<img :src="require(`./img/${item.EnName}.jpg`)" alt="flowers">
在其他地方引用也要写成require(`./img/${item.EnName}.jpg`)。

最后帖一下我的代码

 

<style>
.solve_flex{
display: flex;
justify-content:space-around;
align-items:center;
padding-top: 20px;
width: 100%;
height: 516px; }
.module_smallbox{
width: 360px;
height: 410px;
background: red; }
.solve_span{
font-family:PingFangSC-Regular;
font-size:20px;
color:#333333;
text-align:left; }
.home_onebutton span{
font-family:PingFangSC-Regular;
font-size:14px;
letter-spacing:0.59px; }
.home_onebutton:hover{
color: #0b85ef;
border-color: #0b85ef;
transition: all 0.3s; }
</style>


上面是CSS


<template>
<div class="solve_flex">
<div class="module_smallbox"
v-for="(item,index) in Arr" :key="item.id">
<p class="solve_span ml25 mt30">{{item.name}}</p> <button class="home_onebutton mt15 ml25"><span>查看详情</span></button>
</div>
</div>
</template>
<script>
export default {
name: 'home',
data () {
return {
Arr:[
{id:1,name:"整套区块链解决方案",url:"/Privacy/contact"}, {id:2,name:"多链云钱包解决方案",url:"/Privacy/contact"}, {id:3,name:"智能合约工具",url:"/Privacy/contact"}]
}
},
created() {
},
methods:{
gopage:function () {
alert(this.Arr[2].url)
this.$router.push({ path:this.Arr[2].url })
}
}
}
</script>