vue查缺补漏

  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: [...]
})
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • 1. Vue 实例 1.1 创建一个Vue实例 一个 Vue 应用由一个通过 new Vue 创建的根 Vue 实...
    王童孟阅读 1,013评论 0 2
  • # 在本文中,笔者又提炼了以下几个重点 补偿双向数据绑定 Vue.$set 数据侦听 Vue.$watch 表单绑...
    果汁凉茶丶阅读 1,459评论 1 15
  • 主要还是自己看的,所有内容来自官方文档。 介绍 Vue.js 是什么 Vue (读音 /vjuː/,类似于 vie...
    Leonzai阅读 3,324评论 0 25
  • VUE介绍 Vue的特点构建用户界面,只关注View层简单易学,简洁、轻量、快速渐进式框架 框架VS库库,是一封装...
    多多酱_DuoDuo_阅读 2,684评论 1 17
  • 每个 Vue 应用都是通过用 Vue 函数创建一个新的 Vue 实例开始的: 实例生命周期钩子 每个 Vue 实例...
    Timmy小石匠阅读 1,371评论 0 11