vue查缺补漏

2019-11-19  本文已影响0人  饥人谷_米弥轮
  1. Object.defineProperty有缺陷,就是无法监控到对象属性临时添加的属性,必须使用VUE.set($set)属性去添加,这个方法原理就是重新设定一个Object.defineProperty监听新属性,所以VUE3.0改为使用proxy去监听,没有这种缺陷

  2. 数组在添加过程中也是会无法监听的,所以在VUE中写了push,pop,shift ...这类直接修改数组方法(因为不修改原数组的方法是会返回新数组的,可以通过监听新数组去触发)的变异方法,通过改写这类方法进行数组值的监听,例:

let push = Array.prototype.push
Array.prototype.push = function(...args) {
    // 中间做些类似中间件的代码,获取新增的数据,进行监听
    ....
    push.call(this, ...args)
}

3.v-once只渲染一次
4.v-pre忽略这个元素和它子元素内容的编译
5.v-model修饰符

v-model.lazy,取代change方法,等输入完之后再进行输出
v-model.number,只能输入数字
v-model.trim,收尾空格去除

6.鼠标修饰符

.stop,阻止冒泡
.self,点击事件绑定元素与当前元素一致时才会触发
    //stop和self分别什么情况下使用,当子元素不想产生冒泡触发父级事件时使用stop,
    //而self则时在很多嵌套元素情况下,只想触发当前元素的时候使用
.prevent,阻止默认事件
.once,事件只绑定一次
.passive,告诉浏览器没有阻止默认事件
    //每次触发事件,浏览器都要等线程执行到事件监听器对应的代码时,才能查询代码是否有阻止默认事件这个行为,而这个查询过程会导致在使用scroll,手势,移动等事件出现卡顿,
    //添加上这个修饰符后就是直接告诉浏览器没有做这个行为,就不用去查询了
    //原生写法:el.addEventer('click', function() {}, {once:true,passive:true})

7.键盘修饰符

.exact,精确键盘事件
   //@keyDown.ctrl.exact="fn" 表示只能在单独按ctrl键的时候才能触发

8.watch

new Vue({
  el: '#app',
  data: {
    a: {
      b: {
        c: 1
      }
    }
  },
  watch: {
    'a.b.c': {
      handler: function(new, old) { console.log() },   //对于多层数据的监听,可以使用字符串+点语法
      immediate: true, //当第一次绑定值时就直接监听
      deep: true //深层监听,最多监听5层
    }
    
  }
  //
})

9.v-model在除input元素外的使用

<div id="app">
  <child v-model="val"></child>  
</div>
const child= {
    model: {
            // 指定v-model绑定的prop属性,需要和下方props的属性名对应
            prop: 'checked',
            // 执行内部触发的哪个事件会修改指定的prop
            event: 'check'
    },
    props: ['checked'],
    data() {
            return {
                    status: this.checked
            }
    },
    template: `
            <div class="kkb-radio" :class="{'checked': status}" @click="changeStatus"></div>
    `,
    methods: {
            changeStatus() {
                    this.status = !this.status;
                    this.$emit('check', this.status);
            }
    }
};

let vm = new Vue({
    el: '#app',
    data: {
            val: true
    },
    components: {
            'kkb-radio': kkbRadio,
            'kkb-plane': kkbPlane
    },
    methods: {
            change(status) {
                    this.val = status;
            }
    }
});

10.作用域插槽

<div id="app">
    <dialog :datas="datas">
        <template v-slot:title="data">
            <h1>{{data.title}}</h1>
        </template>

        <template v-slot:default="data">
            <ul>
                <li v-for="user of data.users">
                    {{user.username}}
                </li>
            </ul>
        </template>
    </dialog>
