0
点赞
收藏
分享

微信扫一扫

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

米小格儿 2022-04-15 阅读 54
vuevue.js

文章目录

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:{(指令名, 回调函数)} // 函数式
})

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({
  el: "#app",
  data: {
    msg: "hello Vue"
  },
  methods: {
    btn() {
      console.log(this.msg);
    }
  },
  computed: {
	gather1: {
      get(){
        return `${a + b}:我是访问时的值`
	  },
      set(val){
        this.xxx = val
	  }
	},
    gather2(){
      return "我是访问时的值,只有 get 时的简写"
    }
  }
})

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("我是简写形式")
    }
  }
})

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

10.3 computed与watch之间的区别

  1. computed 能完成的功能,watch 都可以完成
  2. watch 能完成的功能,computed 不一定能完成,例如 watch 可以进行异步操作
  3. computed 主要进行计算的汇总,watch 主要用于观察数据,根据数据的变化来处理对应的程序
  4. 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
    }
  }
})
举报

相关推荐

0 条评论