文章

01.Vue2.x入门

01.Vue2.x入门

Vue.js 入门

什么是 Vue.js?

Vue 是一个渐进式的 JS 框架

vue 的特点

  1. 轻量级的框架

Vue.js 能够自动追踪依赖的模板表达式和计算属性,提供 MVVM 数据绑定和一个可组合的组件系统,具有简单、灵活的 API,使读者更加容易理解,能够更快上手。

  1. 双向数据绑定

声明式渲染是数据双向绑定的主要体现,同样也是 Vue.js 的核心,它允许采用简洁的模板语法将数据声明式渲染整合进 DOM。

  1. 指令

Vue.js 与页面进行交互,主要就是通过内置指令来完成的,指令的作用是当其表达式的值改变时相应地将某些行为应用到 DOM 上。

  1. 组件化

组件(Component)是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。在 Vue 中,父子组件通过 props 传递通信,从父向子单向传递。子组件与父组件通信,通过触发事件通知父组件改变数据。这样就形成了一个基本的父子通信模式。

在开发中组件和 HTML、JavaScript 等有非常紧密的关系时,可以根据实际的需要自定义组件,使开发变得更加便利,可大量减少代码编写量。

组件还支持热重载(hotreload)。当我们做了修改时,不会刷新页面,只是对组件本身进行立刻重载,不会影响整个应用当前的状态。CSS 也支持热重载。

  1. 路由

Vue-router 是 Vue.js 官方的路由插件,与 Vue.js 深度集成,用于构建单页面应用。Vue 单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来,传统的页面是通过超链接实现页面的切换和跳转的。

  1. 状态管理

状态管理实际就是一个单向的数据流,State 驱动 View 的渲染,而用户对 View 进行操作产生 Action,使 State 产生变化,从而使 View 重新渲染,形成一个单独的组件。

Vue.js 安装

  • 官网

https://v2.vuejs.org/js/vue.min.js

  • CDN

以下推荐国外比较稳定的两个 CDN,国内还没发现哪一家比较好,目前还是建议下载到本地。

先安装 Node.js 和 npm:

1
2
3
4
# 全局安装 vue-cli
cnpm install --global vue-cli
# 创建一个基于 webpack 模板的新项目
vue init webpack my-project
  • NPM 方法
1
cnpm install vue

Vue.js 版本

  • 2.X 学习用这个版本
  • 3.X

Vue 目录结构

目录/文件说明
build项目构建 (webpack) 相关代码
config配置目录,包括端口号等。我们初学可以使用默认的。
node_modulesnpm 加载的项目依赖模块
src这里是我们要开发的目录,基本上要做的事情都在这个目录里。里面包含了几个目录及文件:
- assets: 放置一些图片,如 logo 等。
- components: 目录里面放了一个组件文件,可以不用。
- App.vue: 项目入口文件,我们也可以直接将组件写这里,而不使用 components 目录。
- main.js: 项目的核心文件。
static静态资源目录,如图片、字体等。
test初始测试目录,可删除
.xxxx 文件这些是一些配置文件,包括语法配置,git 配置等。
index.html首页入口文件,你可以添加一些 meta 信息或统计代码啥的。
package.json项目配置文件。
README.md项目的说明文档,markdown 格式

Vue 配置

  • Vue.config.productionTip = false; 阻止 vue 启动时生成生产提示。

Vue 生命周期

每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。

Vue 生命周期分析

初始化 beforeCreate/created/beforeMount/mounted

  • beforeCreate()
  • created() 能获取到 data 数据了
  • beforeMount()
  • mounted()
    • 常用发送 ajax 请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】

更新状态:beforeUpdate/updated

this.xxx = value

  • beforeUpdate()
  • updated()

销毁 vue 实例: beforeDestory/destroyed

vm.$destroy()

  • beforeDestory()
    • 清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】
  • destroyed()

activated 和 deactivated

  1. 作用:activateddeactivated 是 Vue.js 中的两个生命周期钩子函数,它们在 <keep-alive> 组件中使用,用于控制被缓存的组件的激活和停用。
  2. 功能分别是:
    1. activated: 被缓存的组件激活时调用,可以在这里执行一些需要在组件被重新渲染前进行的操作,比如获取最新数据、更新状态等。(激活钩子)
    2. deactivated: 被缓存的组件停用时调用,可以在这里执行一些需要在组件被缓存前进行的操作,比如保存当前状态、清空数据等。(失活钩子)

具体来说,当一个被缓存的组件被切换到时,会触发 activated 钩子函数;当一个被缓存的组件离开时,会触发 deactivated 钩子函数。

使用场景:<keep-alive> 组件通常用于缓存页面中经常切换的组件,以提高页面的响应速度和用户体验。但是有些情况下,缓存的组件可能需要在每次被重新渲染前或者被缓存前执行一些特定的操作,例如:

  • 在页面切换到某个组件时,需要从服务器获取最新的数据。
  • 当一个组件被缓存时,需要保存当前选中的状态,以便下次缓存时可以恢复。
  • 当一个组件被停用时,需要将一些数据清空或重置。

