vue框架深度解析之vue基础

  • Vue实例

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

-- 1. app.$data -> 所有data的数据 [obj](app.data)
-- 2. app.$props -> 所有props的数据 [obj]
-- 3. app.$el -> vue组件挂载到dom上的html节点
-- 4. app.$options Vue实例对象的所有options, 包括默认和我们传进去的通过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 -> 在父组件里通过调用slots-> vue插槽 -> 在组件章节中会有讲解 -- 9.app.refs-> 如果ref绑定组件到dom节点获取模板的真实dom节点, 如果绑定到组件, 获取组件的实例 -- 11.app.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()的对应方法: 如果直接删除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 = '
' } new Vue({ components: { ComP: component}, template: '

我是header

我是默认的插槽

' })

-- 插槽传值

const component = {
  template = '
', data () { return { a: 'a的值' } } } new Vue({ components: { ComP: component}, template: ' // 组件的ref是组件的实例(不推荐, 应该使用props), dom几点的ref是dom节点

我是header

{{obj.a}}我是默认的插槽{{obj.b}}

' })
  1. provideinject: 往任意后代组件传值, provide原生不支持reactive的, 需要用到Object.defineProperty()方法
const sunCom = {
  inject: ['yeye', 'data'],
  template: `
我是孙子
`, mounted () { console.log(this.$parent.$options.name) // er-com console.log(this.yeye, this.data.value) // } } const erCom = { name: 'er-com', components: {sunCom}, template: `` } 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: ``, data: { value: 'yeye的value' } })
  • vue之render()

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

--
--
--
--
--

你可能感兴趣的:(vue框架深度解析之vue基础)