vue框架深度解析之vue基础

  • 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>

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

推荐阅读更多精彩内容

  • 这篇笔记主要包含 Vue 2 不同于 Vue 1 或者特有的内容,还有我对于 Vue 1.0 印象不深的内容。关于...
    云之外阅读 5,045评论 0 29
  • 下载安装搭建环境 可以选npm安装,或者简单下载一个开发版的vue.js文件 浏览器打开加载有vue的文档时,控制...
    冥冥2017阅读 6,029评论 0 42
  • Vue 实例 属性和方法 每个 Vue 实例都会代理其 data 对象里所有的属性:var data = { a:...
    云之外阅读 2,202评论 0 6
  • 定位文件位置:Ctrl+[+SAlt + Shift + F10:引用命名空间快捷键F7:查看代码Shift F7...
    AsaGuo阅读 2,422评论 0 0
  • 赶早六点的街道一派冷清,趴在陋巷中的车子还在等着主人。早前熟悉的吆喝,现在七点才会有老板招呼,勤勉不在人心不古啊。...
    叔谦阅读 157评论 0 0