在这些情况下,就可以使用 activateddeactivated 钩子函数来实现这些操作。

nextTick

在 Vue.js 中,DOM 更新是异步执行的。当我们修改页面的数据时,Vue.js 会将这些修改操作放入一个队列中,等到下一个事件循环时再执行这些操作,这个过程就叫做 DOM 更新。在 Vue.js 中,nextTick 方法可以让我们在 DOM 更新之后执行一些操作。这些操作可能是获取更新后的 DOM 元素的属性或者在更新后对 DOM 进行一些操作。
nextTick 方法是 Vue.js 实例的一个方法,它接收一个回调函数作为参数。当 DOM 更新完成之后,Vue.js 会调用这个回调函数。这个回调函数会在当前事件循环的末尾执行,这意味着在这个回调函数中获取到的 DOM 元素的属性一定是更新后的最新值。
简单来说:就是等到下一次 DOM 更新。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
new Vue({
  el: '#app',
  data: {
    message: 'Hello, Vue.js!'
  },
  methods: {
    updateMessage: function () {
      this.message = 'Hello, World!'
      this.$nextTick(function () {
        // DOM 更新完成后执行的代码
        var messageDiv = document.getElementById('message')
        console.log(messageDiv.innerText)
      })
    }
  }
})

Vue 实例生命周期图

image.png

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>分析生命周期</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root" :x="n">
			<h2 v-text="n"></h2>
			<h2>当前的n值是:</h2>
			<button @click="add">点我n+1</button>
			<button @click="bye">点我销毁vm</button>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

		new Vue({
			el:'#root',
			// template:`
			// 	<div>
			// 		<h2>当前的n值是</h2>
			// 		<button @click="add">点我n+1</button>
			// 	</div>
			// `,
			data:{
				n:1
			},
			methods: {
				add(){
					console.log('add')
					this.n++
				},
				bye(){
					console.log('bye')
					this.$destroy()
				}
			},
			watch:{
				n(){
					console.log('n变了')
				}
			},
			beforeCreate() {
				console.log('beforeCreate')
			},
			created() {
				console.log('created')
			},
			beforeMount() {
				console.log('beforeMount')
			},
			mounted() {
				console.log('mounted')
			},
			beforeUpdate() {
				console.log('beforeUpdate')
			},
			updated() {
				console.log('updated')
			},
			beforeDestroy() {
				console.log('beforeDestroy')
			},
			destroyed() {
				console.log('destroyed')
			},
		})
	</script>
</html>

Vue 技巧

vue 相关插件

Vetur

可识别 .vue 文件

Vue VSCode Snippets/ Vue VSCode Snippets

Snippets that will supercharge your Vue workflow

VsCode Vue 快捷键生成代码模板 (Vue2、Vue3)

  1. 在 VScode 插件库搜索插件 VeturVueHelper, 然后安装

注意:安装好插件后,要重新启动 VScode

  1. 文件——首选项——用户片段 搜索 vue.json(vue)

  1. 然后在打开的 vue.json 中加入你的模板代码片段
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
// {
	// Place your snippets for vue here. Each snippet is defined under a snippet name and has a prefix, body and 
	// description. The prefix is what is used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
	// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. Placeholders with the 
	// same ids are connected.
	// Example:
	// "Print to console": {
	// 	"prefix": "log",
	// 	"body": [
	// 		"console.log('$1');",
	// 		"$2"
	// 	],
	// 	"description": "Log output to console"
	// }
// }
{
	"Print to v2": {
	  "prefix": "vue2",
	  "body": [
		"<template>",
		"    <div>\n",
		"    </div>",
		"</template>",
		""
		"<script>",
		"export default {",
		"    data() {",
		"        return {\n",
		"        }",
		"    },",
		"    mounted() {\n",
		"    },",
		"    computed: {\n",
		"    },",
		"    methods: {\n",
		"    },",
		"}",
		"</script>",
		""
		"<style scoped>\n",
		"</style>",
		"$2"
	  ],
	  "description": "Log output to console"
	},
	"Print to v3": {
	  "prefix": "vue3",
	  "body": [
		"<template>",
		"    <div></div>",
		"</template>",
		"<script>",
		"export default {",
		"  components: {\n",
		"  },",
		"  props: {\n",
		"  },",
		"  setup(props, context) {\n",
		"  }",
		"}",
		"</script>",
		"<style scoped>\n",
		"</style>",
	  ],
	  "description": "Log output to console"
	},
	"Print to setup": {
	  "prefix": "setup",
	  "body": [
		"<template>",
		"  <div></div>",
		"</template>",
		"<script setup>\n",
		"</script>",
		"<style scoped>\n",
		"</style>",
	  ],
	  "description": "Log output to console"
	}
}
  1. 然后在空的 .vue 文件,输入 vue2vue3 关键字就能生成代码片段

