• vue常见开发问题整理


    1.(webpack)vue-cli构建的项目如何设置每个页面的title

    在路由里每个都添加一个meta

    [{
        path:'/login',
        meta: {
          title: '登录页面'
        },
        component:'login'
    }]

    钩子函数:

    在main.js中添加如下代码

    router.beforeEach((to, from, next) => {
      window.document.title = to.meta.title;
      next()
    })

    2.vue项目中使用axios上传图片等文件

    首先安装axios:
    1.利用npm安装npm install axios –save
    2.利用bower安装bower install axios –save
    3.直接利用cdn引入

    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>

    一般情况上传照片有两种方式:

    • 1.本地图片转换成base64,然后通过普通的post请求发送到服务端。

      操作简单,适合小图,以及如果想兼容低版本的ie没办法用此方法

    • 2.通过form表单提交。

      form表单提交图片会刷新页面,也可以时form绑定到一个隐藏的iframe上,可以实现无刷新提交数据。

    这里只讲解一下第二种方式:
    html代码:

    <input name="file" type="file" accept="image/png,image/gif,image/jpeg" @change="update"/>

    js代码:

    import axios from 'axios'
    // 添加请求头
    update (e) {   // 上传照片
          var self = this
          let file = e.target.files[0]
          /* eslint-disable no-undef */
          let param = new FormData()  // 创建form对象
          param.append('file', file)  // 通过append向form对象添加数据
          param.append('chunk', '0') // 添加form表单中其他数据
          console.log(param.get('file')) // FormData私有类对象,访问不到,可以通过get判断值是否传进去
          let config = {
            headers: {'Content-Type': 'multipart/form-data'}
          }
         // 添加请求头
        axios.post('http://172.19.26.60:8081/rest/user/headurl', param, config)
            .then(response => {
              if (response.data.code === 0) {
                self.ImgUrl = response.data.data
              }
              console.log(response.data)
            })
        }

    3.qs.stringify() 和JSON.stringify()的区别以及在vux中使用post提交表单数据需要qs库序列化

    qs库的npm地址:https://www.npmjs.com/package/qs

    功能虽然都是序列化。假设我要提交的数据如下

    var a = {name:'hehe',age:10};

    qs.stringify序列化结果如下
    name=hehe&age=10

    而JSON.stringify序列化结果如下:
    "{"a":"hehe","age":10}"

    vux中使用post提交表单数据:

    this.$http.post(this.$sign.config.url.loginUrl,this.$qs.stringify({
        "phone":this.phoneNumber,
        "vCode":this.loginCode,
        "smsCode":this.phoneCode    
        })
    )
    .then(response=>{
        console.log(response.data);
        if(response.data.httpCode == 200){
            
        }else{
            
        }
    }) 

    在firebug中可以看到传递的参数:
    phone=15210275239&vCode=8vsd&smsCode=1534

    在vue中使用axios:

    this.$axios.post(loginUrl, {
        "email": this.email,
        "password": this.password
    }, {
        transformRequest: (data) => {
            return this.$qs.stringify(data)
        },
    }).then(res => {
        if(res.data.resultCode == RESULT_CODE_SUCCESS){
            console.log('登录成功');
            this.$router.push({name:"home"})
        }else{
            console.log('登录失败');
        }
    }).catch(err => {
        console.log('登登录出现错误');
    })

    4.vue中实现全局的setCookie,getCookie以及delCookie方法笔记

    import Vue from 'vue'
    import Vuex from 'vuex'
    import VueRouter from 'vue-router'
    import App from '../component/App.vue'
    import Login from '../component/Login.vue'
    import UserInfo from '../component/UserInfo.vue'
    //状态管理
    Vue.use(Vuex)
      //路由
    Vue.use(VueRouter)
    
    //路由配置
    //如果需要加菜单,就在这里添加路由,并在UserMenu.vue添加入口router-link
    const router = new VueRouter({
      routes: [{
        path: '/login',
        component: Login
      }, {
        path: '/user_info',
        component: UserInfo
      }]
    })
    
    //Vuex配置
    const store = new Vuex.Store({
      state: {
        domain:'http://test.example.com', //保存后台请求的地址,修改时方便(比方说从测试服改成正式服域名)
        userInfo: { //保存用户信息
          nick: null,
          ulevel: null,
          uid: null,
          portrait: null
        }
      },
      mutations: {
        //更新用户信息
        updateUserInfo(state, newUserInfo) {
          state.userInfo = newUserInfo;
        }
      }
    })
    
    //设置cookie,增加到vue实例方便全局调用
    Vue.prototype.setCookie = (c_name, value, expiredays) => {
      var exdate = new Date();    
      exdate.setDate(exdate.getDate() + expiredays);    
      document.cookie = c_name + "=" + escape(value) + ((expiredays == null) ? "" : ";expires=" + exdate.toGMTString());
    }
    
    //获取cookie
    Vue.prototype.getCookie = (name) => {
        var arr, reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)");
        if (arr = document.cookie.match(reg))
            return (arr[2]);
        else
            return null;
    }
    
    //删除cookie
    Vue.prototype.delCookie =(name) => {
        var exp = new Date();
        exp.setTime(exp.getTime() - 1);
        var cval = this.getCookie(name);
        if (cval != null)
          document.cookie = name + "=" + cval + ";expires=" + exp.toGMTString();
      }
    
    //vue实例
    var app = new Vue({
      data: {},
      el: '#app',
      render: h => h(App),
      router,
      store,
      watch:{
        "$route" : 'checkLogin'
      },
      created() {
        this.checkLogin();
      },
      methods:{
        checkLogin(){
    
          //检查是否存在session
          if(!this.getCookie('session')){
            this.$router.push('/login');
          }else{
            this.$router.push('/user_info');
          }
        }
      }
    })

    5.webpack中alias配置中的“@”是什么意思?

    如题所示,build文件夹下的webpack.base.conf.js

    resolve: {
        extensions: ['.js', '.vue', '.json'],
        alias: {
          'vue$': 'vue/dist/vue.esm.js',
          '@': resolve('src')
        }
      }

    其中的@的意思是:
    只是一个别名而已。这里设置别名是为了让后续引用的地方减少路径的复杂度。

    //例如
    src
    - components
      - a.vue
    - router
      - home
        - index.vue
    
    
    index.vue 里,正常引用 A 组件:
    
    import A from '../../components/a.vue'
    
    如果设置了 alias 后。
    alias: {
     'vue$': 'vue/dist/vue.esm.js',
     '@': resolve('src')
    }
    
    引用的地方路径就可以这样了
    
    import A from '@/components/a.vue'
    
    这里的 @ 就起到了【resolve('src')】路径的作用。

    6.webpack proxyTable 代理跨域

    webpack 开发环境可以使用proxyTable 来代理跨域,生产环境的话可以根据各自的服务器进行配置代理跨域就行了。在我们的项目config/index.js 文件下可以看到有一个proxyTable的属性,我们对其简单的改写

    proxyTable: {
          '/api': {
            target: 'http://api.douban.com/v2',
            changeOrigin: true,
            pathRewrite: {
              '^/api': ''
            }
          }
        }

    这样当我们访问localhost:8080/api/movie的时候 其实我们访问的是http://api.douban.com/v2/movi...

    当然我们也可以根据具体的接口的后缀来匹配代理,如后缀为.shtml,代码如下:

    proxyTable: {
        '**/*.shtml': {
            target: 'http://192.168.198.111:8080/abc',
            changeOrigin: true
        }
    }

    可参考地址:
    webpack 前后端分离开发接口调试解决方案,proxyTable解决方案
    http-proxy-middleware

    7.如何在 vue 项目里正确地引用 jquery 和 jquery-ui的插件

    使用vue-cli构建的vue项目,webpack的配置文件是分散在很多地方的,而我们需要修改的是build/webpack.base.conf.js,修改两处的代码

    // 在开头引入webpack,后面的plugins那里需要
    var webpack = require('webpack')
    // resolve
    
    module.exports = {
       // 其他代码...
       resolve: {
          extensions: ['', '.js', '.vue'],
          fallback: [path.join(__dirname, '../node_modules')],
          alias: {
              'src': path.resolve(__dirname, '../src'),
              'assets': path.resolve(__dirname, '../src/assets'),
              'components': path.resolve(__dirname, '../src/components'),
    
              // webpack 使用 jQuery,如果是自行下载的
              // 'jquery': path.resolve(__dirname, '../src/assets/libs/jquery/jquery.min'),
              // 如果使用NPM安装的jQuery
              'jquery': 'jquery' 
          }
       },
    
       // 增加一个plugins
       plugins: [
          new webpack.ProvidePlugin({
              $: "jquery",
              jQuery: "jquery"
          })
       ],
    
       // 其他代码...
    }

    这样就可以正确的使用jQuery了,比如我要引入Bootstrap,我们在vue的入口js文件src/main.js开头加入

    // 使用Bootstrap
    import './assets/libs/bootstrap/css/bootstrap.min.css'
    import './assets/libs/bootstrap/js/bootstrap.min'

    这样Bootstrap就正确的被引用并构建。
    在比如使用toastr组件,只需要在需要的地方import进来,或者全局引入css在需要的地方引用js,然后直接使用

    // 使用toastr
    import 'assets/libs/toastr/toastr.min.css'
    import toastr from 'assets/libs/toastr/toastr.min'
    
    toastr.success('Hello')

    参考:Managing Jquery plugin dependency in webpack

    vue-cli webpack全局引入jquery

    1.首先在package.json里加入,

    dependencies:{
     "jquery" : "^2.2.3"
    }

    然后 npm install

    2.在webpack.base.conf.js里加入

    var webpack = require("webpack")

    3.在module.exports的最后加入

    plugins: [
     new webpack.optimize.CommonsChunkPlugin('common.js'),
     new webpack.ProvidePlugin({
         jQuery: "jquery",
         $: "jquery"
     })
    ]

    4.然后一定要重新 run dev

    5.在main.js 引入就ok了

    import $ from 'jquery'

    参考: vue-cli怎么引入jquery

    在.vue文件中引入第三方非NPM模块

    var Showbo = require("exports?Showbo!./path/to/showbo.js");

    参考: exports-loader

    vue-cli引入外部文件

    在 webpack.base.conf.js 中添加externals
    图片描述

    externals 中 swiper 是键,对应的值一定的是插件 swiper.js 所定义的变量 Swiper :
    图片描述

    图片描述

    之后再在根目录下的index.html文件里引入文件:<script src="static/lib/swiper.js"></script>
    这样子就可以在需要用到swiper.js的文件里加入这行代码:import Swiper from 'swiper',这样就能正常使用了。
    参考: https://segmentfault.com/q/1010000005169531?_ea=806312

    8.vue和mintui-Loadmore结合实现下拉刷新,上拉加载 (待优化)

    mintui是饿了么团队针对vue开发的移动端组件库,方便实现移动端的一些功能,这里只用了Loadmore功能实现移动端的上拉分页刷新,下拉加载数据.
    mintui官网:http://mint-ui.github.io/#!/zh-cn

    <template>  
      <div class="main-body" :style="{'-webkit-overflow-scrolling': scrollMode}">  
        <v-loadmore :top-method="loadTop" :bottom-method="loadBottom" :bottom-all-loaded="allLoaded" :auto-fill="false" ref="loadmore">  
          <ul class="list" v-for="(val, key) in pageList">  
            <li>  
              <div>我是小11</div>  
              <div>我是小11</div>  
            </li>  
          </ul>  
        </v-loadmore>  
      </div>  
    </template>  
    <script>  
      import {Loadmore} from 'mint-ui';  
      export default {  
        data:function() {  
          return {  
            searchCondition:{  //分页属性  
              pageNo:"1",  
              pageSize:"10"  
            },  
            pageList:[],  
            allLoaded: false, //是否可以上拉属性,false可以上拉,true为禁止上拉,就是不让往上划加载数据了  
            scrollMode:"auto" //移动端弹性滚动效果,touch为弹性滚动,auto是非弹性滚动  
          }  
        },  
        components: {  
          'v-loadmore':Loadmore  // 为组件起别名,vue转换template标签时不会区分大小写,例如:loadMore这种标签转换完就会变成loadmore,容易出现一些匹配问题  
                                  // 推荐应用组件时用a-b形式起名  
        },  
        mounted(){  
          this.loadPageList();  //初次访问查询列表  
        },  
        methods: {  
          loadTop:function() { //组件提供的下拉触发方法  
            //下拉加载  
            this.loadPageList();  
            this.$refs.loadmore.onTopLoaded();// 固定方法,查询完要调用一次,用于重新定位  
          },  
          loadBottom:function() {  
            // 上拉加载  
            this.more();// 上拉触发的分页查询  
            this.$refs.loadmore.onBottomLoaded();// 固定方法,查询完要调用一次,用于重新定位  
          },  
          loadPageList:function (){  
              // 查询数据  
            this.api.PageList(this.searchCondition).then(data =>{  
              // 是否还有下一页,加个方法判断,没有下一页要禁止上拉  
              this.isHaveMore(data.result.haveMore);  
              this.pageList = data.result.pageList;  
              this.$nextTick(function () {  
                // 原意是DOM更新循环结束时调用延迟回调函数,大意就是DOM元素在因为某些原因要进行修改就在这里写,要在修改某些数据后才能写,  
                // 这里之所以加是因为有个坑,iphone在使用-webkit-overflow-scrolling属性,就是移动端弹性滚动效果时会屏蔽loadmore的上拉加载效果,  
                // 花了好久才解决这个问题,就是用这个函数,意思就是先设置属性为auto,正常滑动,加载完数据后改成弹性滑动,安卓没有这个问题,移动端弹性滑动体验会更好  
                this.scrollMode = "touch";  
              });  
            });  
          },  
          more:function (){  
              // 分页查询  
            this.searchCondition.pageNo = parseInt(this.searchCondition.pageNo) + 1;  
            this.api.loadPageList(this.searchCondition).then(data=>{  
              this.pageList = this.pageList.concat(data.result.pageList);  
              this.isHaveMore(data.result.haveMore);  
            });  
          },  
          isHaveMore:function(isHaveMore){  
            // 是否还有下一页,如果没有就禁止上拉刷新  
            this.allLoaded = true; //true是禁止上拉加载  
            if(isHaveMore){  
              this.allLoaded = false;  
            }  
          }  
        }  
      }  
    </script>  

    PS:有个坑一定要注意就是注释里说的iPhone里loadmore和-webkit-overflow-scrolling属性冲突无法上拉问题

    可参考另外一个插件,没有使用过,《简单灵活且强大的Vue下拉刷新组件:vue-pull-to》

    9.在vue+webpack实际开发中出现两个或多个菜单公用一个组件的解决方案

    在vue的实际开发中往往会遇到公用一个组件的问题,比如有一个菜单中的两个按钮,点击每个按钮调用的是同一个组件,其内容是根据路由的参数的不同来请求不同的内容。

    第一步,首先新建一个vue+webpack+vuecli的demo,如下操作:
    全局安装vue-clivue-cil是vue的脚手架工具,安装命令:

    npm install -g vue-cli

    第二步,进入到工程目录中,创建一个vuedemo的文件夹工程,如下两步操作:

    cd vue_test_project //进入vue_test_project目录下
    vue init webpack vuedemo //在vue_test_project目录下创建一个vuedemo工程

    输入这个命令之后,会出现一些提示,是什么不用管,一直按回车即可。

    第三步,如下操作:

    cd vuedemo
    npm install

    执行npm install需要一点时间,因为会从服务器上下载代码啦之类的。并且在执行过程中会有一些警告信息。不用管,等着就是了。如果长时间没有响应,就ctrl+c停止掉,然后再执行一次即可。

    最后一步,操作如下:

    npm run dev

    在运行了npm run dev之后,会自动打开一个浏览器窗口,就可以看到实际的效果了。这个demo就创建好了。现在就在这个demo中添加一些内容,修改成如下:
    图片描述

    修改HelloWorld.vue的内容为如下:

    <template>
      <div class="hello">
        <h1>{{ msg }}</h1>
        <h2>Essential Links</h2>
        <div class="btn">
             <router-link :to="{name:'content',params:{differId:'con1'}}">内容按钮1</router-link>
             <router-link :to="{name:'content',params:{differId:'con2'}}">内容按钮2</router-link>
        </div>
        <router-view></router-view>
      </div>
    </template>
    
    <script>
    export default {
      name: 'HelloWorld',
      data () {
        return {
          msg: 'Welcome to Your Vue.js App'
        }
      }
    }
    </script>
    <style scoped>
    h1, h2 {
      font-weight: normal;
    }
    ul {
      list-style-type: none;
      padding: 0;
    }
    li {
      display: inline-block;
      margin: 0 10px;
    }
    a {
      color: #42b983;
    }
    </style>
    路由router下的index.html的修改为如下:
    
    import Vue from 'vue'
    import Router from 'vue-router'
    import HelloWorld from '@/components/HelloWorld'
    import content from '@/components/conDetail'
    Vue.use(Router)
    
    export default new Router({
      routes: [
        {
          path: '/',
          name: 'HelloWorld',
          component: HelloWorld,
          children:[
              {name:'content',path:'content/:differId',component:content}
          ]
        }
      ]
    })

    现在创建一个conDetail.vue了,如下:

    <template>
        <div class="same">
            这个是相同的内容
            <div class="conlist">
                <template v-for="item in items">
                    <p>{{item.con}}</p>
                </template>
            </div>
        </div>
    </template>
    
    <script>
    export default {
      name: 'conDetail',
      data () {
        return {
          msg: '',
          differIdType:'',
          conlist:[
              {'con':'这是第一个内容按钮的内容1'},
              {'con':'这是第一个内容按钮的内容2'}
          ],
          items:[], 
          
        }
      },
      mounted(){
              this.differIdType = this.$route.params.differId == 'con1' ? '0' : '1';
              if(this.differIdType == 0){
                  this.items = this.conlist;
              }else{
                  this.items = [];
              }
      },
      watch:{
          $route:function(to,from){
              this.differIdType = to.params.differId == 'con1' ? '0' : '1'; 
              if(this.differIdType == 0){
                  this.items = this.conlist;
              }else{
                  this.items = [];
              }    
          }
      }
      
    }
    </script>
    
    <style>
    </style>

    结果就是,当点击内容按钮1,出现了对象的内容,点击内容按钮2,出现相应的内容。当然我这儿写的是点击按钮2的时候,其items的内容为空数组。这儿也使用了$route的监听。

    复用组件时,想对路由参数的变化作出响应的话,你可以简单地 watch(监测变化) $route 对象:

    const User = {
      template: '...',
      watch: {
        '$route' (to, from) {
          // 对路由变化作出响应...
        }
      }
    }

    或者使用 2.2 中引入的 beforeRouteUpdate 守卫:

    const User = {
      template: '...',
      beforeRouteUpdate (to, from, next) {
        // react to route changes...
        // don't forget to call next()
      }
    }

    详细了解路由相关的内容,查看官网:https://router.vuejs.org/zh-cn/

    10.vue2.x父子组件以及非父子组件之间的通信

    1.父组件传递数据给子组件

    父组件数据如何传递给子组件呢?可以通过props属性来实现

    父组件:

    <parent>
        <child :child-msg="msg"></child>//这里必须要用 - 代替驼峰
    </parent>
    
    data(){
        return {
            msg: [1,2,3]
        };
    }

    子组件通过props来接收数据:

    方式1:

    props: ['childMsg']

    方式2 :

    props: {
        childMsg: Array //这样可以指定传入的类型,如果类型不对,会警告
    }

    方式3:

    props: {
        childMsg: {
            type: Array,
            default: [0,0,0] //这样可以指定默认的值
        }
    }

    这样呢,就实现了父组件向子组件传递数据.

    2.子组件与父组件通信

    子组件:

    <template>
        <div @click="up"></div>
    </template>
    
    methods: {
        up() {
            this.$emit('fun','这是一段内容'); //主动触发fun方法,'这是一段内容'为向父组件传递的数据
        }
    }

    父组件:

    <div>
        <child @fun="change" :msg="msg"></child> //监听子组件触发的fun事件,然后调用change方法
    </div>
    methods: {
        change(msg) {
            this.msg = msg; 
        }
    }

    3.非父子组件通信

    如果2个组件不是父子组件那么如何通信呢?这时可以通过eventHub来实现通信.
    所谓eventHub就是创建一个事件中心,相当于中转站,可以用它来传递事件和接收事件.

    let Hub = new Vue(); //创建事件中心

    组件1触发:

    <div @click="eve"></div>
    methods: {
        eve() {
            Hub.$emit('change','hehe'); //Hub触发事件
        }
    }

    组件2接收:

    <div></div>
    created() {
        Hub.$on('change', () => { //Hub接收事件
            this.msg = 'hehe';
        });
    }

    可参考:vue非父子组件怎么进行通信

    11.vue项目中在使用vue-router切换页面的时候滚动条怎样自动滚动到顶部?

    有时候我们需要页面滚动条滚动到某一固定的位置,一般使用Window scrollTo() 方法。

    语法就是:scrollTo(xpos,ypos)

    xpos:必需。要在窗口文档显示区左上角显示的文档的 x 坐标。

    ypos:必需。要在窗口文档显示区左上角显示的文档的 y 坐标。

    例如滚动内容的坐标位置100,500:

    window.scrollTo(100,500);

    好了,这个scrollTop这儿只是简单介绍一下,下面我们介绍下veu-router中的滚动行为。

    使用前端路由,当切换到新路由时,想要页面滚到顶部,或者是保持原先的滚动位置,就像重新加载页面那样。 vue-router能做到,而且更好,它让你可以自定义路由切换时页面如何滚动。

    注意: 这个功能只在 HTML5 history 模式下可用。

    当创建一个 Router 实例,你可以提供一个 scrollBehavior 方法:

    const router = new VueRouter({
      routes: [...],
      scrollBehavior (to, from, savedPosition) {
        // return 期望滚动到哪个的位置
      }
    })

    scrollBehavior 方法接收 to 和 from 路由对象。第三个参数 savedPosition 当且仅当 popstate 导航 (通过浏览器的 前进/后退 按钮触发) 时才可用。

    这个方法返回滚动位置的对象信息,长这样:

    • { x: number, y: number }
    • { selector: string, offset? : { x: number, y: number }} (offset 只在 2.6.0+ 支持)

    如果返回一个 falsy (译者注:falsy 不是 false参考这里)的值,或者是一个空对象,那么不会发生滚动。

    举例:

    scrollBehavior (to, from, savedPosition) {
      return { x: 0, y: 0 }
    }

    对于所有路由导航,简单地让页面滚动到顶部。

    返回 savedPosition,在按下 后退/前进 按钮时,就会像浏览器的原生表现那样:

    scrollBehavior (to, from, savedPosition) {
      if (savedPosition) {
        return savedPosition
      } else {
        return { x: 0, y: 0 }
      }
    }

    如果你要模拟『滚动到锚点』的行为:

    scrollBehavior (to, from, savedPosition) {
      if (to.hash) {
        return {
          selector: to.hash
        }
      }
    }

    我们还可以利用路由元信息更细颗粒度地控制滚动。

     routes: [
        { path: '/', component: Home, meta: { scrollToTop: true }},
        { path: '/foo', component: Foo },
        { path: '/bar', component: Bar, meta: { scrollToTop: true }}
      ]

    完整的例子:

    import Vue from 'vue'
    import VueRouter from 'vue-router'
    
    Vue.use(VueRouter)
    
    const Home = { template: '<div>home</div>' }
    const Foo = { template: '<div>foo</div>' }
    const Bar = {
      template: `
        <div>
          bar
          <div style="height:500px"></div>
          <p id="anchor">Anchor</p>
        </div>
      `
    }
    
    // scrollBehavior:
    // - only available in html5 history mode
    // - defaults to no scroll behavior
    // - return false to prevent scroll
    const scrollBehavior = (to, from, savedPosition) => {
      if (savedPosition) {
        // savedPosition is only available for popstate navigations.
        return savedPosition
      } else {
        const position = {}
        // new navigation.
        // scroll to anchor by returning the selector
        if (to.hash) {
          position.selector = to.hash
        }
        // check if any matched route config has meta that requires scrolling to top
        if (to.matched.some(m => m.meta.scrollToTop)) {
          // cords will be used if no selector is provided,
          // or if the selector didn't match any element.
          position.x = 0
          position.y = 0
        }
        // if the returned position is falsy or an empty object,
        // will retain current scroll position.
        return position
      }
    }
    
    const router = new VueRouter({
      mode: 'history',
      base: __dirname,
      scrollBehavior,
      routes: [
        { path: '/', component: Home, meta: { scrollToTop: true }},
        { path: '/foo', component: Foo },
        { path: '/bar', component: Bar, meta: { scrollToTop: true }}
      ]
    })
    
    new Vue({
      router,
      template: `
        <div id="app">
          <h1>Scroll Behavior</h1>
          <ul>
            <li><router-link to="/">/</router-link></li>
            <li><router-link to="/foo">/foo</router-link></li>
            <li><router-link to="/bar">/bar</router-link></li>
            <li><router-link to="/bar#anchor">/bar#anchor</router-link></li>
          </ul>
          <router-view class="view"></router-view>
        </div>
      `
    }).$mount('#app')

    在网上查了一下,网友说还可以试试在main.js入口文件配合vue-router写这个

    router.afterEach((to,from,next) => {
        window.scrollTo(0,0);
    });

    12.vue自定义全局组件并通过全局方法 Vue.use() 使用该组件

    简介

    Vue.use( plugin ):安装 Vue.js 插件。如果插件是一个对象,必须提供 install 方法。如果插件是一个函数,它会被作为 install 方法。install 方法将被作为 Vue 的参数调用。

    当 install 方法被同一个插件多次调用,插件将只会被安装一次。

    Vue.js 的插件应当有一个公开方法 install 。这个方法的第一个参数是 Vue 构造器,第二个参数是一个可选的选项对象:

    MyPlugin.install = function (Vue, options) {
      // 1. 添加全局方法或属性
      Vue.myGlobalMethod = function () {
        // 逻辑...
      }
      // 2. 添加全局资源
      Vue.directive('my-directive', {
        bind (el, binding, vnode, oldVnode) {
          // 逻辑...
        }
        ...
      })
      // 3. 注入组件
      Vue.mixin({
        created: function () {
          // 逻辑...
        }
        ...
      })
      // 4. 添加实例方法
      Vue.prototype.$myMethod = function (methodOptions) {
        // 逻辑...
      }
    }

    通过全局方法 Vue.use() 使用插件:

    // 调用 `MyPlugin.install(Vue)`
    Vue.use(MyPlugin)

    也可以传入一个选项对象:

    Vue.use(MyPlugin, { someOption: true })

    Vue.use 会自动阻止多次注册相同插件,届时只会注册一次该插件。

    Vue.js 官方提供的一些插件 (例如 vue-router) 在检测到 Vue 是可访问的全局变量时会自动调用 Vue.use()。然而在例如 CommonJS 的模块环境中,你应该始终显式地调用 Vue.use()

    // 用 Browserify 或 webpack 提供的 CommonJS 模块环境时
    var Vue = require('vue')
    var VueRouter = require('vue-router')
    // 不要忘了调用此方法
    Vue.use(VueRouter)

    实例:实现一个children组件

    main.js中使用该组件的方法:

    import  childModule from './components/children'
    Vue.use(childModule)

    组件文件夹的目录结构如下:

        |-components
          |-children
            |-index.js 导出组件,并且install
            |-children.vue (定义自己的组件模板)
    children.vue代码如下:
    
    import childrencomponent from './children.vue'
    const childrenMo = {
        install:function(Vue){
            Vue.component('childModule',childrencomponent)
        }
    }
    export default childrenMo

    这样就实现了一个通过vue.use调用一个全局组件。

    13.IE9报vuex requires a Promise polyfill in this browser问题解决

    因为使用了 ES6 中用来传递异步消息的的Promise,而IE低版本的浏览器不支持。

    如图所示:
    图片描述

    解决方法
    第一步: 安装 babel-polyfill 。 babel-polyfill可以模拟ES6使用的环境,可以使用ES6的所有新方法

    npm install --save babel-polyfill

    第二步: 在 Webpack/Browserify/Node中使用

    在webpack.config.js文件中

    module.exports = {
        entry: {
            app: './src/main.js'
        }
    }

    替换为:

    module.exports = {
        entry: {
            app: ["babel-polyfill", "./src/main.js"]
        }
    };

    14.通过webpack+vue+vueRouter+vuecli的配置文件package.json创建一个新的项目

    如果是简单通过package.json来创建一个项目,只需要执行npm install

    首先,我们自己得手动创建一个webpack+vue+vueRouter+vuecli工程,执行下面:
    如:
    新建一个vue项目,创建一个基于"webpack"的项目,项目名为vuedemo:

    $ vue init webpack vuedemo

    安装完成后进入工程名称再根据原来项目的配置文件初始化

    $ cd vuedemo
    $ npm install

    但是由于在新建的时候对eslint的选择中选择了Yes,所以后面根据配置package.json的时候,发现没有eslint-friendly-formatter 模块,由于原来的工程应该没有配置这个,所以这儿需要安装下,如下代码:

    npm i -D eslint eslint-friendly-formatter

    模块地址:https://www.npmjs.com/package/eslint-friendly-formatter

    安装后执行:npm run dev 发现运行起来的页面没有启动起来,原因是还是这个eslint引起的。

    出错信息为:

    These relative modules were not found:
    */build/dev-client in multi ./build/dev-client ./src/main.js,
    *./src/main.js in multi ./build/dev-client ./src/main.js

    原因如下:
    webpack.base.conf.js里面,脚手架本来就有 js的编译模块,

     {
            test: /.js$/,
            loader: 'babel-loader',
            include: [resolve('src'), resolve('test')]
          }

    我们需要注释掉这段代码:

    //    {
    //      test: /.(js|vue)$/,
    //      loader: 'eslint-loader',
    //      enforce: 'pre',
    //      include: [resolve('src'), resolve('test')],
    //      options: {
    //        formatter: require('eslint-friendly-formatter')
    //      }
    //    },

    原因就是导致重复编译,所以应该就有两个main.js文件。所以不要重复出现匹配规则就可以。
    然后运行npm run dev可以了。
    相似问题:vue-cli安装完成之后,命令行npm run dev没有问题,但webstorm报错

    15.VUE利用webpack 给生产环境和发布环境配置不同的接口地址

    第一步,分别设置不同的接口地址

    首先,我们分别找到下面的文件:

    /config/dev.env.js
    /config/prod.env.js

    其实,这两个文件就是针对生产环境和发布环境设置不同参数的文件。我们打开dev.en.js文件。代码如下:

    var merge = require('webpack-merge')
    var prodEnv = require('./prod.env')
    
    module.exports = merge(prodEnv, {
      NODE_ENV: '"development"'
    })

    我们在NODE_ENV下面增加一项,代码如下:

    var merge = require('webpack-merge')
    var prodEnv = require('./prod.env')
    
    module.exports = merge(prodEnv, {
      NODE_ENV: '"development"',
      API_ROOT: '"//192.168.1.8/api"'
    })

    prod.env.js文件修改为:

    module.exports = {
      NODE_ENV: '"production"',
      API_ROOT: '"//www.baidu.com/api"'
    }

    第二步,在代码中调用设置好的参数

    以我们之前的演示代码为例。你自己的项目请根据你自己的情况调整。以下文件和代码仅供参考。
    我们打开src/config/api.js文件,将原来开头的代码

    // 配置API接口地址
    var root = 'https://cnodejs.org/api/v1'

    修改为:

    // 配置API接口地址
    var root = process.env.API_ROOT

    然后就完成了我们的配置工作。最后,重启项目,就能使新配置的接口地址生效了。

    npm run dev
    npm run build

    在main.js区分生产与开发环境

    process.env.NODE_ENV == 'production';  //生产环境
    process.env.NODE_ENV == 'development'; //开发环境

    参考地址:http://blog.csdn.net/fungleo/article/details/54574049

    16.vue单页应用添加百度统计

    前言

    申请百度统计后,会得到一段JS代码,需要插入到每个网页中去,在Vue.js项目首先想到的可能就是,把统计代码插入到index.html入口文件中,这样就全局插入,每个页面就都有了;这样做就涉及到一个问题,Vue.js项目是单页应用,每次用户浏览网站时,访问内页时页面是不会刷新的,也就意味着不会触发百度统计代码;所以最终在百度统计后台看到的效果就是只统计到了网页入口的流量,却无法统计到内页的访问流量。

    解决方法

    main.js文件中调用vue-routerafterEach方法,将统计代码加入到这个方法里面,这样每次router发生改变的时候都会执行一下统计代码,这样就达到了目的,代码如下:

    router.afterEach( ( to, from, next ) => {
            setTimeout(()=>{
                    var _hmt = _hmt || [];
                    (function() {
                        //每次执行前,先移除上次插入的代码
                        document.getElementById('baidu_tj') && document.getElementById('baidu_tj').remove();
                        var hm = document.createElement("script");
                        hm.src = "https://hm.baidu.com/hm.js?xxxx";
                        hm.id = "baidu_tj"
                        var s = document.getElementsByTagName("script")[0];
                        s.parentNode.insertBefore(hm, s);
                    })();
            },0);
        } );
  • 相关阅读:
    没有技术驱动型公司 | 每个人都得加班 | 关注软技能
    各种15min(启动、横盘、破位)样例
    最新win10教育版激活密匙 win10各版本永久激活序列号
    大数定律具体是个什么概念?
    统计与概率——马同学高等数学
    三星MagicInfo Express软件制作介绍
    !!网上找的【英语单词词根记忆顺口溜】
    一个故事轻松记忆常见252个英语字根
    分享一个开源的音频分析软件
    C#连接XAMPP中的mysql 数据库(windows)
  • 原文地址:https://www.cnblogs.com/ygunoil/p/9242167.html
Copyright © 2020-2023  润新知