程序人生 A log of my life

vue.js

router

route的代码组织也可以按照模块拼装到一起,这样每个模块的目录都有自己的router,代码的分割和维护更好一些。

router的一个重要的需要考虑的地方是history,如果不加任何控制,每次通过的跳转都会在history中加一条,这在手机端做为app是不合适的,比如几个平行tab,切换几次Tab,然后按手机的back,就会不停的逆向切换Tab,这多半不是用户想要的(应该直接退出),解决方法就是在route-link中加replace来控制history不增长。

带参数的router重新加载

很多时候,我们用同一个route带不同的参数,对应不同的内容,比如 /blog/:id,表示一条blog,那么问题来了,当切换id的时候,vue认为是同一条路由,不会重新加载,简单的解决方案就是:

<router-view :key="$route.fullPath" />

vuex

状态管理vuex是可选的,稍大的app都应该使用。一个常见场景是,多个page间切换、回退,如果每次都从服务器端加载数据,操作体验不好,所以要通过vuex把很多数据管理在全局store里,这样切换页面时,可以接近本地应用的体验。

vuex的核心是state,就是要管理的状态对象,同时封装了对state的两类操作mutation和action,可以把mutation理解为对state的同步修改,无关业务逻辑,action则是包含异步业务逻辑代码的,并且action并不直接修改state,而要通过mutation来修改(可以调用多次),这样整个封装就很清楚了。

为什么mutation要同步修改state,因为mutation遵循vux的响应规则,可以触发view的自动修改,所以必须同步修改掉state,因此所有需要异步操作后再修改state的操作必须封装在action里,另一个原因是同步的修改才可以被跟踪维护。

模板

有时为了使用v-if,或v-for,但不用不想绑定到任何tag上,可以使用内置的template标签,这样用:

<template v-if="ok">
  <h1>Title</h1>
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</template>

转义

  • 一般变量替换的时候内容都会被转义,html格式不再保留,可以用v-html=”var”来保留html格式。
  • 如果不希望vue处理一段标签,可以在上层标签加v-pre属性。

动态模板

在很多时间需要从服务器端返回一段模板,插入当前页面,这是动态模板的应用,要做到支持动态模板,需要完整版本的vue(包括compiler),而不仅是runtime版本,在webpack配置中需要增加一个alias,类似

vue: 'vue/dist/vue.js'

然后在模板文件中,使用下面的方式来嵌入动态模板

<component :is="dynamicTemplate()" />

dynamicTemplate函数需要返回编译好的模块,类似:

return Vue.compile('<div>' + dynamicContent +'</div>')

之所以再套一个div,是因为Vue的模块需要单根。另一个需要注意的问题是,如果在动态模板内容中依赖一些组件,这些组件需要提前注册好,可以使用vue的全局模块注册。

组件

自定义组件中实现v-model需要做一些事情,把v-model替换为:

<custom-component  :value="xxx"  @input="xxx = $event"></custom-component>

就知道组件里应该做什么了,通常类似这样:

Vue.component('custom-input', {
  props: ['value'],
  template: `<input value="value" @input="$emit('input', $event.target.value)">`
})

这里有一点不统一,$event.target.value是html的intput送出的input事件参数,而自定义组件里,需要直接把这个值放出做event参数,不再需要target了。

全局变量

一般不应该使用全局变量,如果是希望在所有组件共用,可以用instance Properties:

Vue.prototype.$var = 'value'

css

在vue的模块css部分,可以用scoped指定是否这个css全局生效。

如果某些css需要依据环境动态加载,比如移动端使用,桌面不使用,可以在index.template.html里用条件模板的方式加入,比如:

<% if (htmlWebpackPlugin.options.ctx.mode.cordova) { %>
  <style type="text/css">
    *:not(input):not(textarea) {
      -webkit-user-select: none; /* disable selection/Copy of UIWebView */
      -webkit-touch-callout: none; /* disable the IOS popup when long-press on a link */
    }
  </style>      
<% } %>

ajax

ajax组件在vue2中不是缺省内置的,在这里有解释, 官方的推荐是Axios

通用处理

使用axios很容易做通用处理,包括异常处理,比如

Vue.prototype.$http = Axios.create({
  baseURL: 'http://xxx.com/api',
  headers: {'token': 'abcdefg'}
})
Vue.prototype.$http.interceptors.response.use(
  response => { return response },
  error => { return error.response ? Promise.reject(error) : Toast.create.negative('网络出错了') })

ui

  • vant 有赞开源的ui库,非常轻量,自带icon,不错的组件设计

性能

大量的组件很容易导致render性能下降,可以在beforeCreated里加时标输出,再在mounted里加下面的时标输出:

this.$nextTick(function () {
  console.log(Date.now())
})

两个时标相减来评估初始化+render时间,最简单的优化方法是减少不必要的组件,将大部分组件转换为标准html可以有效提高render性能。