• vue小细节


    1. 组件缓存 keep-aive  属性  exclude  

    include - 字符串或正则表达式。只有名称匹配的组件会被缓存

    exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存。

    max - 数字。最多可以缓存多少组件实例。

    <keep-alive exclude="Detail"> 
          <router-view />
     </keep-alive>

    2. es6加载路由组件

    const Detail = () => import('../views/detail/Detail.vue');

    3.避免路由跳转报错

    //replace  避免报错
    const VueRouterReplace = VueRouter.prototype.replace
    VueRouter.prototype.replace = function replace(to) {
      return VueRouterReplace.call(this, to).catch(err => err)
    }
    
    //push 避免报错
    const VueRouterPush = VueRouter.prototype.push
    VueRouter.prototype.push = function push(to) {
      return VueRouterPush.call(this, to).catch(err => err)
    }

    4.声明组件名 , 避免通俗语义化 例如 Footer ,需改为FooterView

    5.组件点击   @click.native

    <back-top @click.native="backClick" v-show="isBackShow"></back-top>

    6.this.$refs获取子组件相关 , 改变子组件数据

    <tab-control
          :titles="[{ title: '流行' }, { title: '精选' }, { title: '新款' }]"
          @itemClick="tabClick"
          ref="tabControl1"
          v-show="isFixed"
        ></tab-control>  //子组件
    this.$refs.tabControl1.courrentIndex = index;  //改变子组件数据
    this.$refs.tabControl1.$el.getBoundingClientRect()
            .top //获取子组件距离顶部高度

    7.具名插槽 , 类名不要用 中划线  来间隔

     8.Vuex,每次调用mutation之后向localstorage存值,防止刷新丢失

    9.vue.config.js  每次更改完之后需要重新启动项目

    10.  用样式穿透来解决ui框架后引入导致样式覆盖问题  .home  >>> .children

     11.vue使用this.$refs.xx在mounted中获取DOM元素为undefined 

    12.使用 @hook 即可监听组件生命周期,组件内无需做任何改变

    <template>
        <List @hook:mounted="listenMounted" />
    </template>

    13.手动挂载组件

    import vue from 'vue'
    import Message from './Message.vue'
    
    // 构造子类
    let Messageconstructor = vue.extend(Message)
    // 实例化组件
    let messageInstance = new Messageconstructor()
    // $mount可以传入选择器字符串,表示挂载到该选择器
    // 如果不传入选择器,将渲染为文档之外的的元素,你可以想象成 document.createElement()在内存中生成dom
    messageInstance.$mount()
    // messageInstance.$el获取的是dom元素
    document.body.appendChild(messageInstance.$el)

    14.wacth高阶使用

      14-1.在组件创建后 watch    属性immediate设置为true  能够立即执行  

    export default {
        data() {
            return {
                name: 'Joe'
            }
        },
        watch: {
            name: {
                handler: 'sayName',
                immediate: true
            }
        },
        methods: {
            sayName() {
                console.log(this.name)
            }
        }
    }

        14-2.在监听对象时,对象内部的属性被改变时无法触发 watch  , 设置属性deep为true , 为其设置深度监听

    export default {
        data: {
            studen: {
                name: 'Joe',
                skill: {
                    run: {
                        speed: 'fast'
                    }
                }
            }
        },
        watch: {
            studen: {
                handler: 'sayName',
                deep: true
            }
        },
        methods: {
            sayName() {
                console.log(this.studen)
            }
        }
    }

     14-3  触发监听执行多个方法

    export default {
        data: {
            name: 'Joe'
        },
        watch: {
            name: [
                'sayName1', //字符串形式
                function(newVal, oldVal) {  //函数形式  
                    this.sayName2()
                },
                {           //对象形式
                    handler: 'sayName3',
                    immaediate: true
                }
            ]
        },
        methods: {
            sayName1() {
                console.log('sayName1==>', this.name)
            },
            sayName2() {
                console.log('sayName2==>', this.name)
            },
            sayName3() {
                console.log('sayName3==>', this.name)
            }
        }
    }

      14-4  wacth监听多个变量

    watch本身无法监听多个变量。但我们可以将需要监听的多个变量通过计算属性返回对象,再监听这个对象来实现“监听多个变量”

    export default {
        data() {
            return {
                msg1: 'apple',
                msg2: 'banana'
            }
        },
        compouted: {
            msgObj() {
                const { msg1, msg2 } = this
                return {
                    msg1,
                    msg2
                }
            }
        },
        watch: {
            msgObj: {
                handler(newVal, oldVal) {
                    if (newVal.msg1 != oldVal.msg1) {
                        console.log('msg1 is change')
                    }
                    if (newVal.msg2 != oldVal.msg2) {
                        console.log('msg2 is change')
                    }
                },
                deep: true
            }
        }
    }

        14-4  注销 watch

            1.为什么要注销 ?
    因为我们的组件是经常要被销毁的,比如我们跳一个路由,从一个页面跳到另外一个页面,那么原来的页面的 watch 其实就没用了,
    这时候我们应该注销掉原来页面的 watch 的,不然的话可能会导致内置溢出。好在我们平时 watch 都是写在组件的选项中的,他会随着组件的销毁而销毁。
            2.什么情况下需要注销?
      如果我们使用下面这样的方式写 watch,那么就要手动注销了,这种注销其实也很简单
    const unWatch = app.$watch('text', (newVal, oldVal) => {
      console.log(`${newVal} : ${oldVal}`);
    })

            3.如何注销?

    const unWatch = app.$watch('text', (newVal, oldVal) => {
      console.log(`${newVal} : ${oldVal}`);
    })
    unWatch(); // 手动注销watch

      app.$watch调用后会返回一个值,就是unWatch方法,你要注销 watch 只要调用unWatch方法就可以了。

     

    15.函数式组件: 

    一般适合只依赖于外部数据的变化而变化的组件,因其轻量,渲染性能也会有所提高。

    创建函数式组件也很简单,只需要在模板添加 functional 声明即可

    子组件

    <template functional>
        <div class="list">
            <div class="item" v-for="item in props.list" :key="item.id" @click="props.itemClick(item)">
                <p>{{item.title}}</p>
                <p>{{item.content}}</p>
            </div>
        </div>
    </template>

    父组件

    <template>
        <div>
            <List :list="list" :itemClick="item => (currentItem = item)" />
        </div>
    </template>
    import List from '@/components/List.vue' export default { components: { List }, data() { return { list: [{ title: 'title', content: 'content' }], currentItem: '' } } }

    16.路由参数解耦

    将路由的 props 属性设置为 true 后,组件内可通过 props 接收到 params 参数

    const router = new vueRouter({
        routes: [{
            path: '/user/:id',
            component: User,
            props: true
        }]
    })

    另外还可以通过函数模式来返回 props

    const router = new vueRouter({
        routes: [{
            path: '/user/:id',
            component: User,
            props: (route) => ({
                id: route.query.id
            })
        }]
    })

    可通过 props 接收参数

    export default {
        props: ['id'],
        methods: {
            getParamsId() {
                return this.id
            }
        }
    }

    16.params传参问题   

    params传参时,如果没有在路由中定义参数,也是可以传过去的,同时也能接收到,但是一旦刷新页面,这个参数就不存在了。

    这对于需要依赖参数进行某些操作的行为是行不通的.

    // 定义的路由中,只定义一个id参数
    {
        path: 'detail/:id',
        name: 'Detail',
        components: Detail
    }
    
    // template中的路由传参,
    // 传了一个id参数和一个token参数
    // id是在路由中已经定义的参数,而token没有定义
    <router-link :to="{name: 'Detail', params: { id: 1, token: '123456' }}">前往Detail页面</router-link>
    
    // 在详情页接收
    created () {
        // 以下都可以正常获取到
        // 但是页面刷新后,id依然可以获取,而token此时就不存在了
        const id = this.$route.params.id;
        const token = this.$route.params.token;
    }

    17.定时器问题

    通过$once这个事件侦听器器在定义完定时器之后的位置来清除定时器

    const timer = setInterval(() =>{
        // 某些定时器操作
    }, 500);
    // 通过$once来监听定时器,在beforeDestroy钩子可以被清除。
    this.$once('hook:beforeDestroy', () => {
        clearInterval(timer);
    })

     18.props验证

    props: {
      status: {
        type: String, //数据类型
        required: true, //是否验证
        validator: function (value) { //验证函数
          return [   //验证结果
            'success',
            'error',
          ].indexOf(value) !== -1
        }
      }
    }

     19.路由组件复用

    在开发当中,有时候我们不同的路由复用同一个组件,默认情况下,我们切换组件,Vue出于性能考虑可能不会重复渲染。

    但是我们可以通过给router-view绑定一个key属性来进行切换的时候路由重复渲染。

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

    20批量属性继承

    使用$props将父组件的所有的props传递到子组件

    场景 :    从父组件接收传递下来的数据使用props接收,再将这些props数据传递到子组件

    <template>
        <!-- 将从父组件接收到的props数据传递到子组件
            使用v-bind="$props" 批量传递
        -->
        <childComponent
            v-bind="$props"
        />
    </template>
    <script>
    export default {
        // 从父组件接收到的props数据
        props: ['value1','value2','value3','value4','value5'],
        data() {
            return {....}
        .....
        }
    }
    
    // childComponent.vue
    <script>
    export default {
        props: ['value1','value2','value3','value4','value5'],
        data() {
            return {....}
        .....
        },
        mounted() {
            // 子组件可以接收到数据
            console.log(this.value1)
            console.log(this.value2)
            console.log(this.value3)
            console.log(this.value4)
            console.log(this.value5)
        }
    }
    </scrript>

    属性继承在开发表单组件时,使用$props就可以很好的解决批量属性传递问题。

    21.组件懒加载(异步加载组件)

    1.为什么要用

      所有的组件代码都会在首次渲染是下载 , 体验不佳

    2.什么场景用

    比如后台管理页面,在多个tab之间切换的时候,其余tab里面的组件就可以在需要的时候再异步加载~

    有多个子路由的页面必用

    3.如何用?

    components: { test: () => import("./Test.vue") },

    给加载js命名
     components: {
        test: () => import(/* webpackChunkName:'test' */ "./Test.vue"),  //给加载js命名
      },

    处理加载状态的写法  

    异步组件工程函数
    const AsyncTest = () => ({ component: import(/* webpackChunkName:'test' */ "./Test.vue"), loading: LoadingComponent, //加载时显示的组件 error: ErrorComponent, //超时或错误时显示的组件 delay: 200, //延迟 timeout: 3000, //超时 });

    22.解决async/await异步问题

     使用  await 1; 解决异步

    例子:
    async created(){
                    try {  //捕获await错误信息 
                       this.couponArr = await this.getData({form_id:11,pageSize:9}).then(res=>{
                        if(res.length>8){
                            res.pop();
                            this.couponBtn=true;
                            return res;
                        }
                        return res;
                        });
                        this.storeArr1[this.currentIndex]= await this.getData({form_id:8,position_ename:'nav1-1',pageSize:4});
                        this.currentArr =  this.storeArr1[this.currentIndex];
                        this.storeArr2 = await this.getData({form_id:18,pageSize:5}).then(res=>{
                            if(res.length>4){
                                res.pop();
                                this.bandanBtn=true;
                                return res;
                            }
                            return res;
                        });
                        this.storeArr3 = await this.getData({form_id:8,position_ename:'nav3'});
                    } catch (e) {
                        console.log(e)
                    }
                    
                    await 1; //解决异步
                    this.gundong()
                    this.navFixed({
                        navParent: '.nav_box',
                        nav: '.nav',
                        navItem: '.nav li',
                        itemParent: '.tit',
                        active: 'active',
                        fixedTop: '0',
                        deviation: parseFloat($('.nav').height()),
                        animateTime: 500,
                        flag: 0
                    })
                    this.tab()
                    this.xuanran();
                    this.videoHandle();
                    this.gtOrltVisible()
                    this.swiperHandle()
                    this.staticImg()
                },

    23.滚动节流

     passive: 是告诉浏览器,监听器不会调用e.preventDefault()函数,不用来检查,可以提前生成手势,从而提高流畅性,通常用在move事件中

    例子: 

    <template>
      <div class="scroll">
        <div class="containers" @scroll.passive="scrollHandle">
          <div class="content">
            <ul>
              <li v-for="item in 100">{{ item }}</li>
            </ul>
          </div>
        </div>
      </div>
    </template>
    
    <script>
    export default {
      name: "Scroll",
      components: {},
      data() {
        return {
          scrollHandle: () => {},
        };
      },
      created() {
        this.scrollHandle = this.throttle(this.scrollHandle2, 200);
      },
      methods: {
        scrollHandle2(e) {
          console.log(456);
        },
        throttle(func, delay = 800) {
          let lock = false;
          return (...args) => {
            if (lock) {
              return;
            }
            func(...args);
            lock = true;
            setTimeout(() => {
              lock = false;
            }, delay);
          };
        },
      },
    };
    </script>
    
    <style scoped >
    .containers {
      height: 500px;
      border: 1px solid #000;
      overflow: scroll;
    }
    </style>

     24.$destroy()方法问题

    某种业务场景下,我们期望缓存的页面可以被销毁,就会调用$destroy方法,这回导致被销毁的页面,虽然会触发activated钩子函数,但是页面实际上没有被缓存,重新进入是初始dom结构的状态。

     24.数据更新,update()/beforeUpdate()未触发问题

    页面使用到的数据改变时才会更新 updated 和 beforedate钩子函数

    ...

  • 相关阅读:
    前端程序员的进阶
    字符集的知识
    通晓多种编程语言的程序员,真香?
    理解 Docker
    免费开源软件的潜在安全风险
    技术编程人员成长的 9 个段位
    如何更好的设计 RESTful API
    selenium环境搭建:
    自动化测试有哪些?
    删除书籍:
  • 原文地址:https://www.cnblogs.com/wxyblog/p/14573897.html
Copyright © 2020-2023  润新知