Vue 基础、选项/数据、模板语法、指令、数据代理/检测(笔记)

1. 什么是vue

  • vue 是一套用于构建用户界面渐进式 JavaScript 框架
  • 构建用户界面:把对应的数据渲染到页面上
  • 渐进式:对于简单应用 vue 的核心库非常轻量小巧,对于复杂应用可以引入各式各样的 vue 插件

2. vue的特点

  1. 采用组件化模式,提高代码复用率、且让代码更好的维护
  2. vue 是单页面应用,使页面局部刷新
  3. 声明式编码( 直接在标签上写 vue 指令 ),无需操作 dom,提高开发效率
  4. 使用虚拟 dom 和 diff 算法,避免真实 dom 过多的创建与销毁

3. MVVM模型

  • M:模型(Model),对应 data 中的数据
  • V:视图(View):模板
  • VM:视图模型(ViewModel):Vue 实例对象
  • 无需操作 DOM,数据发生变化视图自动更新

4. 初始vue

<!-- 创建视图(vue 模板) -->
<div id="app">
  <button @click="btn">点击</button>
</div>

<!-- 引入 vue 框架,使用的 CDN 引入 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>

<!-- 创建实例 -->
<script>
  const vm = new Vue({ // 创建 vue 实例
    el: "#app", // 挂载,用于指定这个实例为哪个视图服务
    data: { // 用于存储数据,在视图中可以直接使用,在 vue 中可以通过 this 获取
      msg: "hello Vue"
    },
    methods: { // 
      btn() {
        console.log(this.msg);
      }
    }
  })
</script>

5. 模板语法(插值表达式)

数据绑定最常见的形式就是使用“Mustache”语法(双大括号)的文本插值

<!-- 
  可以在 *标签体* 中写一些js代码,只能是表达式,不能是js语句
	一、表达式:表达式会产生一个值
	  1. a
	  2. a + b
	  3. true ? 1 : 0
	  4. (function(){return "在页面中 Vue 会显示我"})()
	二、js语句
	  1. if(){}
	  2. let abc

	msg 为 data 中的数据
-->
<div id="app">{{msg}}</div>
{{ number + 1 }}

{{ ok ? 'YES' : 'NO' }}

{{ msg.split('').reverse().join('') }}

<!-- 这样写是不可以的,和 eval 中的内容很像 -->
{{let num}} 

6. vue内置指令

6.1 v-on:事件绑定
<script>
 // v-on ===> @,语法糖写法
 // 1. 事件修饰符
 // .stop:调用 event.stopPropagation(),阻止事件冒泡
 // .prevent:调用 event.preventDefault(),阻止默认事件
 // .once:事件只触发一次
 // .capture:转为事件捕获
 // .self:只有 event.target 是当前元素时才会触发
 // .passive:事件的默认行为立即执行,无需等待事件回调执行完毕
 //    (比如滚轮事件,要等事件回调执行完成之后,页面才会发生滚动,加了这个事件修饰符后,可以直接滚动)
 // .native:监听组件根元素的原生事件
 
 
 // 2. 键盘事件
 // (1). Vue 中常用的按键的别名,和事件修饰符的用法一样
 // 只能触发对应的键盘事件
 // 回车 => enter
 // 删除 => delete
 // 退出 => esc
 // 空格 => space
 // 换行 => tab
 // 上 => up
 // 下 => down
 // 左 => left
 // 右 => right
 
 // (2). 其他事件
 // 直接使用 event 事件对象中 key 值即可,不过需要小写,多个单词 CapsLock => caps-lock
 // keyCode 也可以,但是 MDN 不推荐使用,已经从 web 标准中移除
    
 // (3). Vue.config.keyCodes.自定义键名 = keyCode ,可以自定义键盘别名
</script>

<!-- 用法 -->
<button @click.stop="btn"></button>

<!-- 还可以连续点击 -->
<a v-on:click.stop.prevent="doThat"></a>

<!-- 事件对象,这两种方法在函数中的第一个参数,都可以接收事件对象 -->
<button @click="btn"></button> 			<!-- 不可以传参 -->
<button @click="btn($event)"></button>  <!-- 可以传参 -->
6.2 v-bind:属性绑定
<!-- v-bind ===> : ,语法糖写法 -->
<!-- imageSrc 为 Vue 中 data 的数据 -->
<img :src="imageSrc">

