vue全家桶+element 项目踩坑总结

项目简介

vue + axios + vue-router + vuex + ElementUI

架构

vue

vue数据更新,视图不更新

只有当实例被创建时 data 中存在的属性才是响应式的,Vue 不能检测对象属性的添加或删除;
可以使用 Vue.set(object, key, value) 方法向嵌套对象添加响应式属性

Vue.set(vm.userProfile, 'age', 27)
this.$set(this.transportAddData.serviceOrderList[a].serviceOrderItems[i], 'deletePoundIds', [])

vue 数据与方法
vue 对象更改检测注意事项

Vue 不能检测以下变动的数组:

  • 当你利用索引直接设置一个项时,例如:vm.items[indexOfItem] = newValue
  • 当你修改数组的长度时,例如:vm.items.length = newLength

vue 数组更新检测

持续触发事件的优化

持续触发某个事件可以用函数的节流和防抖来做性能优化

//防抖
function(){  
    ...
    
    clearTimeout(timeoutId);

    timeoutId = setTimeout(function () {
      console.log('content', content);
      player(content.msgTypeId, comId)
    }, 500);
    
    ...
    
}

// 节流
var canRun = true;
document.getElementById("throttle").onscroll = function(){
    if(!canRun){
        // 判断是否已空闲,如果在执行中,则直接return
        return;
    }

    canRun = false;
    setTimeout(function(){
        console.log("函数节流");
        canRun = true;
    }, 300);
};

javaScript的Throttling(节流)和Debouncing(防抖)

nextTick

在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。



get() {
    this.$http.get('/api/article').then(function (res) {
        this.list = res.data.data.list
        // ref  list 引用了ul元素,我想把第一个li颜色变为红色
        document.querySelectorAll('li')[0].style.color = 'red'  //这里会报错-,因为还没有 li
        
        this.$nextTick( ()=> {
            document.querySelectorAll('li')[0].style.color = 'red'
        })
    })
},

Vue.nextTick 的原理和用途

音频文件自动播放报错

谷歌浏览器(Chrome 66)音频自动播放报错

DOMException: play() failed because the user didn’t interact with the document first.

解决方案:AudioContext

// Chrome
request.get('/baseConfig/messageAudio/play', {
    params: {
        "comId": Cookies.get('comId'),
        "msgTypeId": id
    },
    responseType: 'arraybuffer'   // 这里需要设置xhr response的格式为arraybuffer
    })
    .then(req => {
    
    ...
    
        let context = new (window.AudioContext || window.webkitAudioContext)();
        context.decodeAudioData(req.data, decode => play(context, decode));
                  
        function play (context, decodeBuffer) {
            sourceadio = context.createBufferSource();
            sourceadio.buffer = decodeBuffer;
            sourceadio.connect(context.destination);
            // 从0s开始播放
            sourceadio.start(0);
        }
    
    ...
    
})

Chrome 66禁止声音自动播放之后
AudioContext

AudioContext.decodeAudioData()

vuex

使用vuex修改state的方法和区别

  • 可以直接使用 this.$store.state.变量 = xxx;
  • this.store.dispatch(actionType, payload) 或者 this.store.commit(commitType, payload)

相同点:能够修改state里的变量,并且是响应式的(能触发视图更新)
不同点: 若将vue创建 store 的时候传入 strict: true, 开启严格模式,那么任何修改state的操作,只要不经过
mutation的函数,vue就会报如下错

throw error :    [vuex] Do not mutate vuex store state outside mutation handlers。

使用commit提交到mutation修改state的优点:vuex能够记录每一次state的变化记录,保存状态快照,实现时间漫游/回滚之类的操作。

dispatch 和 commit的区别在于:
使用dispatch是异步操作, commit是同步操作,
所以 一般情况下,推荐直接使用commit,即 this.$store.commit(commitType, payload),以防异步操作会带来的延迟问题。

vuex strict
vuex Mutation
vuex actions

vuex到底是什么

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    increment (context) {
      context.commit('increment')
    }
  }
})

==vuex中的state本质上是没有template的隐藏的vue组件。==

vuex工作原理详解

axios

兼容问题

Edge 41.16299.15.0 post请求会自动转为get

microsoft-edge/platform/issues
vue 使用axios 在EDGE浏览器上面post请求变成了get请求

取消请求

场景:每次请求在拦截器中添加token,后台判断token是否过期;当进入一个页面时触发多次请求,且正好token已经过期。这个时候需要第一次请求完成之后知道token已经过期则弹出提示、页面跳转到登录、停止之后的请求;否则会因为多次请求和axios响应拦截而多次弹框提示。

  • 解决方案
    axios自带cancelToken 取消方法,然后在路由跳转后停止之前的请求
// 请求拦截中 添加 cancelToken
axios.interceptors.request.use(config => {
    config.cancelToken = store.source.token
    return config
}, err => {
    return Promise.reject(err)
})
 
// 路由跳转中进行判断
router.beforeEach((to, from, next) => {
    const CancelToken = axios.CancelToken
    store.source.cancel && store.source.cancel()
    store.source = CancelToken.source()
    next()
})


//sort文件/
state: {
    source: {
      token: null,
      cancel: null
    }
  }

axios api
路由变化时使用axios取消所有请求
vue项目中 axios请求拦截器与取消pending请求功能

存在问题: 如果 token过期提示弹框为二次确认弹框,再次确认之后才会进行页面跳转,那么在点击确认之前,页面中之前的请求还是会继续进行;
解决方案:给弹窗添加全局状态,根据状态判断是否需要弹出弹框

预检请求

