目录
Vue简介
Vue 是一套用来动态构建用户界面的渐进式 JavaScript 框架
- 构建用户界面:把数据通过某种办法变成用户界面
- 渐进式:Vue 可以自底向上逐层的应用,简单应用只需要一个轻量小巧的核心库,复杂应用可以引入各式各样的 Vue 插件
Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架(部分使用,不是全家桶)。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。vue是一款简单的mvvm(model-view-viewmodel)框架。
它的中心思想就是数据驱动,不像jQuery是结构驱动,
结构驱动:先获取HTML的结构,然后再修改数据更新结构
数据驱动:简单的理解就是直接将数据同步到结构上,视图管理抽象为数据管理,而不是管理dom结构
Vue.js 不支持 IE8 及其以下版本,因为 Vue.js 使用了 IE8 不能模拟的 ECMAScript 5 特性。Vue.js 支持所有兼容 ECMAScript 5 的浏览器。
MVVM模式
1:什么是MVVM模式?
Model-View-ViewModel的简写。即模型-视图-视图模型
M 指的是后端传递的数据
V 指的是所看到的页面。
VM MVVM模式的核心,它是连接view和model的桥梁
★它有两个作用:将后端传递的数据转化成所看到的页面。实现的方式是:数据绑定。
将所看到的页面转化成后端的数据。实现的方式是:DOM 事件监听。
如果这两个方向都实现的,我们称之为数据的双向绑定。
2:为什么会有MVVM框架?
HTML5 最大的亮点是它为移动设备提供了一些非常有用的功能,使得 HTML5 具备了开发App的能力, HTML5开发App 最大的好处就是跨平台、快速迭代和上线,节省人力成本和提高效率,因此很多企业开始对传统的App进行改造,逐渐用H5代替原生App开发,到目前为止,市场上大多数App 或多或少嵌入都了H5 的页面。
既然要用H5 来构建 App, 那View 层所做的事,就不仅仅是简单的数据展示了,它不仅要管理复杂的数据状态,还要处理移动设备上各种操作行为等等。因此,前端就需要工程化,也需要一个类似于Web端MVC 的框架来管理这些复杂的逻辑,使开发更加高效。
在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。 ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。
3:Vue为什么称之渐进式框架?什么是渐进式?
如果你已经有一个现成的服务端应用,你可以将vue 作为该应用的一部分嵌入其中,带来更加丰富的交互体验;
如果你希望将更多业务逻辑放到前端来实现,那么Vue的核心库及其生态系统也可以满足你的各式需求(core+vuex+vue-route)。和其它前端框架一样,Vue允许你将一个网页分割成可复用的组件,每个组件都包含属于自己的HTML、CSS、JAVASCRIPT以用来渲染网页中相应的地方。
如果我们构建一个大型的应用,在这一点上,我们可能需要将东西分割成为各自的组件和文件,vue有一个命令行工具,使快速初始化一个真实的工程变得非常简单(vue init webpack my-project)。我们可以使用VUE的单文件组件,它包含了各自的HTML、JAVASCRIPT以及带作用域的CSS或SCSS。以上这三个例子,是一步步递进的,也就是说对VUE的使用可大可小,它都会有相应的方式来整合到你的项目中。所以说它是一个渐进式的框架。
4:结构示意图☺
Vue.js的简单介绍
1:什么是Vue.js?
Vue.js是一套基于前后端分离模式、用于构建用户界面的渐进式框架,他只关注视图层的逻辑、采用自底向上、增量式开发的设计。
2:Vue的基本使用,创建Vue实例
Vscode构建Vue环境(编码有提示):下载扩展插件--1、Vetur 2、Vue 3 Snippets
3:怎么引入Vue.js文件?
代码演示【这里以压缩过的js文件为例】:
<script src="../js/vue.min.js"></script>
下载链接:https://pan.baidu.com/s/14nxqE0H7Yt2x1PwkhFRIsw?pwd=lgqy
提取码:lgqy
还可以CDN形式引入Vue.js文件:
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
Vue中常见指令和操作
1:el--Vue接管区
①直接在HTML中:如果你在HTML中直接编写Vue代码,而不是使用单文件组件(.vue
文件),你可以在Vue实例的JavaScript代码中指定 el
。
这里 '#app'
是一个CSS选择器,用于选择页面上id为app
的DOM元素。
new Vue({
el: '#app'
});
②结合 template
选项:如果你使用 template
选项定义了组件的HTML结构,那么 el
选项将不再适用,因为模板内容将由Vue接管并动态渲染。
2:data指令
data是Vue实例的数据对象,Vue.js会将data对象的属性转换为getter/setter,从而让data的属性能够响应数据变化。
const app= new Vue({data: {数据}}),Vue通过这种方式监听了data内的数据修改,因此,只要data内的数据进行变动,视图层就会同步自动刷新。data定义的数据通过插值语法(“{{}}”)绑定到DOM节点,data数据对象有以下两种写法:
①对象(Object)的形式:
<div id="app">{{content}}</div>
<script>
var app = new Vue({
el: "#app",
data: {
content: "通过data对象获取content的值"
}
})
</script>
②函数(Function)的形式:
<div id="app">{{content}}</div>
<script>
var app = new Vue({
el: "#app",
// 这是下面function的简写形式
data(){
return {
name:'张三',
age:18
}
},
// 另一种写法
// data:function() {
// return {
// name: '张三',
// age: 18,
// sex: '男'
// }
// },
})
</script>
3:methods--定义方法
概述:methods用来定义Vue实例中的方法,可以通过Vue实例直接访问这些方法。在定义的方法中,this对象指向Vue实例本身。通过methods定义的方法还可以作为页面中的事件处理方法使用,一旦事件被触发,即执行相应的方法进行处理。
注意:在methods方法中访问 data 的数据,可以直接通过 this.属性名的形式来访问,this表示Vue实例,若在箭头函数中,this表示的是window。
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
//1、第一步 引入vue.js
<script src="../js/vue.js"></script>
</head>
<body>
// 2、第二步
<div id="app">
<div>
{{msg}}
<p>tip:点击按钮把“旧文本”字样修改为“新文本”</p>
<!-- v-on 可以简写为 @ -->
<button v-on:click="btnClick">点击</button>
<!-- 简写形式 -->
<!-- <button @click="btnClick">点击</button> -->
</div>
</div>
<script>
// 3、第三步
var app = new Vue({
el: "#app",
data: {
msg: "旧文本"
},
// 页面的点击事件都需要放到 methods 里面
methods:{
btnClick(){
this.msg="新文本"
}
}
})
</script>
</body>
</html>
总结:
methods 中定义的方法属于被 Vue 实例所管理的方法:
- 如果使用箭头函数,this 表示 window
- 如果使用普通函数,this 表示 Vue 实例或者组件实例对象
4:v-text指令
v-text用来在DOM元素内部插入文本内容,该指令以文本的方式更新元素的内容,即使是HTML代码,它也只当做普通字符串处理,不会解析标签,与插值表达式作用相同。
<div id="app">
<p>{{msg}}</p>
<p v-text="msg"></p>
</div>
<script>
const vm = new Vue({
el: "#app",
data: {
msg: "666"
}
});
</script>
5:v-html指令
v-html指令更新节点元素的 innerHTML ,内容按照HTML格式进行解析,并且显示对应的内容。
<div id="app">
<p>{{msg}}</p>
<p v-html="msg"></p>
</div>
<script>
var vm = new Vue({
el: "#app",
data: {
msg: <h1>"666"</h1>
}
});
</script>
6:v-bind指令
v-bind动态地绑定一个或多个属性,或一个组件 prop 到表达式。简写形式:v-bind=>:
<div id="app">
<input v-bind:value="msg">
</div>
<script>
const app = new Vue({
el: "#app",
data: {
msg: "Hello,v-bind!"
}
});
</script>
★例如:常见的绑定类的几种情况☺
①绑定单个动态类名时:
②绑定多个动态类名时:
③同时绑定静态+动态类名时:
④在v-bind指令中使用逻辑判断时:
7:v-on事件指令
v-on指令用来绑定事件监听器。在普通元素上,v-on指令可以监听原生的DOM事件(如click、dblclick、keyup、mouseover等)。
<button v-on:click="counter += 1">增加</button>
简写形式:v-bind=>@
<button @click="counter += 1">增加</button>
$event
如果想要事件发生时既要传递实参又要在函数中使用事件对象,那么就必须在调用函数时使用 $event
来表示传递的是事件对象,如下代码所示:
<div id="root">
<h2>欢迎来到{{name}}学习</h2>
<!-- $event表示这个参数是事件对象而不是自定义的实参 -->
<button @click="showInfo1($event, 22)">点我提示信息1</button>
</div>
</body>
<script type="text/javascript">
const vm = new Vue({
el:'#root',
data:{
name:'霍格沃茨',
},
methods: {
showInfo1(event, number) {
// event表示事件对象,number表示接收的实参
console.log(event.target)
console.log('参数数字是' + number)
},
}
})
</script>
六种事件修饰符
- prevent:阻止事件的默认行为
- stop:阻止事件冒泡(使用在内部标签上)
- 事件冒泡:内部标签的事件触发时,外层标签如果有相同的事件,那么这个外部标签的事件会被自动触发
- once:事件只触发一次
- self:只关心自己标签上触发的事件,不监听事件冒泡
- capture:使用事件的捕获模式
- passive:事件的默认行为立即执行,无需等待事件回调执行完毕
①prevent代码演示:
作用:点击之后只弹出提示信息,没有跳转到百度页面。
<body>
<div id="root">
<h2>欢迎来到{{name}}学习</h2>
<!-- a标签的默认行为是跳转到指定的页面,prevent阻止跳转,只执行函数 -->
<a href="http://www.baidu.com" @click.prevent="showInfo">点我提示信息</a>
</div>
</body>
<script type="text/javascript">
new Vue({
el:'#root',
data:{
name:'霍格沃茨'
},
methods:{
showInfo(){
alert('同学你好!')
}
}
})
</script>
②stop代码演示:
作用:只弹出一次提示信息,如果不阻止事件冒泡,则会弹出两次提示信息。
<body>
<div id="root">
<h2>欢迎来到{{name}}学习</h2>
<!-- div标签是外层标签,拥有与内层标签一致的点击事件 -->
<div @click = "showInfo">
<!-- 默认点击按钮之后,内部标签的事件触发,外部标签的事件也会随之触发(事件冒泡) -->
<!-- 使用stop阻止了事件冒泡,不会触发外层标签的同一事件 -->
<button @click.stop = "showInfo"> 按钮 </button>
</div>
</div>
</body>
<script type="text/javascript">
new Vue({
el:'#root',
data:{
name:'霍格沃茨'
},
methods:{
showInfo(){
alert('同学你好!')
}
}
})
</script>
③once代码演示:
<!-- 事件只会执行一次,之后再点击也不会触发事件了 -->
<button @click.once="showInfo"> 按钮 </button>
④self代码演示:
<!-- div标签是外层标签,拥有与内层标签一致的点击事件 -->
<!-- 使用了self事件,只有点击了外部事件才会触发,不监听事件冒泡 -->
<div @click.self = "showInfo">
<button @click= "showInfo"> 按钮 </button>
</div>
注意:事件修饰符可以连续写,比如:@click.prevent.stop = "method"
表示既阻止事件的默认行为又阻止事件冒泡的发生。
按键修饰符的运用
- 使用方式:@事件名.按键修饰符名称 = "要执行的方法"
- 作用:用来和按键事件绑定在一起,修饰特定按键事件
- click:点击事件
- keyup:按键抬起事件
- keydown:按键按下事件
常用的按键修饰符有9个
- enter:回车
- delete:删除或退格
- esc:退出
- space:空格
- tab:换行(键盘按下就会失去焦点,所以必须配合 keydown 使用)
- up:上
- down:下
- left:左
- right:右
代码演示:
<body>
<div id="root">
<!-- 只有按下并抬起回车键后才会执行对应的方法 -->
<input type="text" placeholder="请按下对应的按键" @keyup.enter="showInfo"></input>
</div>
</body>
<script type="text/javascript">
new Vue({
el:'#root',
methods:{
showInfo(event){
alert(event.target.value)
}
}
})
</script>
获取按键名
<script type="text/javascript">
new Vue({
methods:{
// event是事件对象
showInfo(event){
//获取按键名
console.log(event.key)
//获取按键编码
console.log(event.keyCode)
}
}
})
</script>
8:v-for遍历指令
v-for是Vue.js的循环语句,当需要遍历数组或对象时,常用的就是列表渲染指令v-for, 它需要结合着in或者of来使用。
①for循环普通数组
<div id="app">
<ul>
<li v-for="(item,index)of fruit" key="index">
索引值index:{{index]}-每-项item:{{item]
</li>
</ul>
</div>
<script>
new Vue({
el: "#app",//绑定了app这个元素
data: {
fruit: ["苹果","梨子","香蕉","橘子"]
}
});
</script>
②for循环对象数组
<div id="app">
<ul>
<li v-for="(item, index) in fruits" :key="index">
索引值 index: {{ index }} --
每-项 name: {{ item.name }} --
每-项 color: {{ item.color }}
</li>
</ul>
</div>
<script>
new Vue({
el: "#app", // 绑定了 #app 这个元素
data: {
fruits: [
{ name: "苹果", color: "红色" },
{ name: "梨子", color: "黄色" },
{ name: "橘子", color: "橘色" },
{ name: "西瓜", color: "绿色" }
]
}
});
</script>
③for循环对象
<div id="app">
<ul>
<li v-for="(value, key, index) in apple" :key="index">
属性索引:{{ index }}--属性名:{{ key }}--属性值:{{ value }}
</li>
</ul>
</div>
<script>
new Vue({
el: "#app",
data: {
apple: {
name: "苹果",
color: "红色"
}
}
});
</script>
④for循环整数
假设我们想循环从 1 到 10 的整数㉿
<div id="app">
<ul>
<li v-for="number in numbers" :key="number">
{{ number }}
</li>
</ul>
</div>
<script>
new Vue({
el: '#app',
data: {
numbers: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] // 一个包含整数的数组
}
});
</script>
在这个例子中,numbers
是一个包含从 1 到 10 的整数数组。我们使用 v-for="number in numbers"
来迭代这个数组,并且为每个整数创建一个列表项 <li>
。
如果你需要动态生成一个整数序列,而不是使用硬编码的数组,你可以在 Vue 实例的 computed
属性中定义一个计算属性。
例如:
computed: {
numbers() {
const start = 1;
const end = 10;
return Array.from({ length: end }, (v, k) => k + start);
}
}
这里 Array.from()
接收两个参数:
-
第一个参数是一个对象,它具有一个
length
属性,该属性的值是end
。这意味着Array.from()
将创建一个长度为end
的新数组。 -
第二个参数是一个映射函数,它接收两个参数:
v
(当前遍历的值,虽然在这里未使用)和k
(当前项的索引)。映射函数返回k + start
,这将为数组中的每个位置生成一个从start
开始的连续整数。
9:v-model双向绑定
v-model指令主要用于实现表单元素和数据的双向绑定,通常用在表单类元素上(如input、select、textarea等)。所谓双向绑定,指的就是Vue实例中的data与其渲染的DOM元素上的内容保持一致,两者无论谁被改变,另一方也会相应的同步更新为相同的数据。
v-model修饰符:
1:.lazy: 代替 input
监听 change
事件,可以在输入框失去焦点时进行输入的更新。
<input v-model.lazy="msg" />
2:.number: 输入字符串转为有效的数字,如果无效则返回原值。
<input v-model.number="age" type="number" />
3:.trim: 输入时自动过滤掉首尾的空格。
<input v-model.trim="msg" />
10:v-if、v-else-if、v-else条件判断
v-if
、v-else-if
和v-else
是Vue.js中的指令,用于根据表达式的值条件性地渲染一块内容。
示例:
假设我们有一个表示分数的数字 score
,我们想根据分数显示不同的评价:
<div id="app">
<p v-if="score >= 90">优秀,继续保持!</p>
<p v-else-if="score >= 70">不错,但还有提升空间。</p>
<p v-else-if="score >= 50">加油,努力学习!</p>
<p v-else>需要更多努力,不要放弃!</p>
</div>
<script>
new Vue({
el: '#app',
data: {
score: 75
}
});
</script>
可以使用上述方式得到所有按键的按键名,故可以使用的按键修饰符不仅仅是默认的9个。
注意:如果想要使用非默认的9个按键修饰符,使用时必须将对应的按键名进行转换,比如:CapsLock 转换成 caps-lock
。
计算属性Computed
基本概念:
如果一个属性要通过已有的属性计算出来,那么可以使用计算属性。计算属性的读取和修改必须通过定义 getter/setter 来进行。
注:计算属性的底层借助了 Objcet.defineproperty 方法提供的 getter 和 setter 来完成读取和修改
计算属性具有以下特点:
-
缓存:计算属性具有缓存特性,只有当计算属性依赖的数据发生变化时,计算属性才会重新计算并更新其值。如果依赖数据没有变化,计算属性会返回上一次的计算结果。
-
可配置:计算属性可以配置
get
方法和set
方法,允许你在读取和修改计算属性时执行自定义逻辑。
代码示例:
<body>
<div id="root">
姓:<input type="text" v-model="firstName"> <br/><br/>
名:<input type="text" v-model="lastName"> <br/><br/>
<!-- 调用两次计算属性 -->
全名:<span>{{fullName}}</span> <br/><br/>
全名:<span>{{fullName}}</span>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false
const vm = new Vue({
el:'#root',
data:{
firstName:'张',
lastName:'三',
},
methods: {
},
// 定义计算属性必须使用computed对象
computed:{
// 一个新的属性fullName,需要通过已有的属性计算出来
fullName:{
// 读取计算属性的值
get(){
console.log('计算属性被调用了')
// this表示Vue实例,读取data中的属性
// 计算属性fullName依赖已有的属性
return this.firstName + '-' + this.lastName
},
// 修改计算属性的值
set(value){
console.log('set',value)
const arr = value.split('-')
// 修改data中的属性(依赖的已有属性)
this.firstName = arr[0]
this.lastName = arr[1]
}
}
}
})
</script>
演示效果:
可以直接在Scope->Local中读取计算属性,计算属性会直接放在Vue实例中,值是get方法的return值。
Object.defineProperty方法
先看一段 JS 代码,将一个变量的值赋值给一个属性:
let number = 18
let person = {
name:'张三',
sex:'男',
age:number //age值为18
}
如果通过这种方式给 age 赋值,只有第一次代码执行到赋值语句时才会将 age 的值修改为 18,如果以后 number 的值发生变化,则 age 不会跟着变化。
方法介绍:
Object.defineProperty()
是 JavaScript 中的一个方法,它用于定义对象的属性,或者修改对象的现有属性。这个方法接受三个参数:
- 对象(Object):要在其上定义或修改属性的对象。
- 属性名(String):要定义或修改的属性的名称(字符串形式)。
- 属性描述符(Object):提供一个描述如何访问属性的对象,这个对象可以包含以下属性:
- value: 属性的值。
- writable: 属性是否可写。
- get: 属性的 getter 函数。
- set: 属性的 setter 函数。
- configurable: 属性是否可配置(是否可以删除或修改)。
- enumerable: 属性是否可枚举。
此方法用于给对象定义属性使用,参数1表示给哪个对象定义属性,参数2表示给对象中的哪个属性赋值,参数3写赋予值的配置对象(对属性值进行一些高级的操作),如下所示:
<script type="text/javascript" >
let person = {
name:'张三',
sex:'男',
}
Object.defineProperty(person,'age',{
value:18, //这个属性值为18
enumerable:true, //控制属性是否可以枚举(被遍历),默认值是false
writable:true, //控制属性是否可以被修改,默认值是false
configurable:true //控制属性是否可以被删除,默认值是false
})
</script>
get()、set()方法:
<script type="text/javascript" >
let number = 12
let person = {
name:'张三',
sex:'男',
}
Object.defineProperty(person,'age',{
//当有人读取person的age属性时,get函数(getter)就会被调用,且返回值就是age此时的值
get(){
console.log('有人读取age属性,get方法被调用')
return number //返回定义的number变量值
},
//当有人修改person的age属性时,set函数(setter)就会被调用,且参数是要赋予age属性的值
set(value){
console.log('有人修改age属性,set方法被调用,修改值为',value)
//age的值取决于number,修改number的值就可以修改age的值
//并没有直接修改age属性值
number = value
}
})
</script>
运行结果:
上述代码完成了一种功能:person 对象中有 age 这个属性,但是 age 属性的值并不是固定的,可以随时读取,随时修改。
数据代理
概念:通过一个代理对象,操作另一个对象中的数据,而不是直接操作该对象。
代码示例:
<!-- 想要通过obj2获取、修改obj中的数据,而不是直接操作obj -->
<script type="text/javascript" >
let obj = {
x:100
}
let obj2 = {
y:200
}
Object.defineProperty(obj2,'x',{
get(){
return obj.x
},
set(value){
obj.x = value
}
})
</script>
Vue中的数据代理
代码演示:
<body>
<div id="root">
<h2>名称:{{name}}</h2>
<h2>地址:{{address}}</h2>
</div>
</body>
<script type="text/javascript">
const vm = new Vue({
el:'#root',
data:{
name:'Jay',
address:'台湾'
}
})
</script>
总结:
1、Vue 中的数据代理指的就是通过 Vue 实例(Vue实例中也会有上述的 name、address 属性)来代理 data 对象中 name、address 属性的操作
2、如果没有数据代理,那么在 View 中获取 data 中的数据只能通过上述的 _data 来获取
- Vue 使用数据代理的目的就是可以编码时简写,比如直接写 name 就可以拿到 'Jay' 这个值(编码获取的是 Vue 中的 name,最终通过 getter() 方法读取到的是 data 中的 name)。
- Vue 使用数据代理还可以将数据的改变同步到页面上,比如修改 vm.name 值,最终通过 setter() 方法修改的是 data 中的数据,data 中的数据发生了变化,最终会直接影响到页面上的数据。
- 只要 data 中的数据发生变化,Vue 就会重新解析模板(View),以更新模板中的值,如果解析模板的过程中,插值表达式中有调用函数,这个函数一定会被重新调用。
3、通过 Object.defineProperty() 方法把 data 对象中的所有属性添加到 Vue 实例上,并且为每个属性自动的添加 getter/setter,通过这些方法修改 data 中的属性值
4、具体见下图:
可以发现编码时写的 data 没有出现在 Vue 实例中,都转换成了 _data
,所以最终读取的都是 _data
中的数据。
5、只有 data
中的数据会做数据代理