美文网首页Html我爱编程Vue
vue 实战各种小技巧(长期更新)

vue 实战各种小技巧(长期更新)

作者: sunxiaochuan | 来源:发表于2018-04-11 10:27 被阅读517次

    1. vue-cli 构建项目

    官网地址

    • 命令行
    # 全局安装 vue-cli
    $ npm install --global vue-cli
    # 创建一个基于 webpack 模板的新项目
    $ vue init webpack your-project-name
    # 安装依赖,走你
    $ npm install
    # 进入项目
    $ cd your-project-name
    # 开发版本打包并运行
    $ npm run dev
    # 线上环境整个项目打包  生成 dist 可以直接部署到服务器上的文件夹
    npm run build
    

    2. 项目模板中使用 less 方法

    原文地址
    vue-cli 构建的项目默认是不支持 less 的,需要自己添加。

    • 首先安装 less 和 less-loader ,在项目目录下运行如下命令
    # npm安装
    $ npm install less less-loader --save-dev
    # 或者使用 yarn
    $ yarn add less less-loader --dev
    
    • 安装成功后,打开 build/webpack.base.conf.js ,在 module.exports = 的对象的 module.rules 后面添加一段:
    module.exports = {
        //  此处省略无数行,已有的的其他的内容
        module: {
            rules: [
              //  此处省略无数行,已有的的其他的规则
              {
                test: /\.less$/,
                loader: "style-loader!css-loader!less-loader",
              }
            ]
        }
    }
    
    image.png
    • 最后在代码中的 style 标签中 加上 lang="less" 属性即可
    <style scoped lang="less">
    
    </style>
    
    image.png
    • 之后在项目中测试是否成功
    npm install less less-loader --save-dev
    npm run dev
    
    image.png
    • 在浏览其中打开相应页面,这个页面是 / 根页面点击跳转过来的子路由
    image.png
    image.png

    可以看到样式编译成功了 哦耶~

    3. 在 router 下的路由文件里设置格式,将页面上路由中默认显示的 #/ 给去掉

    // 去掉路由中自带的 #/ 这种东西
      mode: 'history',
    
    image.png
    • 需要注意的是使用了 history 之后需要在服务器部署时增加一些配置,具体方法插件下面官方写的配置方法

    配置方法

    4. 引入 jquery

    • 安装
    npm install jquery --save
    
    • 配置
    image.png
    image.png
    // 先在顶部引入 webpack
    const webpack  = require('webpack')
    
    // plugins 中添加
    new webpack.ProvidePlugin({
          'window.jQuery': 'jquery', // 为了兼容其他的插件
          jQuery: 'jquery',
          $: 'jquery'
        })
    
    • 使用
    image.png

    5. :class 使用表达式

    :class="{'想要改变的类名': 判断条件}
    
    • 示例图片
    image.png

    6. DOM 事件修饰符

    <!-- 阻止单击事件继续传播 -->
    <a v-on:click.stop="doThis"></a>
    
    <!-- 提交事件不再重载页面 -->
    <form v-on:submit.prevent="onSubmit"></form>
    
    <!-- 修饰符可以串联 -->
    <a v-on:click.stop.prevent="doThat"></a>
    
    <!-- 只有修饰符 -->
    <form v-on:submit.prevent></form>
    
    <!-- 添加事件监听器时使用事件捕获模式 -->
    <!-- 即元素自身触发的事件先在此处处理,然后才交由内部元素进行处理 -->
    <div v-on:click.capture="doThis">...</div>
    
    <!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
    <!-- 即事件不是从内部元素触发的 -->
    <div v-on:click.self="doThat">...</div>
    
    • 示例,如下图所示,这样写的话点击了 li 内部的元素的话不会影响 li 的 click 的点击事件
    image.png

    7. vue 使用 clipboard 实现复制功能

    原文地址

    • 安装依赖 clipboard.js
    npm install clipboard --save
    
    • 在需要使用的地方 require 引用
    var clipboard = require('clipboard');
    
    • 在页面加载后调用该方法即可
    image.png

    8. 解决 vue-resource 的跨越问题

    我这里是 vue-cli 基于 webpack 的项目(注意:在修改了 proxyTable 之后需要在命令行中 npm run dev 重新运行下项目,否则是不会有效果的呀~)

    • 错误信息

    Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.

    • 解决方法:

    先找到对应的配置 js 文件中的 proxyTable


    image.png

    修改相应的配置


    image.png
    再在 main.js 中配置 vue-resource 的格式,不配置的话是无法向后台传递参数的
    image.png

    在 vue 文件中的使用
    data 中绑定相应的静态配置


    image.png
    methods 增加相应的方法
    image.png
    mouted 在 data 数据挂载到实例对象的时候 ,请求页面数据,实现页面的正常显示
    image.png

    9. vue-router 单页之间如何在 js 中跳转

    原文地址

    • 三种写法
    // 字符串
    this.$router.push('/home/first')
    
    // 对象
    this.$router.push({ path: '/home/first' })
    
    // 命名的路由
    this.$router.push({ name: 'home', params: { userId: wise }})
    
    image.png

    10. vuex 实现组件之间数据的传递

    根据 state 可以实时的获取到数据
    原文地址

    • 安装
    npm install vuex --save
    
    • 在 src 文件夹中新建一个 stroe 文件夹,并在目录下新建一个 index.js 文件(已有的话请忽略),index.js 文件编辑如下
    import Vue from 'vue';
    import Vuex from 'vuex';
    
    Vue.use(Vuex);
    
    let store = new Vuex.Store({
        state: {
            formData: {} // 企业提交数据表单对象
        }
    });
    
    export default store;
    
    
    • 在 src 目录下的 main.js 文件中引入 vuex 文件,并在实例化时添加配置
    import Vue from 'vue';
    import App from './App';
    import router from './router';
    import store from './store'; // 引入 vuex
    
    Vue.config.productionTip = false;
    Vue.http.options.emulateJSON = true;
    
    /* eslint-disable no-new */
    new Vue({
      el: '#app',
      router,
      store, // 需要在添加
      components: { App },
      template: '<App/>'
    });
    
    
    • 之后就可以直接在需要的组件中直接引用,引用具体示例如下
    image.png
    image.png

    控制台成功输出


    image.png

    11. .eslintrc.js 文件 rules 增加设置

    我的笔记

    12. vue 表单操作

    我的笔记

    13. 解决使用 vux 组件库时 与 rem 设置冲突带来的问题

    • 思路

    将之前 rem 计算的数值 html font-size: "100px",改到 12px,之后连锁的将 less 中计算和引用的的值也改下,之后就可以了,尽量做到少量的修改即可

    • 将之前的 js 计算 rem 数值脚本修改相应的数值
    image.png

    改过之后的


    image.png
    • 修改 less
    image.png

    改过之后的


    image.png
    • 之后就可以是 rem 和 vux 基本正常了

    14. 通过 watch 动态的监测路由跳转(跳转时)和 APP.vue 中设置 created 方法实时监测 path (刷新时),来实现 header 文字的改变

    • header.vue
    watch: {
        '$route' (to, from) {
            // 检测路由改变 header 内容
            if (to.name === 'Index') {
                this.$store.state.PageTitle = '预约领号';
                this.$store.state.isShowBack = false;
            } else if (to.name === 'PreferentialDescription') {
                this.$store.state.PageTitle = '优惠说明';
                this.$store.state.isShowBack = true;
            } else if (to.name === 'RuleIntroduction') {
                this.$store.state.PageTitle = '规则简介';
                this.$store.state.isShowBack = true;
            } else if (to.name === 'ReservationSuccess') {
                this.$store.state.PageTitle = '预约排号';
                this.$store.state.isShowBack = true;
            }
        }
      }
    

    15. vue-router spa (单页)需要的 nginx 配置,防止出现 404 的情况

    官方文档

    image.png
    照着上方的图将代码复制至服务器的 nginx.config 配置文件即可
    1. ssh 远程登录服务器
    ssh username@ipaddress
    enter your password
    
    1. 查找服务器中的 nginx 相关目录,我这边是 nginx 服务器
    whereis nginx
    
    image.png
    • /etc/nginx 这个是 nginx 相关配置的目录
    • /usr/share/nginx 是静态文件的目录
    • 进入 html 目录,这个就是默认的存放项目文件的目录
    image.png
    • 修改 nginx 默认的配置文件
    # 首先进入配置文件目录
    cd /etc/nginx
    ls
    # 查看配置文件
    cat nginx.config
    # 复制一份原始的配置文件
    cp nginx.config nginx.config.back
    # 按照上面 vue-router 的需求修改配置文件
    vi nginx.config
    # 进入编辑状态
    I
    # 修改文件
    location / {
      try_files $uri $uri/ /index.html;
    }
    # 之后保存并退出
    esc
    :  
    wq
    # 再次查看是否已修改成功
    cat nginx.config
    # 重载 nginx 配置文件(必须重载,不然修改的是不会生效的!)
    nginx -s reload
    
    image.png
    • 上面的步骤操作完成之后便解决了 vue-router spa 带来的刷新页面 404 的问题了,哦耶~

    16. 与后台 API 进行通信时,Content-Type 请求文本格式为统一带来的问题

    • 问题截图
    image.png
    后台返回 415 Unsupported Media Type
    对于当前请求的方法和所请求的资源,请求中提交的实体并不是服务器中所支持的格式,因此请求被拒绝。
    • 产生错误的原因:

    这里使用的是 post 请求,后台的请求文本格式为 Content-Type:application/json;charset=UTF-8
    但是这里使用的是默认的 Content-Type:application/x-www-form-urlencoded 所以造成的此次错误

    • 解决方法

    在提交数据之前使用 JSONstringify方法将数据转换为 json 格式的文本即可,如下图所示

    image.png
    JSON.stringiy()
    JSON.stringify() 方法是将一个JavaScript值(对象或者数组)转换为一个 JSON字符串,如果指定了replacer是一个函数,则可以替换值,或者如果指定了replacer是一个数组,可选的仅包括指定的属性。

    17. 清除 .vue 文件在 vscode 编辑器中格式化时默认添加的分号和双引号的规则

    参考地址

    image.png
    • 问题

    因为 vue-cli 项目创建后会默认的增加 .eslintrc.js eslint 规则文件来帮助我们更好的统一代码的规范性,但是现在的趋势是省略 javascript 代码书写时在末尾添加的分号,但是 vscode 编辑器因为装了 vetur这个插件,所以还是会像之前的那样默认追加,使得项目报 eslint 语法的错误,单双引号也是相同的问题

    • 解决方法

    先安装扩展插件 Prettier - Code formatter

    image.png

    之后在顶部菜单栏依次操作:【文件】->【首选项】->【设置】->【用户设置】
    最后增加下面的规则代码片段

    "prettier.singleQuote": true,
    "prettier.semi": false
    

    18. 之前的删掉了,等待更新中......

    19. 给 vue 挂载全局方法

    • 找到 main.js 文件进行编辑,这里以 axios 为例演示
    import Vue  from 'vue'
    import  axios from 'axios'
    
    Vue.prototype.axios = axios
    
    • 使用方法 某个 .vue 文件的 sccript 中如下编辑
    Vue.axios.post('url', { name: '' })
    .then(response => { 
      console.log(response)
    })
    .catch(response => {
      console.log(response)
    })
    

    20. axios 不兼容 ie 的问题解决

    • 问题描述
    image.png

    在 IE 浏览器下会报 “Promise”未定义" 的错误

    • 资料

    axios npmjs 地址

    image.png
    问题解决参考地址
    • 解决方法

    使用 babel-polyfill 这个包

    • 装包
    yarn add babel-polyfill --dev
    
    • 之后在 main.js 文件中引入包即可
    import 'babel-polyfill'
    
    image.png
    • 测试可兼容至 IE8+
    image.png
    • 更新 优化进阶 已经过测试

    参考文章里面有详细的解释:babel-polyfill使用与性能优化
    目的是为了打包出更小的体积,下图是使用新方法打包出的体积,用上面的方法打包出来是 2.64MB

    image.png
    • 解决方法 将之前引入的 babel-polyfill 换成 core-js/es6/promise 这个是 vue-cli 脚手架就有的包无需再装了
    import 'core-js/es6/promise' // 解决 axios 兼容 IE 问题
    
    image.png

    21. 组件封装,这里以 bootstrap 的 modal 模块为例

    参考官方文档 -- 组件基础
    参考官方文档 -- 组件注册
    参考官方文档 -- props

    • 先写组件,在 src -> components 目录下新建一个文件夹 msgmodal -> index.vue,编辑如下
    <template>
    <!-- 弹窗 -->
        <div class="modal fade" tabindex="-1" role="dialog" id="myModal">
          <div class="modal-dialog" role="document">
            <div class="modal-content">
              <div class="modal-header">
                <!-- <h5 class="modal-title"></h5> -->
                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                  <span aria-hidden="true">&times;</span>
                </button>
              </div>
              <div class="modal-body">
                <p>{{ modalMsg }}</p>
              </div>
              <div class="modal-footer">
                <button type="button" class="btn btn-primary" data-dismiss="modal">确定</button>
                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
              </div>
            </div>
          </div>
        </div>
    </template>
    
    <script>
    export default {
      name: 'MsgModal', // 定义的组件名称 使用时写法:msg-modal
      props: ['modalMsg'] // 定义的与父级通信的属性值 使用时写法:modal-msg
    }
    </script>
    
    <style scoped>
    </style>
    
    
    • 在具体的 .vue 文件使用组件,方法如下,这里是用的动态绑定的方法传递属性的值
    <!-- template -->
    <!-- 弹窗 -->
        <msg-modal :modal-msg="modalMsg"></msg-modal>
    
    
    // script
    import MsgModal from '@/components/msgmodal'
    
    export default{
      name:'App',
      components: { MsgModal },
      data () {
        return {
          // 弹窗信息 在执行操作时使用
          modalMsg: ''
        }
      }
    }
    
    • 测试,已实现可以实时更新内容了
    image.png

    22. 在 router -> index.js 按需引入模块,优化 SPA 页面的性能

    参考地址

    • 源码
    import Vue from 'vue'
    import Router from 'vue-router'
    import VueResource from 'vue-resource'
    
    // import index from '@/index'
    // import companyapply from '@/companyapply'
    // import choosenumber from '@/choosenumber'
    // import statelist from '@/statelist'
    
    Vue.use(Router)
    Vue.use(VueResource)
    
    export default new Router({
      // 去掉路由中自带的 #/ 这种东西
      mode: 'history',
      routes: [
        {
          path: '/',
          name: 'index',
          component: () => import('@/index')
        },
        {
          path: '/companyapply',
          name: 'companyapply',
          component: () => import('@/companyapply')
        },
        {
          path: '/choosenumber',
          name: 'choosenumber',
          component: () => import('@/choosenumber')
        },
        {
          path: '/statelist',
          name: 'statelist',
          component: () => import('@/statelist')
        }
      ]
    })
    
    

    23. 在 Vue 上挂载 vux 库中的 LoadingPlugin 组件

    官方文档地址 - 该组件支持以plugin形式调用

    • main.js
    // The Vue build version to load with the `import` command
    // (runtime-only or standalone) has been set in webpack.base.conf with an alias.
    import Vue from 'vue'
    import { LoadingPlugin } from 'vux' // 引入 looding 组件
    import App from './App'
    import store from './store' // 引入 vuex
    import router from './router'
    
    Vue.config.productionTip = false
    Vue.http.options.emulateJSON = true
    
    Vue.use(LoadingPlugin) // 挂载 loading 组件
    
    /* eslint-disable no-new */
    new Vue({
      el: '#app',
      router,
      store, // 需要在添加
      components: { App },
      template: '<App/>'
    })
    
    
    • .vue 文件中具体的使用示例:
    // loading
    this.$vux.loading.show({
      text: '数据提交中
    })      
    
    // 隐藏 loading
    this.$vux.loading.hide()
    

    24. 解决:使用 axios 默认发送的是 application/json;charset=UTF-8 这种格式的数据后台无法读取的问题

    后台需要的是 application/x-www-form-urlencoded 这样的数据格式
    参考地址

    • 问题截图
    image.png
    • 需要的格式截图
    image.png
    • 解决方法

      • 使用 qs 模块,转换数据格式
      image.png
      • 源码
      import qs from 'qs' // 解决 axios 数据提交格式与后台不一致的问题  -> name=hehe&age=10
      
      
      axios.post(postAPI,qs.stringify(postData))
      .then(request => {
        console.log(request)
      })
      .catch(error => {
        console.log(error)
      })
      

    25. 化繁为简的Watchers

    原文地址

    • 场景还原:
    created(){
        this.fetchPostList()
    },
    watch: {
        searchInputValue(){
            this.fetchPostList()
        }
    }
    

    组件创建的时候我们获取一次列表,同时监听input框,每当发生变化的时候重新获取一次筛选后的列表这个场景很常见,有没有办法优化一下呢?

    • 招式解析:

    首先,在watchers中,可以直接使用函数的字面量名称;其次,声明immediate:true表示创建组件时立马执行一次。

    watch: {
        searchInputValue:{
            handler: 'fetchPostList',
            immediate: true
        }
    }
    

    26. 父子组件通信 -- 子组件可以调用父组件的方法

    • 实现思路

    使用 this.$emit()

    以下示例为分页组件,下面只是将主要的部分代码贴出

    • 父组件
    <template>
      <!-- 分页 -->
          <pagination @updatePageData="loadPageData"></pagination>
    </template>
    
    <script>
      export default{
        methods:{
          loadPageData:function(){
            //  do something
          }
        }
      }
    <script>
    
    • 上面代码的说明

    @updatePageData="loadPageData" :传递方法时前面使用 @updatePageData 是给子组件使用的 父组件 loadPageData 方法的别名

    • 子组件
    export default{
      methods:{
        pageGo:function(){
          const me = this
          // 调用父组件方法
          me.$emit('updatePageData')
        }
      }
    }
    

    27. 父子组件通信 -- 子组件可动态获取父组件的数据

    • 问题描述

    由于父组件的数据是动态获取的,而子组件初始化时如果获取不到数据就 Game Over

    • 实现思路

    使用 props 传数据 ; watch 监听数据

    以下示例为分页组件,下面只是将主要的部分代码贴出

    • 父组件
    <template>
      <!-- 分页 -->
          <pagination :parentPageData="pageGetData"></pagination>
    </template>
    
    <script>
      export default{
        data(){
          return{
            pageGetData:[]
          }
        },
        methods:{
          getData:function(){
            //  ajax 请求之后改变 pageGetData 的数据
          }
        }
      }
    <script>
    
    • 上面代码的说明

    :parentPageData="pageGetData" 传递方法前面使用 :parentPageData 是给子组件使用的 父组件 pageGetData 数据的别名

    • 子组件
    export default{
      props:['parentPageData'], // 父组件数据 别名
      watch:{
        // 监听父组件数据变化实时更新数据
        parentPageData:{
          handler: 'loadPageList',
          immediate: true
        }
      },
      methods:{
        // 加载页面数据
        loadPageList:function(){
          // do something
        }
      }
    }
    

    28. vue 多页面开发分页组件 有搜索功能

    文章笔记

    29. Vue.vue 文件的样式 style 标签中使用 background:url() 引入图片

    参考资料 vue 背景图引入

    • 示例代码片段
    <style scoped>
    .loading {
      position: fixed;
      left: 0;
      top: 0;
      background: url('~@/assets/img/loading-ball.svg') center center no-repeat #fff;
      width: 100vw;
      height: 100vh;
      z-index: 1000;
    }
    </style>
    

    30. 页面加载数据之前增加 loading 动画

    文章笔记

    31. 封装一个 axios 的通用方法

    • 思路

    自定义一个函数,将其挂载到 Vue 对象的 prototype 上面,方便在页面使用,因为 axios 一般得和 qs 模块配合使用
    qs 使用参考地址

    image.png
    • main.js 文件中挂载自定义方法
    import Vue from 'vue'
    import 'babel-polyfill' // 解决 axios 兼容 IE 问题
    import qs from 'qs' // 解决 axios 数据提交格式与后台不一致的问题  -> name=hehe&age=10
    import axios from 'axios'
    // import router from './router'
    import '@/assets/css/common.css'
    import App from './index.vue'
    
    Vue.config.productionTip = false
    
    /**
     * 自定义一个方法封装 axios 请求,并将其挂载至 Vue 原型链
     * @param {string} url axios 请求的地址
     * @param {string} dataJson axios 向请求地址发送的 json 数据
     * @param {function} sucessFn axios 成功回调函数
     * @param {function} errorFn axios 失败回调函数
     */
    Vue.prototype.axiosFn = function(url, dataJson, sucessFn, errorFn) {
      axios
        .post(url, qs.stringify(dataJson))
        .then(response => {
          console.log(response)
          sucessFn()
        })
        .catch(error => {
          console.log(error)
          errorFn()
        })
    }
    
    /* eslint-disable no-new */
    new Vue({
      el: '#app',
      // router,
      components: { App },
      template: '<App/>'
    })
    
    
    • 具体的使用就不写了,只需要在调用方法 axiosFn 时给其传相应的参数即可

    相关文章

      网友评论

      本文标题:vue 实战各种小技巧(长期更新)

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