Vue 遇到的问题

vue 更新值

数组更新操作

问题:this.list[1] = 'jerry' ,但遗憾的是页面并不会更新;这种方法确实改变了 list[1] 的值,但没法触发页面更新。

那么在 Vue 中,如何更新数组某一项呢?下面是总结的一些方法:

数组原生方法

Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。这些被包裹过的方法包括:

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

splice()

Array.prototype.splice 被称为数组最强大的方法,具有删除增加替换功能,可以用 splice 来更新。

splice 不再是数组原生方法了,而是 Vue 重写过的方法

为什么 splice 可以触发更新?

通过删除现有元素和/或添加新元素来修改数组。

1
2
let fruits = ['apple', 'banana', 'mango', 'orange'];
fruits.splice(2, 1, 'lemon', 'kiwi'); // fruits = ['apple', 'banana', 'lemon', 'kiwi', 'orange']

push()

将一个或多个元素追加到数组的尾部,并返回新的数组长度。

1
2
let fruits = ['apple', 'banana'];
fruits.push('orange'); // 返回 3, fruits = ['apple', 'banana', 'orange']

pop()

移除数组的最后一个元素,并返回该元素。

1
2
let fruits = ['apple', 'banana', 'orange'];
let last = fruits.pop(); // 返回 'orange', fruits = ['apple', 'banana']

shift()

移除数组的第一个元素,并返回该元素,其他元素索引减一。

1
2
let fruits = ['apple', 'banana'];
let first = fruits.shift(); // 返回 'apple', fruits = ['banana']

unshift()

将一个或多个元素添加到数组的开头,并返回新的数组长度。

1
2
let fruits = ['banana'];
fruits.unshift('apple'); // 返回 2, fruits = ['apple', 'banana']

sort()

根据比较函数排序数组元素,并返回数组。修改原数组

1
2
let numbers = [1, 3, 2];
numbers.sort((a, b) => a - b); // 返回 [1, 2, 3]

reverse()

颠倒数组中元素的顺序,并返回数组。修改原数组

1
2
let numbers = [1, 2, 3];
numbers.reverse(); // 返回 [3, 2, 1]

重塑数组

变异方法 (mutation method),顾名思义,会改变被这些方法调用的原始数组。相比之下,也有非变异 (non-mutating method) 方法,例如: filter(), concat()slice() 。这些不会改变原始数组,但总是返回一个新数组。当使用非变异方法时,可以用新数组替换旧数组:

1
2
3
example1.items = example1.items.filter(function (item) {
  return item.message.match(/Foo/)
})

你可能认为这将导致 Vue 丢弃现有 DOM 并重新渲染整个列表。幸运的是,事实并非如此。 Vue 实现了一些智能启发式方法来最大化 DOM 元素重用,所以用一个含有相同元素的数组去替换原来的数组是非常高效的操作。

filter() 数组元素过滤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<ul id="example-1">
 <li v-for="n in even()"></li>
</ul>
<script type="text/javascript">
var example1 = new Vue({
 el: '#example-1',
 data: {
  numbers: [ 1, 2, 3, 4, 5 ]
 },
 methods : {
  even : function(){
   return this.numbers.filter(function (number) {
         return number % 2 === 0;
      });
  }
 }
});
</script>

Vue 官方 API Vue.set()

Vue.set 是官方提供的全局 API,别名 vm.$set,用来主动触发响应:

1
2
3
Vue.set(this.list, 1, 'jerry')
// 或者
this.$set(this.list, 1, 'jerry')

其实 set 方法本质上还是调用的 splice 方法来触发响应,部分源码

1
2
3
4
5
6
7
8
9
function set (target: Array<any> | Object, key: any, val: any): any {
  // ...
  if (Array.isArray(target) && isValidArrayIndex(key)) {
    target.length = Math.max(target.length, key)
    target.splice(key, 1, val)
    return val
  }
  // ...
}

当 set 的第一个参数为数组时,直接调用 target.splice()

Vm.$forceUpdate()

强制使 Vue 实例重新渲染,其实 this.list[1] = 'jerry' 操作,list 确实已经更改了,我们调用 vm.$forceUpdate() 可以强制渲染

1
2
this.list[1] = 'jerry'
this.$forceUpdate()

通常你应该避免使用这个方法,而是通过数据驱动的正常方法来操作

当你无路可走的时候,可以试试这个方法,但此方法不可滥用,想想你只是想更改某个数组项,但是却可能更新了整个组件

其他

Error: You appear to be using a native ECMAScript module configuration file, which is only supported when running Babel asynchronously

image.png

  1. 先查看我的配置文件 package.js 在文件前面加上 "type":"module"
  2. 然后我们需要把 babel.config 配置文件的后缀名改为 .cjs
  3. 然后运行问题解决:npm run serve
本文由作者按照 CC BY 4.0 进行授权