VUE笔记(1)

文章目录

  • 开始使用Vue
    • el
    • $mount
    • data
    • 插值表达式
  • vue的响应式-1
    • vm.$el
    • vm.$nextTick & Vue.nextTick
  • vue的响应式-2
  • 扩展_剖析Vue响应式原理
  • Vue相关指令
    • v-pre
    • v-cloak
    • v-once
    • v-text
    • v-html
  • 条件渲染
    • v-if
    • v-else
    • v-else-if
    • v-show
    • v-if VS v-show
  • v-bind 指令
  • v-on指令
    • 为什么在 HTML 中监听事件?
  • v-on指令的修饰符
    • 事件修饰符
      • .stop
      • .prevent
      • .capture
      • .self
      • .once
      • .passive
      • 注意
    • 按键修饰符
      • 按键码
    • 系统修饰键
      • exact 修饰符
    • 鼠标按钮修饰符
  • 列表渲染
    • 在v-for中使用数组
    • 在v-for中使用对象
    • 在v-for中使用数字
    • 在v-for中使用字符串
    • 循环一段包含多个元素的内容
    • 关于key
      • key的使用方法
    • v-for 和 v-if 一同使用
  • v-model指令
    • input
      • type=text 文本框
      • type=checkbox 复选框
        • 单个复选框
        • 多个复选框
      • type=radio 单选框
    • textarea
    • select
      • 单选
      • 多选
    • 修饰符
      • .lazy
      • .number
      • .trim
  • 计算属性
    • 基础用法
    • 计算属性 vs 方法
    • 深入计算属性
      • getter 读取
      • setter 设置
  • 侦听器
    • 值类型
      • 函数类型
      • 字符串类型
      • 对象类型
        • handler
        • deep
        • immediate
      • 数组类型
    • 键类型
      • 正常对象key值
      • 字符串类型key值
    • vm.$watch
    • 侦听器 vs 计算属性
  • vue-resource
    • 引入vue-resource
    • 请求方法
      • POST请求
      • GET请求
      • PUT请求
      • PATCH请求
      • DELETE请求
      • HEAD请求
      • JSONP请求
    • options 参数说明
    • 响应对象
      • 属性
      • 方法
    • 最后的话
  • Axios
    • 引入
    • API
    • config 配置对象
    • 方法别名
    • 配置默认值
      • 全局配置
      • 实例配置
      • 请求配置
      • 配置的优先顺序
    • 并发
    • 拦截器
      • 请求拦截器
      • 响应拦截器
      • 移除拦截器
      • 为axios实例添加拦截器
    • 取消请求
    • 错误处理
    • axios 预检
  • template 选项
  • Vue生命周期
    • 生命周期图示
    • 生命周期钩子
      • beforeCreate
      • created
      • beforeMount
      • mounted
      • beforeUpdate
      • updated
      • beforeDestroy
      • destroyed

开始使用Vue

  1. 引入vue.js

    官网:vuejs.org

    开发版本:包含完整的警告和调试模式

    生产版本:删除了警告,体积更小

  2. 引入vue.js后,给我们提供了一个构造函数 Vue

  3. 在js中,new Vue()

  4. new Vue() 后会返回一个vue实例对象,我们用变量接着它

  5. const vm = new Vue()

  6. 传递一个配置对象{} – > const vm = new Vue({})

el

类型: 字符串

全称:element(元素)

作用:配置控制的元素,表示Vue要控制的区域,值为css选择器

  
  <div id="app">div>
  const vm = new Vue({
    el: '#app' // 控制id为app的元素
  })

$mount

  • 作用和el一致,都是配置控制的元素,使用哪个都可以,二选一
      <div id="app">div>
    
      const vm = new Vue({})
      vm.$mount('#app');
    
  • 问:和el有什么不同?

    答:本质上没什么不同,$mount为手动挂载,在项目中有时要进行延迟挂载,比如有时要在挂载之前进行一些其他的操作,比如判断等等(但是,这样做的时候很少,比邓哥回家的次数还少,emmmmm)

data

  • 类型:对象
  • 作用:存放要用到的数据,数据为响应式的
      const vm = new Vue({
        el: '#app',
        data: {
          'mrDeng': '风姿绰约、花枝招展'
        }
      })
    

