美文网首页
vue框架深度解析之vue基础

vue框架深度解析之vue基础

作者: 胖太_91bf | 来源:发表于2018-04-08 11:41 被阅读0次
    • Vue实例

    1. Vue实例创建和作用
    const app = new Vue({
      // el: '#root',
      template: '<div>{{text}}</div>',
      data: {
        text: 'text'
      }
    })
    app.$mount('#root')
    

    -- 1. app.$data -> 所有data的数据 [obj](app.data 和 app.data是同一个对象)(vue把app.data上的属性代理到app.data)
    -- 2. app.$props -> 所有props的数据 [obj]
    -- 3. app.$el -> vue组件挂载到dom上的html节点
    -- 4. app.$options Vue实例对象的所有options, 包括默认和我们传进去的通过options是无法修改Vue实例的属性的(至少data是), 应为, Vue实例上的data并不是和options.data是同一个对象
    -- 5. app.$options.render = h => { return h(div, {}, 'new render function')} -> 这里的 h其实是createElement()方法参数1. 标签名2. 存放标签属性的对象4.标签内容(如果还是标签,就会循环使用createElement()),也可以不传参数 h 直接使用this.$createElement()方法
    -- 6. app.$root -> 指的的是挂载到真实html上的根实例对象
    -- 7. app.$children -> 在父组件里通过调用children可以访问子组件的实例 -- 8. `app.slots-> vue插槽 -> 在组件章节中会有讲解 -- 9.app.scopedSlots` -> vue插槽存储传值的对象 -> 在组件章节中会有讲解 -- 10. `app.refs-> 如果ref绑定组件到dom节点获取模板的真实dom节点, 如果绑定到组件, 获取组件的实例 -- 11.app.isServer` -> 判断是否ssr -- 12. 在组件内部可以调用parent, 获取父组件的实例. 可以改变父组件的属性, 不推荐, 在且只在new Vue实例的parent属性中定义一个父组件, 这样就可以获取这个组件的实例, 普通组件中的组件间的关系是vue渲染中指定了, 无法修改

    // comp1 可以通过this.$parent获取comp0的实例
    new Vue {
      parent: comp0
    }
    

    2.Vue实例的属性

    1. Vue实例的方法
      -- 1. app.$mount()-> 将Vue实例挂载到真实Dom上
      -- 2. app.$watch() -> 监听data里的数据,作用同组件内的watch, 在组件销毁的同事, 需要注销掉, 否则会导致内存溢出, 在组件内生命的watch伴随这组件的消亡而注销, 而调用的$watch方法需要手动注销
    // 监听data数据并得到注销watch的函数
    const unWatch = app.$watch('text', (newText, oldText) => {})
    // 注销watch
    unWatch()
    

    -- 3. app.$onapp.$emit -> 用来派发(emit)和监听(on)事件, 必须同事作用于同一vue对象否则不会冒泡 app.$once -> 只触发一次

    app.$on('test', (a, b) => {
      console.log(`test emited ${a} ${b}`)
    })
    app.$emit('test', 1, 2)
    

    -- 4. app.$forceUpdate -> 强制组件重新渲染一次

    new Vue({
      ...,
      data: {
        obj: {} // vue是响应式的框架, 如果没有声明对象里边的属性而直接给这个属性赋值, 就不是响应式的, 可以在每次调用这个属性的时候, 执行一次app.$forceUpdate(), 但是这样性能太低
      }
    })
    

    -- 5. app.$set() -> 用来给date里的数组和对象添加响应式的属性, 相当于把某些值, 补到了data里

    app.$set(app.obj, 'a', 123)
    

    -- 6. app.$delete(app.obj, 'a') -> app.$set()的对应方法: 如果直接删除set添加的属性, 只会删除值, 其值的reactive还在, 会导致内存溢出 -- 7. `app.nextTick(callback())-> 这个和js的事件队列有关, vue的渲染过程是异步的,举个例子: 在setInterval()里, 声明一个变量i并让i++五次, 最后打印i的值, 得到的结果不会是, 一个一个往上加, 而是5个5个的往上加, 这就是js事件队列 -> js会把当前的队列都执行一遍, 然后在循环一遍, 执行新添加的队列,如果是需要操作dom节点的, 肯定是要在dom全渲染完之后才行, $nextTick就是再dom完全渲染完之后, 才执行回调(如果你拿不到dom或者值跟新了页面没更新, 这个时候你可能会用到$nextTick) -- 8.app.$destroy()` -> 主动销毁组件

    • vue组件的生命周期

    1. beforeCreate() -> 组件初始化就会执行
      -- 初始化events和 lifecycle, reactive并没有初始化, 不要做数据的修改
    2. created()
      -- created()之后会判断是否有el属性, 没有就等待$mount方法被调用,
      初始化injections 和reactive
    3. beforeMount() -> 将组件的template编译挂载到dom上 -> $el是vue绑定到的真事dom
      中间有个 render(createElement) -> 在render之前会vue会查看是否有template属性, 有的话, 会通过render把template渲染到页面上, 没有的话就会显示vue挂载的节点
    4. mounted() -> $el是组件template里的数据
    5. beforeUpdate() -> 数据更新的时候执行
    6. updated()
    7. activated() -> keepalive激活的时候执行
    8. deactivated() - keepalive停用的时候执行
    9. beforeDestroy() - 组件销毁的时候触发
    10. destroyed()
    11. renderError(h, err){return h('div', {}, err.stack)} -> render()报错时会调用此方法, 只会在开发环境调用, 只管自己的组件的错误, 不能冒泡
    12. errorCaptured () {} -> 可以捕捉到子组件的报错, 用法类似renderError() 可以在线上使用
      调用一次的: create类, mount类, destroy类
      ssr调用的: create类
      生命周期中vue实例有哪些区别? -> $el会有所不同

    注: 在使用.vue开始方式, 都没有template, vue-loader会直接将.vue文件中的template解析成render()方法, 这样更快

    • vue的数据绑定

    1. class的数据绑定
    :class="{active: isActive}" -> 如果isActive是true就添加active的类名
    :class="['header', {active: isActive}, isActive ? 'red' : 'green']" 
    
    1. style的数据绑定: 动态绑定的style会自动添加浏览器前缀
    :style="[s1, s2, {color: 'red'}]"
    data () {return { s1, s2 }}
    
    • computed和watch

    1. computed是vue的计算属性, 可以对data进行处理, 拥有缓存机制, 只有当相关数据改变的时候, 才会执行computed里的相关函数, 这也是为什么要用computed而不是在methods创建一个方法

    computed写在标签上时候, 不用加(), 这是因为, computed是通过Object.defineProperty(obj, 'abc', { get: () => xxx, value: xxx }), 通过get方法可以直接以变量名的方式调用函数

    {
      computed: {
        name () {
          return first + last
        }
      }
    }
    // computed内部支持Object.defineProperty()的get和set函数
    {
      computed: {
        name: {
          get () {},
          set (name) {在这里可以改变data中的数据(不推荐, 容易搞出死循环)}
        }
      }
    }
    
    1. watch: 监听数据的变化, 当数据变化时才执行这个watch里的方法
    watch: {
      first (newData, oldData) {
         console.log('change', newData, oldData)
      }
    }
    

    // watch可以通过设置参数去立刻执行

    在data里声明对象时, 有几个坑, 1. 如果为声明对象的属性, 那么只有第一次给obj属性赋值时会触发watch, 2. 即便在data里声明了obj.a,通过obj.a的方式修改数据, 也不会触发watch监听, watch只会监听obj的对象引用, 通过this.obj = {a:1}的方式才能被watch监听到,

    watch: {
        // obj: {
        //   handler (newData, oldData) {
        //     console.log('obj.a change')
        //   },
        //   immediate: true // 立即执行watch
        //   deep: true // 为true时候, watch会递归循环obj里的说有属性, 性能低
        // }
        // 这种方式可以监听obj的属性, 性能高用字符串里去写对象的深入调用
        'obj.a': () => {
          console.log('obj.a change')
        }
      }
    
    • vue原生指令

    指令修饰符: @click.stop: 组织冒泡, @keydown.13: 按回车, v-model.number="": 输入的数字为number类型, v-model.trim="": 输入的内容清除前后空格, @touchend.capture=""或@touchstart.capture="": 事件捕获

    1. v-text: 显示文本, 标签只能显示v-text里的内容
    2. v-html: 显示未转义的内容, 可以解析标签
    3. v-show: 原理display:none
    4. v-if: 节点不放在dom流里, 动态增删节点, 性能低重绘
    5. v-for: 遍历数组和对象, 性能优化添加:key="内容不要index" -> 通过:key里边的内容(唯一的id)去判断是否重新渲染这一行:数组: v-for="(item, index) in items", 对象: v-for-"(val, key, index) in obj"
    6. v-on: 简写@: 绑定事件, 如果是dom节点:使用addEventListener, 如果是组件使用$on, 修饰符: .stop组织冒泡
    7. v-bind:简写: :绑定变量
    8. v-model: 表单响应式的改变数据, 修饰符 .number: 数字为Number类型, .lazy: blur时显示数据, .trim: 清除前后空格
      -- checkbox的v-model绑定一个变量, 只要这个变量为true就是选中状态, 2. 可以对多个checkbox使用数组, 每一个checkbox的value就是这数组对应的值
      -- radio: v-model绑定的变量和radio的value相等时, 为选中状态
    9. v-once: {{}}只执行一次, 之后就不会检测
    10. v-pre: 直接输出{{}}和里边的内容
    • 组件的定义

    1. 全局定义: Vue.component('ComP', component1)
    2. 组件内定义子组件: components: { ComP: component1 }
    3. props: 指定子组件的可配置行为
    props: ['active', 'data']
    props: {
      active: {
        type: Boolean,
        default: false,
        required: true
      },
      data: {
        type: [String, Number]
      }
    }
    // props的自定义核验
    props: {
      active: {
        // type: Boolean,
        validator (value) {
           return typeof value === Boolean
        }
      }
    }
    
    • 组件的extend => 扩展vue,两种extend方式,

    -- 第一种, 实例化扩展: 类似于子组件, 可以通过 propsData传递props, 钩子函数先调用, component里的, data会覆盖component里的

    const compVue = Vue.extend(component)
    new CompVue({
      el: '#root', 
      propsData: {
        prop1: 'xxx'
      }
    })
    

    -- 第二种在组件内的extends属性中什么要继承的组件

    extends: component
    

    如何去用呢? 在一个比较完善的组件里, 配置项太多, 或者还需要扩展, 这时候, 就可以在你的组件上extends这个组件, 然后去覆盖或拓展他的配置

    • 组件的高级属性

    1. slot插槽:
      -- 具名插槽:
    const component = {
      template = '<div>
          <slot name="header"></slot>
          <slot></slot>
        </div>'
    }
    new Vue({
      components: { ComP: component},
      template: '
        <com-p>
          <p slot="header">我是header</p>
          <p>我是默认的插槽</p>
        </com-p>
      '
    })
    

    -- 插槽传值

    const component = {
      template = '<div>
          <slot name="header"></slot>
          <slot :a="aaa" b="bbb"></slot>
        </div>',
      data () {
        return {
          a: 'a的值'
        }
      }
    }
    new Vue({
      components: { ComP: component},
      template: '
        // 组件的ref是组件的实例(不推荐, 应该使用props), dom几点的ref是dom节点
        <com-p ref="comp">
          <p slot="header" ref="p">我是header</p>
          <p scope-slot="obj">{{obj.a}}我是默认的插槽{{obj.b}}</p>
        </com-p>
      '
    })
    
    1. provideinject: 往任意后代组件传值, provide原生不支持reactive的, 需要用到Object.defineProperty()方法
    const sunCom = {
      inject: ['yeye', 'data'],
      template: `<div>我是孙子</div>`,
      mounted () {
        console.log(this.$parent.$options.name)  // er-com
         console.log(this.yeye, this.data.value) // 
      }
    }
    const erCom = {
      name: 'er-com',
      components: {sunCom},
      template: `<sun-com></sun-com>`
    }
    new Vue({
      // provide必须是一个函数, 否则this实例不会出现的
      provide () {
        // 官方不推荐, 有可能会改变写法或弃用
        // 通过defineProperty()自己指定一个get方法
        const data = {}
        // 解释一下下边的代码: 每次获取 value的时候, 都会直接调用get()方法, 设置为可枚举后, get方法就会每次获取最新的数据
        // vue的reactive基础就是Object.defineProperty()里的get()方法
        Object.defineProperty(data, 'value', {
          get: () => this.value,
          enumerable: true // 把属性设置成可枚举的, (可遍历)
         })
        return {
           yeye: this,
           data
        }
      },
      components: {erCom},
      template: `<er-com><er-com>`,
      data: {
        value: 'yeye的value'
      }
    })
    
    • vue之render()

    {
      ...,
      render() {
        return this.$createElement('div', {标签属性}, 标签内容(还有标签就在调用[$createElement)]多节点用数组)
      }
    }
    
    • vue的原生组件:

    -- <router-view>
    -- <router-link>
    -- <keep-alive>
    -- <slot>
    -- <transition>

    相关文章

      网友评论

          本文标题:vue框架深度解析之vue基础

          本文链接:https://www.haomeiwen.com/subject/zzwdhftx.html