美文网首页
我在vue开发中的小技巧

我在vue开发中的小技巧

作者: KlivitamJ | 来源:发表于2018-08-23 14:32 被阅读105次

    我好不容易鼓起勇气买了一手小米,还准备等着这货下崽呢!这货就闹分手。每天下班都会有一个同事在我耳旁放风买facebook,我正准备等加班结束买一手,结果facebook来了一次“跳水”。屋漏偏逢连夜雨 呀!
    今天9点半就下班了,终于有时间写东西了。本来考虑去写es6和异步操作的,写着写着感觉有点写不下了,然后想写书评,但是写着写着又发现感悟不深,想再读一遍再说。回头一想我最近一直加班,写了很多代码,那我就从代码说起讲讲我项目经验。

    一、 js适配经验:

    我们在写代码的时候,很有可能写到这种代码:

    [1,2,3,4,5].includes(1)
    

    或者是使用promise等es6的方法,但是我们的需求是在Android4.4上面完美运行。这样就会出现includes is not undefied等错误提示。如果看了我之前谈到webpack的文章就会疑问:我们之前不是用了babel插件用来转成es5了呢?我当时也疑问了好久,直到我在webpack里面找到一个插件,具体的使用方法:

    import "babel-polyfill"
    import es6Promise from 'es6-promise'
    es6Promise.polyfill()
    require('es6-promise').polyfill()
    
    // webpack配置文件处
      entry: {
        app: ['babel-polyfill', './src/main.js']
      },
    

    二、 全局定义

    我们在写代码的时候,很有可能会封装很多库。如果存在有很多页面都在使用该库的情况,很可能会出现下面的代码:

    // vue 1
    import utils from "library"
    // vue 2
    import utils from "library"
    ...
    // vue n
    import utils from "library"
    

    就像我封装的http方法一样,我一般会这样处理

    import Vue from 'vue'
    import http from "http/http"
    Vue.prototype.$okhttp = http
    
    // use
    this.$okhttp
    

    这样会节省很多没有必要的代码量

    三、 自定义目录

    在写代码的时候,很多时候都存在这种情况 :

    import component1 from "../../../../component"
    import component2 from "../../../../../component"
    

    这种代码是新手很可能出现的,如果一旦出现一个层级目录出问题了,或者是文件的位置被转移过了就会出问题。看过之前我写的webpack文航的都会知道。

    module.exports = {
      context: path.resolve(__dirname, '../'),
      entry: {
        app: ['babel-polyfill', './src/main.js']
      },
      output: {},
      resolve: {
        extensions: ['.js', '.vue', '.json'],
        alias: {
          'vue$': 'vue/dist/vue.esm.js',
          '@': resolve('src'),
          'components': resolve('src/components'),
          'pages': resolve('src/pages')
        }
      },
      module: {
    },
      node: {
      },
      plugins: [],
    }
    

    在resolve->alias里面可以配置绝对相对路径,在使用的时候

    import component1 from "pages/component"
    import component2 from "pages/component"
    

    四、 路由懒加载

    我看官方文档里面定义路由的时候都有两步:

    import Vue from 'vue'
    import Router from 'vue-router'
    import xxx from 'xxx'
    Vue.use(Router)
    
    const router = new Router({
      routes: [
        {
          path: '/',
          component: xxx,
        }
    ]
    })
    

    这样写虽然没有错误,但是我们在做大型项目的时候 很可能定义很多很多个路由,那样页面就会写的特别多。此时懒加载就会解决这个问题

    import Vue from 'vue'
    import Router from 'vue-router'
    Vue.use(Router)
    
    const router = new Router({
      routes: [
        {
          path: '/',
          component: () => import("xxx")
        }
    ]
    })
    

    当然这个也不是强制要求,个人推荐

    五、 样式污染和样式覆盖的问题

    在我们新建vue的时候,经常会看到scoped

    <style scoped>
    </style>
    

    如果我们去掉scoped的时候会发现,在本vue项目内定义的css属性会影响到其他vue页面的css属性。这个就很坑了。所以,我们在使用的时候一定要用scoped

    但是在实际的开发中,也会遇到这么个问题。就拿我们项目来说,我用的是elementUI,虽然里面的资源库很强大,但是里面的视图不能完全符合策划的需求,此时就需要进行微调。

    <style lang="stylus" scoped>
      .custom-dialog
        .el-dialog__header
          padding 0
        .el-dialog__body
          padding 0
    </style>
    

    如果此时我们加上scoped标签的话,我们发现并没有效果,发现去掉scoped才会起作用。

    六、 mock、mock

    很多情况下,后台还没有搭建完成之前。可能前端没办法进行数据的接入。这种情况可能是一个大问题,这样会严重拖慢项目开发,此时就需要mock
    首先在webpack.dev.conf.js里面配置express,别问我为什么要在dev里面配置

    const express = require('express')
    const app = express()
    const appData = require('../static/data/user.json')
    const apiRouter = express.Router()
    app.use('/api',apiRouter)
    

    然后将接口通过devServer发布出去:

     before(app) {
      app.get('/api/user',(req, res) => {
        res.json({
          data: appData
        })
      })
    }
    

    使用的时候就直接打开http://localhost:8080/api/user,就可以了。

    六、 代理解决跨域

    有些时候,在进行本地开发的时候,可能会遇到跨域的问题。为了解决这个问题呢?主要有两种方法:
    1、 服务器设置
    服务端设置很简单,就是将本地开发的东西加上“Access-Control-Allow-Origin”, “*”,或者是直接将本地开发的ip直接设置成白名单,这样就可以了.
    2、 本地代理
    首先引入

    npm install http-proxy-middleware --save
    

    然后在index.js的标签下proxyTable使用

    '/lesson': {
            target: 'http://xxx/v2/webapi/lesson', // 代理的网址
            changeOrigin: true, // 允许跨域
            pathRewrite: {
             '^/lesson': '/'
           }
      }
    

    使用的时候,就直接使用

     axios({
            method: 'get',
            url:'/lesson' ,
            params: qs.stringify(data)
          }).then(function (res) {
            if (res) {
              //...
            }
          });
        }).catch(function (error) {
          console.error(error);
        })
    

    七、 页面统一判断

    在开发中经常会遇到权限判断的问题,我们又不可能在每一个页面的生命周期中去判断一下,那样太消耗时间了,我的处理:

    router.beforeEach((to, from, next) => {
      myAccess.checkhaveAccess(to.path) === true ? next() : next('/forbid')
    })
    

    八、 事件的传递:

    一般来说事件的传递有很多种,比如父子之间传递数据就可以直接用props,和emit来做关联。
    父组件给子组件传递

    // 父组件
    <parent>
        <child :datas="content"></child> 
    </parent>
    
    data(){
        return {
            content:'sichaoyun'
        };
    }
    
    // 子组件
    
    props:["datas"];
    // 或者是 
    props: {
     datas: String
    }
    

    子组件给父组件传递

    // 子组件
    <template>
        <div @click="open"></div>
    </template>
    
    methods: {
       open() {
            this.$emit('showbox','the msg'); //触发showbox方法,'the msg'为向父组件传递的数据
        }
    }
    // 父组件
    <child @showbox="toshow" :msg="msg"></child> //监听子组件触发的showbox事件,然后调用toshow方法
    
    methods: {
        toshow(msg) {
            this.msg = msg;
        }
    }
    

    兄弟组件之间的传递一般有几种方式:
    1、 注册全局事件
    2、 vuex
    3、 localstorage
    关于后面两个,我会专门来讲这个的,我主要是讲全局事件吧,代码如下:

    let vm = new Vue(); //创建实例
    
    <div @click="ge"></div>
    methods: {
        ge() {
            vm.$emit('click',data); //触发事件
        }
    }
    
    <div></div>
    created() {
      vm.$on('click', (arg) => { 
        });
    }
    

    九、 列表渲染

    v-for循环绑定model:

    这个是我在一个微信公众号上面看到的写法,很新颖:

     // 数据    
          data() {
              return{
               obj: {
                  ob: "OB",
                  koro1: "Koro1"
                },
                model: {
                  ob: "默认ob",
                  koro1: "默认koro1"
                }   
              }
          },
        // html模板
        <div v-for="(value,key) in obj">
           <input type="text" v-model="model[key]">
        </div>
          // input就跟数据绑定在一起了,那两个默认数据也会在input中显示
    

    v-if尽量不要与v-for在同一节点使用:

    v-for 的优先级比 v-if 更高,如果它们处于同一节点的话,那么每一个循环都会运行一遍v-if。

    如果你想根据循环中的每一项的数据来判断是否渲染,那么你这样做是对的:

        <li v-for="index in datas" v-if="Object.is(index,0)">
          {{ index }}
        </li>
    

    如果你想要根据某些条件跳过循环,而又跟将要渲染的每一项数据没有关系的话,你可以将v-if放在v-for的父节点:

     // 根据elseData是否为true 来判断是否渲染,跟每个元素没有关系    
         <ul v-if="condition">
          <li v-for="index in datas">
            {{ index }}
          </li>
        </ul>
        // 数组是否有数据 跟每个元素没有关系
        <ul v-if="datas.length">
          <li v-for="index in datas">
            {{ index }}
          </li>
        </ul>
        <p v-else>没有更多数据</p>
    

    十、 深度watch与watch立即触发回调

    这个是我偶尔在vuejs官网上面发现的,watch有两个可选参数,但是好像版本有限制,具体请移步官方文档。查看版本信息
    选项:deep
    在选项参数中指定 deep: true,可以监听对象中属性的变化。
    选项:immediate
    在选项参数中指定 immediate: true, 将立即以表达式的当前值触发回调,也就是默认触发一次。

    十一、 路由的项目启动页和404页面

      export default new Router({
          routes: [
            {
              path: '/', // 项目启动页
              redirect:'/login'  // 重定向到下方声明的路由 
            },
            {
              path: '*', // 404 页面 
              component: () => import('./notfind')
            },
          ]
        })
    

    比如你的域名为:www.baidu.com

    项目启动页指的是: 当你进入www.baidu.com,会自动跳转到login登录页。

    404页面指的是: 当进入一个没有 声明/没有匹配 的路由页面时就会跳转到404页面。

    比如进入www.baidu.com/testRouter,就会自动跳转到notFind页面。

    当你没有声明一个404页面,进入www.baidu.com/testRouter,显示的页面是一片空白。


    说在最后

    这篇文章了写了好久了,我已经不知道当初想要写什么了。我早上快下班的时候,随手修改了一下,但是上面的内容确实是我在项目里面经常会用到的一些小技巧。可能有些瑕疵。但是或多或少也是总结了我一些经验的。

    相关文章

      网友评论

          本文标题:我在vue开发中的小技巧

          本文链接:https://www.haomeiwen.com/subject/novimftx.html