插值表达式

  • 使用方法: {{ }}

  • 可以将vue中的数据填在插值表达式中,如:

      <div id="app">{{ mrDeng }}div>
    
      const vm = new Vue({
        el: '#app',
        data: {
          mrDeng: '邓哥:风姿绰约、花枝招展'
        }
      })
    
  • 除了填写data之外,还可以直接填写数据值(数字、字符串、布尔值、undefined、null、数组、对象),如:

      <div id="app">
        {{ 5201314 }}
        {{ '婀娜多姿、亭亭玉立' }}
        {{ true }}
        {{ ['邓旭明', '小刘', '王小宝'] }}
        {{ {name: '邓旭明', age: 80, height: '140cm', weight: '100kg'} }}
      div>
    
  • 注意:在插值表达式中直接书写对象类型值时,不要将三个{}连在一起,这样会报错,如:

      <div id="app">
        
        {{{name: '邓旭明', age: 80, height: '140cm', weight: '100kg'}}} 
      div>
    
  • 还可在插值表达式中写表达式,如:

      <div id="app">
        
        {{ 'you' + 'me' }}
        {{ 10 - 5 }}
        {{ 100 * 7 }}
        {{ 1000 / 12 }}
        
        {{ liu || li }}
        {{ deng && liu }}
        {{ !wang }}
        
        {{ 1 + 1 === 3 ? '邓旭明' : '正常人' }}
        
      div>
    
  • 还可以填写其他的吗?不可以,No,以下这些都是不行滴:

      <div id="app">
        
        {{ var Deng = 'shuaige'; console.log(deng) }}
        
        {{ if(Deng.looks === 'shuai'){ console.log('不可能')} }}
      div>
    
  • 记住:插值表达式中,可以写:data、js数据、表达式,其他的想都不要想。

  • 注意,只要插值表达式中使用了数据,必须在data中声明过,否则会报错

      
      <div id="app">
        {{ mrCheng }}
      div>
    
      const vm = new Vue({
        el: '#app',
        data: {
          mrDeng: '邓哥:风姿绰约、花枝招展'
        }
      })
    
  • 还有另外一种可能,使用了未被声明过的数据,不报错:

      
      
      
      
      <div id="app">
        {{ mrDeng.wife }}
      div>
    
      const vm = new Vue({
        el: '#app',
        data: {
          mrDeng: {
            name: '邓旭明', 
            age: 80, 
            height: '140cm', 
            weight: '100kg'
          }
        }
      })
    

vue的响应式-1

  • 数据变化,页面就会重新渲染

  • 怎么更改数据?so easy

  <div id="app">
    {{ mrDeng }}
  div>
  const vm = new Vue({
    el: '#app',
    data: {
      mrDeng: '邓哥:风姿绰约、花枝招展'
    }
  });
  vm.mrDeng = '手如柔荑、肤如凝脂'; // 见证奇迹的时刻,页面变化啦
  • 问:为什么data会直接出现在vm实例对象中咧?

答:当创建vue实例时,vue会将data中的成员代理给vue实例,目的是为了实现响应式,监控数据变化,执行某个监听函数(怎么实现的?想一想,提示:Object.defineProperty,试着实现一下)

  • 问:实例中除了data数据外,其他东西是啥子?

为了防止名称冲突。因为会将data中数据代理给vue,假如说我们自己写的data名称和vue中自带的属性冲突了,那么就会覆盖vue内部的属性,所以vue会把自己内部的属性成员名称前加上$或_,如果加上的是$,代表是我们可以使用的,如果加上的是_,是vue自己内部使用的方法或属性,我们不需要调用

  • 更改的数据必须是存在的数据,否则不能重新渲染页面,因为他监听不到,如:
  
  <div id="app">
    {{ mrDeng.wife }} 
  div>
  const vm = new Vue({
    el: '#app',
    data: {
      mrDeng: {
        name: '邓旭明', 
        age: 80, 
        height: '140cm', 
        weight: '100kg'
      }
    }
  })

  vm.mrDeng.wife = 'liu';
  • 更改的数据必须已渲染过的数据,否则从性能角度考虑,不会重新渲染页面,如:
  
  <div id="app">
    {{ mrDeng.wife }} 
  div>
  const vm = new Vue({
    el: '#app',
    data: {
      msg: '邓哥:风姿绰约、花枝招展',
      mrDeng: {
        name: '邓旭明', 
        age: 80, 
        height: '140cm', 
        weight: '100kg'
      }
    }
  })

  vm.mrDeng.wife = 'liu';
  vm.msg = '邓哥:手如柔荑、肤如凝脂';
  • 更改数据后,页面会立刻重新渲染吗?

vue更新DOM的操作是异步执行的,只要侦听到数据变化,将开启一个异步队列,如果一个数据被多次变更,那么只会被推入到队列中一次,这样可以避免不必要的计算和DOM操作。

同步执行栈执行完毕后,会执行异步队列

<div id="app">{{ msg }}div>
const vm = new Vue({
  el: '#app',
  data: {
    msg: '杉杉'
  }
})
vm.msg = '杉杉超美的';
console.log(vm.msg); // 杉杉超美的,此时数据已更改
console.log(vm.$el.innerHTML); // 杉杉。此时页面还未重新渲染

vm.$el

  • 值为被Vue控制的元素(或者说,Vue挂载的元素)