</div>
<script>
    const Dialog = {
        props: ['datas'],
        template: `
                <div class="dialog">
                        <i class="dialog_close_btn"></i>
                        <div class="dialog_header">
                                <slot :title="datas.type" name="title"></slot>
                        </div>
                        <div class="dialog_content">
                                <slot :users="datas.users"></slot>
                        </div>
                </div>
            `
    };

    new Vue({
        el: '#app',
        data() {
            return {
                datas: {
                    type: '学员',
                    users: [{
                            id: 1,
                            username: 'baogege',
                            gender: '男',
                            checked: false
                        },
                        {
                            id: 2,
                            username: 'mt',
                            gender: '男',
                            checked: false
                        },
                        {
                            id: 3,
                            username: 'haigege',
                            gender: '男',
                            checked: false
                        },
                        {
                            id: 4,
                            username: 'zMouse',
                            gender: '男',
                            checked: false
                        },
                        {
                            id: 5,
                            username: 'reci',
                            gender: '女',
                            checked: false
                        },
                        {
                            id: 6,
                            username: 'lisi',
                            gender: '女',
                            checked: false
                        }
                    ]
                }
            }
        },
        components: {
            'dialog': Dialog
        }
    });
</script>

11.生命周期

//捕获子孙组件错误
new Vue({
  .....
  errorCaptured(err, vm, info) {
      //err:  错误信息
      //vm:  错误的组件对象
      //info:  错误类型
   }
})

12.动态加载组件,keep-alive组件

<div id="app">
    <button @click="goto('InBox')" :class="{'current': currentComponent==='InBox'}">收邮件</button>
    <button @click="goto('PostMail')" :class="{'current': currentComponent==='PostMail'}">发邮件</button>
    <button @click="goto('RecycleBin')" :class="{'current': currentComponent==='RecycleBin'}">垃圾箱</button>
    <hr>
    <keep-alive>
            <component :is="currentComponent"></component>
    </keep-alive>
</div>
<script>
    const InBox = {
        data() {
            return {
                items: [
                    '111111',
                    '22222222222',
                    'aaaaaaaa',
                    '3333333'
                ]
            }
        },
        template: `
            <div>
                <ul>
                    <li v-for="item of items">
                        <input type="checkbox" />
                        {{item}}
                    </li>
                </ul>
            </div>
        `,
        created() {
            console.log('InBox:created');
        },
        destroyed() {
            console.log('InBox:destroyed');
        },
        activated() {  //添加keep-live后新增的生命周期,启用的时候触发
            console.log('InBox:activated');
        },
        deactivated() {  //添加keep-live后新增的生命周期,冻结的时候触发
            console.log('InBox:deactivated');
        }
    }
    const PostMail = {
        template: `
            <div>PostMail</div>
        `,
        created() {
            console.log('PostMail:created');
        },
        destroyed() {
            console.log('PostMail:destroyed');
        },
        activated() {  //添加keep-live后新增的生命周期,启用的时候触发
            console.log('PostMail:activated');
        },
        deactivated() {  //添加keep-live后新增的生命周期,冻结的时候触发
            console.log('PostMail:deactivated');
        }
    }
    const RecycleBin = {
        template: `
            <div>RecycleBin</div>
        `,
        created() {
            console.log('RecycleBin:created');
        },
        destroyed() {
            console.log('RecycleBin:destroyed');
        },
        activated() {  //添加keep-live后新增的生命周期,启用的时候触发
            console.log('RecycleBin:activated');
        },
        deactivated() {  //添加keep-live后新增的生命周期,冻结的时候触发
            console.log('RecycleBin:deactivated');
        }
    }
    
    let app = new Vue({
        el: '#app',
        data: {
            currentComponent: 'InBox'
        },
        components: {
            InBox,
            PostMail,
            RecycleBin
        },
        methods: {
            goto(target) {
                this.currentComponent = target;
            }
        }
    });
</script>

13.自定义组件

new Vue({
  el: '#app',
  directives: {
    '指令名称' : {指令配置}
  }
})