<!-- 也可以配合 class 使用 {} -->
<!-- isActive 为真时,div 存在 active 类名,为假时,没有类名 -->
<div :class="{ active: isActive }"></div>

<!-- 也可以使用数组,添加多个属性 -->
<!-- 注意:box、active 为 data 中的数据 -->
<div :class="[box, active]"></div>
<!-- 如果不想使用变量 ['box', 'active'] 即可 -->

<!-- 
  关于数组/对象的写法,可以直接创建一个 arr/obj,放在 data 中
  然后在 class 中写 arr/obj 也可以,这种方式更容易管理
-->

<!-- 当然也可以配合使用 -->
<div :class="[box, { active: isActive }]">张三</div>

<!-- 动态属性名,key 为 data 中的数据,如果 key: class,就代表属性为 class -->
<button :[key]="value"></button>

<!-- 配合 style 使用,数组对象嵌套也可以 -->
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
<div v-bind:style="[{ color: activeColor, fontSize: fontSize + 'px' }]"></div>
6.3 v-text:更新元素
<!-- msg 是 Vue 中 data 的数据 -->
<!-- text 专门展示文本的 -->
<span v-text="msg">我是span中的内容,我会被覆盖</span>
6.4 v-html:更新元素
<!-- 动态渲染任意 HTML,这种行为非常的危险,不能把用户数据通过这种形式渲染 -->
<span v-html="msg">我是span中的内容,我会被覆盖</span>
6.5 v-if:条件渲染
<!-- v-for 比 v-if 优先级高一些,不推荐一起使用 -->
<!-- 当条件为真时,显示对应的元素 -->
<div v-if="type === 'A'">
  A
</div>
<div v-else-if="type === 'B'">
  B
</div>
<div v-else-if="type === 'C'">
  C
</div>
<div v-else>
  Not A/B/C
</div>
6.6 v-show:条件渲染
<!-- 
  v-show 与 v-if:
  v-if:是真正的条件渲染,会对 dom 进行创建和销毁,同时它也是懒惰的,如果最开始条件就为假时,就不会进行渲染
  v-show:无论条件是真或假,元素都会被渲染,只是简单的进行了 css 样式切换(display: none;)
-->
<h1 v-show="true">Hello!</h1>
6.7 v-for:列表渲染
<!-- 需要绑定 key 为唯一标识,设计到 diff 算法,如果 key 没有写,vue 默认会把 index 当做 key -->
<!-- v-for 的优先级要比 v-if 的优先级高一些,但是不推荐写在一起,会出现很多问题 -->

<!-- list 为数组时 -->
<ul>
    <!-- index 为索引,item 为值 -->
  <li v-for="(item, index) in list" :key="item.id">
      {{item.title}}
  </li>
</ul>

<!-- list 为对象时 -->
<div v-for="(val, key, index) in list"></div>

<!-- v-for 可以遍历数组、对象、集合、映射、字符串、指定次数 -->
6.8 v-model:双向绑定
<!-- 只能用于表单类,可输入元素,v-model 默认绑定的 value 值 -->
<!-- v-model:value ===> v-model,语法糖写法 -->
<input type="text" v-model:value="msg"> {{msg}}

<!--
  收集表单数据:
	<input type="text">,v-model 收集的是 value 值,用户输入的就是 value 值
    <input type="radio">,v-model 收集的是 value 值,需要给标签配置 value 值
	<input type="checkbox">
      1. 没有配置 input 的 value 属性,那么收集的就是 checkout (布尔值)
	  2. 配置 input 的 value 属性:
		(1) v-model 的初始值不是数组,那么收集的就是 checkout (布尔值)
		(2)	v-model 的初始值是数组,那么收集的就是 value 组成的数组
	
	v-model 修饰符
	  lazy:失去焦点在收集,和 change 事件一样,v-model 默认是通过 input 事件收集的
	  number:输入的字符串转为数字,因为 value 默认是字符串
	  trim:收集时自动过滤首尾空格
-->
6.9 v-cloak
<!-- 处理 vue 生命周期中,视图数据会出现双大括号的问题 -->
<!-- 需要 css 配合,在有双大括号的时候先隐藏,等到 vue 渲染完成后在展示 -->
<style>
  [v-cloak] {
    display: none;
  }
</style>

<div v-cloak>
  {{ message }}
</div>
6.10 v-once
<!--
  v-once 所在的节点在初次动态渲染后,就视为静态内容了
  以后的数据在怎么改变,该内容也不会更新,可以用于性能优化