vm.$nextTick & Vue.nextTick

  • 如何在更改数据后,看到渲染后的页面上的值?

答:利用vm.$nextTick或Vue.nextTick,在页面重新渲染,DOM更新后,会立刻执行vm.$nextTick

<div id="app">{{ msg }}div>
const vm = new Vue({
  el: '#app',
  data: {
    msg: '杉杉'
  }
})
vm.msg = '杉杉超美的';
console.log(vm.msg); // 杉杉超美的,此时数据已更改
// 1. 使用vm.$nextTick
vm.$nextTick(() => {
  console.log(vm.$el.innerHTML); // 杉杉超美的
})
// 2. 使用Vue.nextTick
Vue.nextTick(() => {
  console.log(vm.$el.innerHTML); // 杉杉超美的
})
  • vm.nextTick和Vue.nextTick还可以作为Promise使用
<div id="app">{{ msg }}div>
const vm = new Vue({
  el: '#app',
  data: {
    msg: '杉杉'
  }
})
vm.msg = '杉杉超美的';
// 1. 使用vm.$nextTick
vm.$nextTick().then(() => {
  console.log(vm.$el.innerHTML); // 杉杉超美的
})
// 2. 使用Vue.nextTick
Vue.nextTick().then(() => {
  console.log(vm.$el.innerHTML); // 杉杉超美的
})
  • vm.$nextTick 和 Vue.nextTick的区别?

Vue.nextTick内部函数的this指向window

  Vue.nextTick(function () {
    console.log(this); // window
  })

vm.$nextTick内部函数的this指向Vue实例对象

  vm.$nextTick(function () {
    console.log(this); // vm实例
  })
  • 好奇nextTick是怎么实现的吗?
  • 异步任务分为宏任务(macro)和微任务(micro)
  • 宏任务比较慢(如setTimeout等),微任务比较快(如Promise.then()等)
  • 微任务在前,宏任务在后(eventloop,事件环)
      // 控制台打印顺序:promise > timeout
      setTimeout(() => {
        console.log('timeout');
      }, 0)  
      Promise.resolve().then(() => {
        console.log('promise');
      })
    
  • 在nextTick的实现源码中,会先判断是否支持微任务,不支持后,才会执行宏任务
      if(typeof Promise !== 'undefined') {
        // 微任务
        // 首先看一下浏览器中有没有promise
        // 因为IE浏览器中不能执行Promise
        const p = Promise.resolve();
    
      } else if(typeof MutationObserver !== 'undefined') {
        // 微任务
        // 突变观察
        // 监听文档中文字的变化,如果文字有变化,就会执行回调
        // vue的具体做法是:创建一个假节点,然后让这个假节点稍微改动一下,就会执行对应的函数
      } else if(typeof setImmediate !== 'undefined') {
        // 宏任务
        // 只在IE下有
      } else {
        // 宏任务
        // 如果上面都不能执行,那么则会调用setTimeout
      }
    
  • 曾经vue用过的宏任务
    • MessageChannel 消息通道 宏任务

vue的响应式-2

  • 除了未被声明过和未被渲染的数据外,还有什么数据更改后不会渲染页面?

    1. 利用索引直接设置一个数组项时:

    
    
    <div id="app">{{ dengFamily }}div>
    
    const vm = new Vue({
      el: '#app'
      data: {
        dengFamily: ['邓哥', '小刘', '王小宝']
      }
    })
    vm.dengFamily[3] = '铁锤妹妹'; // 不是响应式的
    

    2. 修改数组的长度时:

    
    <div id="app">{{ dengWife }}div>
    
    const vm = new Vue({
      el: '#app'
      data: {
        dengWife: ['小刘']
      }
    })
    vm.dengWife.length = 0; // 不是响应式的
    

    3. 添加或删除对象:

    
    <div id="app">{{ deng }}div>
    
    const vm = new Vue({
      el: '#app'
      data: {
        deng: {
          wife: '小刘',
          son: '王小宝',
          weight: '100kg',
          height: '140cm',
          age: 60
        }
      }
    })
    vm.deng.secondWife = '铁锤妹妹'; // 不是响应式的
    delete vm.deng.height; // 不是响应式的
    
  • 问:要如何响应式的更新数组和对象?

    更改数组:
    1. 利用数组变异方法:push、pop、shift、unshift、splice、sort、reverse
    2. 利用vm.$set/Vue.set实例方法
    3. 利用vm.$delete或Vue.delete删除数组中的某一项

    vm.$set是Vue.set的别名
    使用方法:Vue.set(object, propertyName, value),也就是这个意思:Vue.set(要改谁,改它的什么,改成啥)

    vm.$delete是Vue.delete的别名
    使用方法:Vue.delete(object, target),也就是这个意思:Vue.delete(要删除谁的值,删除哪个)

    
    <div id="app">{{ dengFamily }}div>
    
    const vm = new Vue({
      el: '#app'
      data: {
        dengFamily: ['邓哥', '小刘', '王小宝']
      }
    })
    // 使用数组变异方法
    vm.dengFamily.push('铁锤妹妹');
    // 使用vm.$set
    vm.$set(vm.dengFamily, 3, '铁锤妹妹');
    
    
    
    <div id="app">{{ dengWife }}div>
    
    const vm = new Vue({
      el: '#app'
      data: {
        dengWife: ['小刘']
      }
    })
    // 通过用数组的splice方法从数组中添加项目.
    vm.dengWife.splice(1,0,"小张","小王","铁锤妹妹");  //1:从数组的第1位开始, 0:不删除项目, 后续是像数组中添加的新项目(可选);
    

    更改对象:
    1. 添加利用vm.$set/Vue.set实例方法
    2. 删除利用vm.$delete/Vue.delete方法

    <div id="app">{{ deng }}div>
    
    const vm = new Vue({
      el: '#app'
      data: {
        deng: {
          wife: '小刘',
          son: '王小宝',
          weight: '100kg',
          height: '140cm',
          age: 60
        }
      }
    })
    // 添加
    vm.$set(vm.deng, 'secondWife', '铁锤妹妹');
    // 删除
    vm.$delete(vm.deng, 'height')
    
  • 总结:

    更改数组用变异方法,就够了
    更改对象就用vm.$set和vm.$delete

  • 问题解决了,但是为什么会这样呢?

    Object.defineProperty的锅,咱们下节课说~