CORS跨域
CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,==IE浏览器不能低于IE10。==
浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。

  • 简单请求
  1. 请求方法是以下三种方法之一:
    HEAD
    GET
    POST
  2. HTTP的头信息不超出以下几种字段:
    Accept
    Accept-Language
    Content-Language
    Last-Event-ID
    Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

简单请求不会触发 CORS 预检请求。

  • 非简单请求

当请求满足下述任一条件时,即为非简单请求:

  1. 使用了下面任一 HTTP 方法:
    PUT
    DELETE
    CONNECT
    OPTIONS
    TRACE
    PATCH
  2. 人为设置了对 CORS 安全的首部字段集合之外的其他首部字段。该集合为:
    Accept
    Accept-Language
    Content-Language
    Content-Type (but note the additional requirements below)
    DPR
    Downlink
    Save-Data
    Viewport-Width
    Width
  3. Content-Type 的值不属于下列之一:
    application/x-www-form-urlencoded
    multipart/form-data
    text/plain
  4. 请求中的XMLHttpRequestUpload 对象注册了任意多个事件监听器。
  5. 请求中使用了ReadableStream对象。

HTTP访问控制(CORS)

  • 预检请求

非简单请求,会在正式通信之前,增加一次HTTP OPTIONS方法发起的查询请求,称为"预检"请求(preflight)。以获知服务器是否允许该实际请求。
"预检请求“的使用,可以避免跨域请求对服务器的用户数据产生未预期的影响。
==该方法不会对服务器资源产生影响==

  • 优化方案
Access-Control-Max-Age: <delta-seconds> //单位是秒。

表示 preflight request (预检请求)的返回结果(即 Access-Control-Allow-Methods 和Access-Control-Allow-Headers 提供的信息) 可以被缓存多久

Vue Router

push、replace的区别

push会向history添加新的记录,replace只是替换掉原来的记录,不会添加新的记录;
这就导致了用replace方法跳转的页面是无法回到之前的页面的;(类似window.history)

vue Router 编程式的导航

路由懒加载

为了提升页面加载速度,实现按需加载,也就是当路由访问时才加载对应组件,我们可以结合vue的异步组件和webpack的代码分割功能来实现路由的懒加载。

{
    path: '/iov/login',
    name: '登录',
    component: resolve => require(['@/views/login/login'], resolve),
},
{
    path:'/iov/organization',
    name:'组织管理',
    component:() => import('@/views/enterprise/organization')
}

vue Router 路由懒加载
vue 异步组件
vue + vue-router 懒加载 import / resolve+require

elementUI

表单弹窗中 elementform 清除验证残留提示

给表单添加不同的 ref (REFNAME),如果有相同的ref 会导致残留验证提示清除失败

    this.dialogTranspor = true
    //弹窗打开后 dom 没有生成,所有要用 this.$nextTick
   
    this.$nextTick(function () {
     
        this.$refs.REFNAME.resetFields();

      })

页码数无法正常显示

场景:列表页在跳到详情或其他页面后再返回列表页,无法正常显示对应页数(页码数放在state中),但请求的数据时正常的;

解决方案:页码数、总页数必须要在同一个对象中,否则当前页码数不能正常显示

data() {
    return {
        //完成查询条件
        searchComplate: {        
        "comId": Cookies.get('comId'),
        "transportOrderCode": null,
        "orderCode": null,
        "customerId": null,
        "abnormal": 2,
        "startTime": null,
        "endTime": null,
        "pageNum": 1,
        "pageSize": 20,
        total: 0,
        currentRow: '',
        dataArea: ['', ''],
        activeName: '',
        expands: []
        },
    }
}

动态多级表单验证

<li v-for="(item,index) in transportAddData.serviceOrderList">
 
    <template v-for="(subItem,subIndex) in item.serviceOrderItems">
    
        <tr >
                    
            <td>
              <el-form-item :prop="'serviceOrderList.'+index+'.serviceOrderItems.' + subIndex + '.addressName'"
                            :rules="{required: true, message: '卸货地不能为空', trigger: 'blur'}">
                <el-input v-model="subItem.addressName" placeholder="地址"></el-input>
              </el-form-item>
            </td>
            <td>
              <el-form-item :prop="'serviceOrderList.'+index+'.serviceOrderItems.' + subIndex + '.planTonnage'"
                            :rules="[{required: true, message: '必填项', trigger: 'blur'},{pattern: /^((([1-9]+(\d+)?)(\.\d+)?)|(0\.\d+))$/, message: '必须为正数且不为0'}]">
                <el-input v-model="subItem.planTonnage"
                          placeholder="预卸吨数"></el-input>
              </el-form-item>
            </td>
            ...
            
        </tr>
        
    </template>

</li>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容

  • VUE Vue :数据驱动的M V Vm框架 m :model(后台提供数据),v :view(页面),vM(模板...
    wudongyu阅读 5,374评论 0 11
  • vue-cli搭建项目 确保安装了node与npm 再目标文件夹下打开终端 执行cnpm i vue-cli -g...
    Akiko_秋子阅读 3,212评论 1 22
  • ## 框架和库的区别?> 框架(framework):一套完整的软件设计架构和**解决方案**。> > 库(lib...
    Rui_bdad阅读 2,890评论 1 4
  • _________________________________________________________...
    fastwe阅读 1,365评论 0 0
  • 一 我和吴睿是室友。大学刚开学认识的。 当时她留着过肩卷发,在宿舍忙来忙去,微胖的脸上冒着细细的汗珠。 父母来送她...
    大个儿鸭梨阅读 569评论 2 4