-->
<!-- 这里 n 在怎么加,也没有用 -->
<button @click="n++" v-once>{{n}}</button>
6.11 v-pre
<!-- 不去解析 Vue 中的语法,视图写什么页面就渲染什么,可以加快编译 -->
<div v-pre>{{msg}}</div>
<!-- 浏览器直接显示 {{msg}} -->
6.12 v-slot:插槽
<!-- v-slot: ===> #,语法糖写法 -->
<!-- 插槽 -->

7. 自定义指令

7.1 函数式
<!-- html 内容 -->
<div id="app">
    <!-- v-big 可以把 n 放大10倍 -->
  <span v-big="n"></span> 
</div>
const vm = new Vue({
  el: "#app",
  data: {
    n: 1
  },
  directives: {
    // big(){}:代表创建了一个 v-big 的自定义指令
    // el:指令所绑定的真实 dom
    // binding:对应的配置数据,其中 value 属性就是指令所绑定的值
    big(el, binding){ 
      // big 函数的执行时机:
      // 1. 会在 v-big 指令与元素绑定成功时执行
      // 2. 当指令所在的模板被重新解析时也会执行
      el.innerText = binding.value * 10
	}
  }
})
7.2 对象式
<!-- html 内容 -->
<div id="app">  
  <h2 v-my-big="n"></h2>
</div>
const vm = new Vue({
  el: "#app",
  data: {
    n: 1
  },
  directives: {
    // 多个单词连接的自定义指令,不能使用小驼峰,需要用 - 相连
    "my-big": {
      // el:指令所绑定的真实 dom
      // binding:对应的配置数据,其中 value 属性就是指令所绑定的值
      // vnode:虚拟 dom
      // oldVnode:更新之前的虚拟 dom
      bind(el, binding, vnode) {
        console.log("只调用一次,指令第一次绑定到元素时调用");
      },
      inserted(el, binding, vnode) {
        console.log("插入父节点时调用,表示该元素已经在页面上了");
      },
      update(el, binding, vnode, oldVnode) {
        console.log("更新时调用,可能子组件还没有更新完");
      },
      componentUpdated(el, binding, vnode, oldVnode) {
        console.log("全部更新后调用,在 update 之后调用");
      },
      unbind(el, binding, vnode) {
        console.log("只调用一次,指令与元素解绑时调用");
      }
    }
  }
})
7.3 全局与局部语法
// 全局
Vue.directive(指令名, 配置对象) // 对象式
Vue.directive(指令名, 回调函数) // 函数式

// 局部
new Vue({
  directives:{(指令名, 配置对象)} // 对象式
})
new Vue({
  directives:{(指令名, 回调函数)} // 函数式
})

注意:

  • 多个单词组成的指令,无论是使用还是创建都需要用 - 相连
  • 自定义指令中所有函数的 this 都指向 window

8. 数据代理

// 在 vue 实例中,我们写在 data 中的数据可以直接通过 this 使用
// 这个是因为 Vue 使用了 Object.defineProperty() 的方法进行了数据代理
// 还有一点就是 data 在 vue 实例中变成了 _data

// 从下面这段代码就可以很明显的看出,vm._data 是等于 obj 的
// vue 把 data 中的数据直接添加到 vue 实例上了
// 无论是 _data 中的数据,还是添加到 vue 实例上的数据,有一个发生改变另一个也会变
let obj = {
  name: "张三",
  age: 18
}
const vm = new Vue({
  el: "#app",
  data: obj // 只有 data 中的数据才会做数据代理
})
console.log(vm._data === obj); // true

9. 数据检测的问题

9.1 对象
  • vue 在对一个对象进行修改和获取时,vue 是响应式的
  • 因为 vue 是借助 Object.defineProperty() 的方法对数据进行响应的,但是这个方法只有 get 和 set
  • 这个时候就会出现问题,对象中的数据进行添加或删除时,vue 无法检测
  • vue 中提供了一个全局的 set ( set 有添加或修改的意思,这里是指添加 ) 和 delete 两个方法,对数据进行添加或删除
  • 这里要区分一点,vue 中全局的方法是直接可以 Vue. 使用,在实例中是 this.$ 使用