扩展_剖析Vue响应式原理

const data = {
  name: 'shanshan',
  age: 18,
  shan: {
    name: 'shanshan',
    age: 18,
    obj: {}
  },
  arr: [1, 2, 3]
}

const arrayProto = Array.prototype;
const arrayMethods = Object.create(arrayProto);
['push', 'pop', 'shift', 'unshift' ,'sort', 'splice', 'reverse'].forEach(method => {
  arrayMethods[method] = function () {
    arrayProto[method].call(this, ...arguments);
    render();
  }
})

function defineReactive (data, key, value) {
  observer(value);
  Object.defineProperty(data, key, {
    get () {
      return value;
    },
    set (newVal) {
      if(value === newVal) {
        return;
      }
      value = newVal;
      render();
    }
  })
}

function observer (data) {
  if(Array.isArray(data)) {
    data.__proto__ = arrayMethods;
    return;
  }

  if(typeof data === 'object') {
    for(let key in data) {
      defineReactive(data, key, data[key])
    }
  }
}

function render () {
  console.log('页面渲染啦');
}

function $set (data, key, value) {
  if(Array.isArray(data)) {
    data.splice(key, 1, value);
    return value;
  }
  defineReactive(data, key, value);
  render();
  return value;
}

function $delete(data, key) {
  if(Array.isArray(data)) {
    data.splice(key, 1);
    return;
  }
  delete data[key];
  render();
}

observer(data);

利用Object.defineProperty实现响应式的劣势

  1. 天生就需要进行递归
  2. 监听不到数组不存在的索引的改变
  3. 监听不到数组长度的改变
  4. 监听不到对象的增删

Vue相关指令

  • 具有特殊含义、拥有特殊功能的特性
  • 指令带有v-前缀,表示它们是Vue提供的特殊特性
  • 指令可以直接使用data中的数据

v-pre

  • 跳过这个元素和它的子元素的编译过程。可以用来显示原始 Mustache 标签。跳过大量没有指令的节点会加快编译。
    
    <span v-pre>{{ msg }}span>
    

v-cloak

  • 这个指令保持在元素上直到关联实例结束编译

  • 可以解决闪烁的问题

  • 和 CSS 规则如 [v-cloak] { display: none } 一起用时,这个指令可以隐藏未编译的 Mustache 标签直到实例准备完毕

    [v-cloak] {
      display: none;
    }
    
    
    <div v-cloak>
      {{ message }}
    div>
    

v-once

  • 只渲染元素一次。随后的重新渲染,元素及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能
    
    <span v-once>{{msg}}span>
    
    <div v-once>
      <h1>commenth1>
      <p>{{msg}}p>
    div>
    

v-text

  • 更新元素的 textContent
    <span v-text="msg">span>
    
    <span>{{msg}}span>
    

v-text VS Mustache

  • v-text替换元素中所有的文本,Mustache只替换自己,不清空元素内容
    
    <span v-text="msg">----span>
    
    <span>----{{msg}}----span>
    
  • v-text 优先级高于 {{ }}

textContent VS innerText

  1. 设置文本替换时,两者都会把指定节点下的所有子节点也一并替换掉。
  2. textContent 会获取所有元素的内容,包括

你可能感兴趣的:(笔记)