zoukankan      html  css  js  c++  java
  • Vue2.x 项目踩坑笔记

    设置路径别名、全局引入scss文件

    给文件设置路径别名,方便在组件内引入文件,不必写太长的路径名称。
    全局引入scss文件,不必在单个组件内再次引入,可以直接使用。例如:全局变量、px2rem函数等文件

    const path = require('path');
    
    function resolve(dir) {
      return path.join(__dirname, dir)
    }
    
    module.exports = {
      css: {
        loaderOptions: {
          // 给 sass-loader 传递选项
          // 默认情况下 `sass` 选项会同时对 `sass` 和 `scss` 语法同时生效
          // 因为 `scss` 语法在内部也是由 sass-loader 处理的
          // 但是在配置 `data` 选项的时候
          // `scss` 语法会要求语句结尾必须有分号,`sass` 则要求必须没有分号
          // 在这种情况下,我们可以使用 `scss` 选项,对 `scss` 语法进行单独配置
          scss: {
            additionalData: `
            @import "assets/styles/common/variables.scss";
            @import "assets/styles/common/px2rem.scss";
            @import "assets/styles/iconfont/iconfont.scss";
                            `
          },
        }
      },
      chainWebpack: config => {
        config
          .resolve.alias
          .set('@', resolve('src'))    //配置src目录别名
          .set('assets', resolve('src/assets'))    //配置src/assets目录别名
          .set('components', resolve('src/components'));    //配置src/components目录别名
      }
    }
    

    动态路由加载

    为了解决项目进入时候白屏bug

    const router = new VueRouter({
      routes: [
        { 
          path: '/',
          name: 'index',
          component: () => import("@/views/Index.vue")
        }
      ]
    });
    

    prop 命名方案(驼峰式和串联式)

    HTML 属性名称对大小写不敏感,因此浏览器会将所有大写字符解释为小写字符。也就是说。当你在你 DOM 模板中书写 prop 时,你应当将驼峰式(camelCase)转写为等价的(连字符分割的)串联式(kebab-case):

    Vue.component('blog-post', {
      // 在 JavaScript 中使用驼峰式(camelCase)
      props: ['postTitle'],
      template: '<h3>{{ postTitle }}</h3>'
    })
    
    <!-- 在 HTML 中使用串联式(kebab-case) -->
    <!-- 向 props传递一个静态值 -->
    <blog-post post-title="hello!"></blog-post>
    

    还可以通过 v-bind 给 props 分配动态值,就像这样:

    <!-- 动态分配一个变量对应的值 -->
    <blog-post v-bind:title="post.title"></blog-post>
    
    <!-- 动态分配一个复合表达式对应的值 -->
    <blog-post v-bind:title="post.title + ' by ' + post.author.name"></blog-post>
    

    再次申明,如果是在使用字符串模板的场景,则没有这些限制。

    路由跳转拼接参数

    <router-link :to="`/topic/${item.id}`" :title="item.id">
    </router-link>
    

    beforeRouteEnter不能通过this访问组件实例,但是可以通过 vm 访问组件实例

      // 进入路由
      beforeRouteEnter(to, from, next) {
        // beforeRouteEnter不能通过this访问组件实例,但是可以通过 vm 访问组件实例
        next((vm) => {
          console.log('beforeRouteEnter',this);
          // 先解绑,防止多次执行
          vm.eventBus.$off('aaa');
        });
      },
    

    滚动到页面底部加载数据

    在生命周期mounted中进行监听滚动:

    mounted () {
      window.addEventListener('scroll', this.scrollToTop)
    },
    

    在方法中定义监听滚动执行的方法:

    scrollToTop() { 
      var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
      console.log(scrollTop)
    },
    

    记得在离开当前路由解绑scroll事件

    beforeRouteLeave(to, form, next){
      window.removeEventListener('scroll',this.scrollToTop);
      next();
    }
    

    渲染异步数据,浏览器报错

    <img class="avatar" v-if="item.author" :src="item.author.avatar_url" />
    

    如果异步请求的数据出现报错,可以通过v-if判断一下,注意不能使用v-show,v-show的机制是加载后,根据条件判断是否显示,当然渲染组件的时候也可以这样做

    菜单切换获取对应参数并触发请求数据

    参数或查询的改变并不会触发进入/离开的导航守卫,但是可以通过观察 $route 对象来应对这些变化,或使用 beforeRouteUpdate 的组件内守卫。

    父组件修改子组件变量

    有时候父组件触发的实际需要修改子组件内的data数据,这时候请给子组件绑定ref属性,在父组件触发时间内修改子组件的变量

    <template>
      <div class="page">
        <Header 
          :page-type="getType(searchKey.tab)"
          ref="head"
          :fix-head="true"
          :need-add="true"/>
    
        <PostList
          :items="postList"
          ref="postlist"
          v-if="postList.length>0" />
    
        <GoToTop
          ref="gototop"
          :flag="flag"/>
      </div>
    </template>
    
      <!-- 在方法中调用this.$refs即可获取到ref绑定的组件或者DOM -->
      // 收起菜单
      this.$refs.head.show = false;
    

    子组件内调用父组件的方法

    日常开发者经常会遇到多层级嵌套组件,并且需要在最里面的子组件触发最外面的父组件事件,这种情况下当然最好的做法其实还是使用Vuex进行管理,如果你的项目使用Vuex进行管理了,后面就没必要看了。Vuex的相关内容请自行百度查阅。

    第一种:直接在子组件中通过this.$parent.event来调用父组件的方法
    这种方式可以无限级别的向上找父级,例如:this.$parent.$parent.$parent.$parent.event,子组件也不需要props属性接收父组件的方法,但是多层级的时候容易搞乱层级,.$parent太多了

    父组件

    <template>
      <div>
        <child></child>
      </div>
    </template>
    <script>
      import child from '@/components/child';
      export default {
        components: {
          child
        },
        methods: {
          fatherMethod() {
            console.log('fatherMethod');
          }
        }
      };
    </script>
    

    子组件

    <template>
      <div>
        <button @click="childMethod">点击</button>
      </div>
    </template>
    <script>
      export default {
        methods: {
          childMethod() {
            this.$parent.fatherMethod();
          }
        }
      };
    </script>
    

    第二种:父组件把方法传入子组件中,在子组件里直接调用这个方法
    父组件内调用子组件的时候需要显示的传入方法(注意:这里是用的:传入方法),子组件还需要通过props接收父组件传来的方法,否则也不可以调用,另外就是多层级的时候需要一层一层的往下传,这时候就比较繁琐

    父组件

    <template>
      <div>
        <child :fatherMethod="fatherMethod"></child>
      </div>
    </template>
    <script>
      import child from '@/components/child';
      export default {
        components: {
          child
        },
        methods: {
          fatherMethod() {
            console.log('fatherMethod');
          }
        }
      };
    </script>
    

    子组件

    <template>
      <div>
        <button @click="childMethod">点击</button>
      </div>
    </template>
    <script>
      export default {
        props: {
          fatherMethod: {
            type: Function,
            default: null
          }
        },
        methods: {
          childMethod() {
            if (this.fatherMethod) {
              this.fatherMethod();
            }
          }
        }
      };
    </script>
    

    第三种:子组件里用$emit向父组件触发一个事件名(注意:这里是用的@传入方法),父组件监听这个事件名就行了,子组件不需要通过props接收父组件传来的方法,否则也不可以调用,这种最好向上传递一层父级,否则也需要层层传递

    父组件

    <template>
      <div>
        <child @fatherMethod="fatherMethod"></child>
      </div>
    </template>
    <script>
      import child from '@/components/child';
      export default {
        components: {
          child
        },
        methods: {
          fatherMethod() {
            console.log('fatherMethod');
          }
        }
      };
    </script>
    

    子组件

    <template>
      <div>
        <button @click="childMethod">点击</button>
      </div>
    </template>
    <script>
      export default {
        methods: {
          childMethod() {
            this.$emit('fatherMethod');
          }
        }
      };
    </script>
    

    第四种:使用$emit$on 配合传递事件
    如果仅仅是父子一层,传递事件就使用第三种就可以了,如果多层传递或者是兄弟组件,还可以使用$emit$on 配合,其原理就是new 一个vue实例,然后在父子组件引入这个实例,这样在子组件触发的事件就会在父组件监听到了,这就是网上说的eventBus。

    新建一个bus.js

    import Vue from 'vue';
    export default new Vue();
    

    在父子组件分别引入这个bus.js

    import eventBus from 'bus';
    
    

    在子组件触发事件

      export default {
        methods: {
          childMethod() {
            eventBus.$emit('fatherMethod');
          }
        }
      };
    

    在父组件监听事件

      export default {
        mounted() {
          //如果出现多次监听,肯定是没有解绑,可以在监听之前解绑,也可以在进入到这个路由或者渲染组件时候解绑一下就好了
          eventBus.$off('fatherMethod');
          eventBus.$on('fatherMethod');
        }
      };
    

    当然如果你觉得建一个bus.js文件多余的话,可以在main.js里把bus加到原型上

    //vue原型链挂载总线
    Vue.prototype.eventBus = new Vue();
    

    加到原型上的好处就是全局都可以使用了

    this.eventBus.$emit('fatherMethod');
    this.eventBus.$on('fatherMethod');
    

    引入vant

    全局引入组件

    import Vue from 'vue';
    import { Toast } from 'vant';
    
    Vue.use(Toast);
    

    引入 Toast 组件后,会自动在 Vue 的 prototype 上挂载 $toast 方法,便于在组件内调用。

    export default {
      mounted() {
        this.$toast('提示文案');
      },
    };
    
    

    当然也可以在组件内引入

    import { Toast } from 'vant';
    

    组件内使用

    export default {
      mounted() {
        Toast('第一个 Toast');
      },
    };
    

    绑定、解绑节流函数

    只要紧记绑定和解绑的事件是同一个就行了,如果不是一个,就单写成一个函数

    export default {
      mounted() {
        //执行绑定函数事件
        this.addScrollData();
      },
      methods: {
        // 滚动加载数据
        getScrollData: utils.throttle(function() {
          // 节流getScrollTop
            this.getScrollTop();
        },300),
        // 绑定滚动加载数据事件
        addScrollData(){
          //当然你也可以把上面的这个getScrollData写在这个函数里
          this.getScrollData = utils.throttle(function() {
            // 节流getScrollTop
              this.getScrollTop();
          },300);
    
          // 绑定滚动加载数据事件
          window.addEventListener('scroll', this.getScrollData);
        }
      },
      //离开路由和组件销毁选择适合项目写一种解绑即可
      // 离开路由之前
      beforeRouteLeave(to, from, next){
        // 解绑scroll事件
        window.removeEventListener('scroll', this.getScrollData);
        next();
      },
      //组件销毁之前
      beforeDestroy () {
        // 解绑scroll事件
        window.removeEventListener('scroll', this.getScrollData);
      },
    };
    

    vuex使用

    http.js使用store

    
    import Store from '@/store';
    import { SHOW_LOADING, HIDE_LOADING } from "@/store/mutationTypes.js";
    
    ...
    ...
    ...
    
    Store.commit(SHOW_LOADING);
    
    

    在组件内使用

    this.$store.commit(SHOW_LOADING);
    
  • 相关阅读:
    接口:
    抽象类:
    构造方法与重载
    get方法和set方法
    类的成员变量与方法、构造方法
    构造方法
    Java面向对象学习-----类的成员变量2
    Java面向对象学习-----类的成员变量
    java字符串分割
    android 使用讯飞人脸识别api报错:java.lang.UnsatisfiedLinkError
  • 原文地址:https://www.cnblogs.com/jiaoshou/p/13841723.html
Copyright © 2011-2022 走看看