// 全局,target ==> 数组/对象,target 不能为 vue 实例和 vue 实例中的 data
Vue.set( target, key/index, value )
Vue.delete( target, key/index )
9.2 数组
  • 在对应数组的修改时 vue 对这七个方法进行了重写,push()、pop()、shift()、unshift()、splice()、sort()、reverse()
  • 所以使用这七个方法对数组进行修改时,数据也是响应式的
  • 对于 ES6 新增的两个改变数组自身的方法,和手动通过下标修改的数据,都不是响应式的

10. 计算属性和侦听器

10.1 计算属性(computed)
const vm = new Vue({
  data: {
    firstName: "",
    lastName: "",
  },
  computed: {
    fullName: {
      get: function () {
        return this.firstName + " " + this.lastName;
      },
      set: function (newValue) {
        var names = newValue.split(" ");
        this.firstName = names[0];
        this.lastName = names[names.length - 1];
      },
    },
    gather2() {
      return "我是访问时的值,只有 get 时的简写";
    },
  },
});

// 现在再运行 vm.fullName =John Doe’时,setter 会被调用vm.firstName 和 vm.lastName也会相应地被更新。
  1. 计算属性底层也是借助了 Object.defineProperty() 的方法,使计算属性中的值也是响应式的
  2. get 函数在初次读取时会执行一次,当依赖的数据发生改变的时候会被再次调用(这个指上面的案例,firstName 或 lastName 发生改变时才会再次触发 get 方法,而不是指计算属性中的 set)
  3. 计算属性会进行缓存,当值未发生改变时,计算属性中的函数不会再次调用,只是使用了缓存的值
  4. 一般计算属性只是用于得到计算的结果,也就是默认只会用到 get 方法,很少会用到 set 方法,所以可以使用简写
  5. 计算属性最终会出现在 vm 上,可以直接读取
10.2 侦听器(watch)
// 实例中监测
const vm = new Vue({
  el: "#app",
  data: {
    msg: "hello Vue"
  },
  methods: {
    btn() {
      console.log(this.msg);
    }
  },
  watch: {
	msg: { // 被监测的值必须存在
      immediate: true, // 初始化时,就调用一次 handler
      deep: true, // 开始监视深层的数据,在 watch 中默认只监测一层数据的变化
      handler(newValue, oldValue) { // 当 msg 值发生改变时会执行 handler 函数
        console.log("msg 发生改变了,oldValue 为改变前的值,newValue 为改变后的值")
      }
	},
    msg(newValue, oldValue) { // 只有函数不需要配置项时可以简写
      console.log("我是简写形式")
    }
  }
})

// 实例监测,两种效果是一样的,对象式
let unwatch = vm.$watch("msg", {
  immediate: true,
  deep: true,
  handler(newValue, oldValue){
    console.log("msg 发生改变了,oldValue 为改变前的值,newValue 为改变后的值")
  }
})
// 函数式
let unwatch = vm.$watch("msg", function (newValue, oldValue){
  console.log("msg 发生改变了,oldValue 为改变前的值,newValue 为改变后的值")
})

// 取消观察,在全局使用时,会返回一个取消观察的函数
unwatch()

侦听器每次发生变化时就会触发,用于监听数据的变化

10.3 computed与watch之间的区别
  1. computed 能完成的功能,watch 都可以完成
  2. watch 能完成的功能,computed 不一定能完成,例如 watch 可以进行异步操作
  3. computed 主要进行计算的汇总,watch 主要用于观察数据,根据数据的变化来处理对应的程序
  4. computed 会进行缓存,watch 不会
  5. computed 会计算出一个新的值,watch 对已有的值进行监测

11. 过滤器

<!-- html 内容 -->
<div id="app">
  <span>{{msg | filter1 | filter1(123)}}</span>
</div>
// 全局注册
Vue.filter("filter0", (val) => {
  return "我是全局的过滤器"
})

// 局部注册
const vm = new Vue({
  el: "#app",
  data: {
    msg: "hello Vue"
  },
  filters: {
    // 这个 val 默认为过滤器前的值,msg
    filter1(val) {
      return "我被过滤了" + val
	},
    // num 是传入的123
    filter2(val, num) {
      return val + num
    }
  }
})
  1. 过滤器的定义:对要显示的数据进行特定格式化后在显示,比较适用于一些简单的逻辑的处理
  2. 注册过滤器有两种方式,全局的在任何位置都可以使用,局部的只能用于当前组件或实例
  3. 默认过滤器的第一个参数是过滤器前面的值,第二个参数是使用过滤器传入的值,依次类推
  4. 过滤器可以连续使用
  5. 过滤器并不会改变原数据,只是返回新的数据
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值