###  指令生命周期
- bind : 只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置
- inserted : 被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)
- update : 所在组件更新的时候调用
- componentUpdated : 所在组件更新完成后调用
- unbind : 只调用一次,指令与元素解绑时调用

###  例子
<script>
Vue.directive('drag', {
    bind(el, {modifiers,value}) {
        let isDragStart = false;
        let disX = 0;
        let disY = 0;
        el.canDrag = value;
        el.addEventListener('mousedown', e => {
            if (!el.canDrag) return;
            disX = e.clientX - el.offsetLeft;
            disY = e.clientY - el.offsetTop;
            isDragStart = true;

            e.preventDefault();
        });
        document.addEventListener('mousemove', e => {
            if (isDragStart) {
                let x = e.clientX - disX;
                let y = e.clientY - disY;

                if (modifiers.limit) {
                    if (x < 0) {
                        x = 0;
                    }
                    if (y < 0) {
                        y = 0;
                    }
                }

                el.style.left = x + 'px';
                el.style.top = y + 'px';
            }
        });
        document.addEventListener('mouseup', e => {
            isDragStart = false;
        });
    },
    componentUpdated(el, {value}) {
        console.log('componentUpdated', value);
        el.canDrag = value;
    }
});

let app = new Vue({
    el: '#app',
    data: {
        canDrag: false
    }
});
</script>

14.路由守卫

###  组件内路由
beforeRouteEnter(to, from, next) {  //路由组件进入前
  //这个阶段不能访问this,组件未创建
  //实在需要访问的话
  next(vm => { console.log(vm) })
}
beforeRouteUpdate(to, form, next) {}  //当前路由变化,但该组件属于复用时调用
beforeRouteLeave(to, form, next) {}  //离开对应路由时调用

###  路由独享守卫
beforeEnter(to, from, next) {} //直接使用在路由中, 如:
  const router = new VueRouter({
    routes: [
      {
        path: '/foo',
        conponent: Foo,
        beforeEnter: (to, from, next) => {}
      }
     ]
  })

### 全局路由守卫
router.beforeEach((to, from, next) => {})
router.beforeResolve((to, from, next) => {})
router.beforeEach((to, from) => {})  //导航被确认后调用,就是在整个路由完成最后调用的生命周期

15.route组件的props

//路由中可以定义props属性,值为`true/false`。
//router.js
const router = new VueRouter({
  ...
  routers: [
    {
      path: '/home/:itemId',
      name: 'home',
      compoment: Home,
      props: true
    }
  ]
})
`使用了props属性后,那么在组件中就不需要使用this.$route.params.itemId进行获取,可以直接在组件的props:['itemId']中获取到`

// child.vue
export default {
  ...
  props:['itemId'],
  created() { console.log(this.itemId) }
}

`PS: vue在处理props传值时,如果在组件中的props没有定义所传的属性名,将会保存在this.$attrs中,如:
//parent.vue
<div id="app">
  <child a="1" b="2" c="3"></child>
</div>

//child.vue
export default {
  props: ['a'],
  data() {
    return {}
  },
  created() { console.log(this.$attrs) }    //{b:2, c:3}
}
`

`路由props有三种处理模式`
//1.默认处理
//直接将route.params中的数据和组件中props的数据进行合并

//2.对象模式
//有选择的返回props
{
  path: '/home/:itemId',
  compoment: home,
  props: {a:1, b:2}
}

//3.回调函数模式
{
  path: '/home/:itemId',
  compoment: home,
  props: r => ({itemId: Number(r.params.itemId)})
}

16.切换路由时,页面滚动条保持/归顶

//必须使用浏览器前进回退功能(使用js触发前进回退也行)
const router = new VueRouter({
  scrollBehavior(to, from, savedPosition) {
    if(savedPosition) {
      return savedPosition  //保存上一页的x、y坐标
    } else {
      return {x: 0, y: 0}
    }
  },
  routes: [...]
})
上一篇下一篇

猜你喜欢

热点阅读