浏览本文须要根本把握HTML、CSS和JavaScript的中级常识,还有《Vue学习笔记(二) 初遇篇》。本篇在某种程度上并不是承接上一篇,更像是初遇篇的重构。
前言
去思否翻了翻本人第一篇写Vue相干的文章《Vue 学习笔记(一)初遇》, 发表的日期是2019年12月14号,也就是这一年呈现了疫情,到当初大略有三年了,不胜唏嘘。往年据说是“寒意凛然”,为了晋升本人的性价比,加强本人的竞争力,我决定重新学习一下前端。这是开玩笑的话,其实是为了做一个开源我的项目做筹备。让咱们来回顾一下《Vue 学习笔记(一)初遇》讲的货色,在这篇内容中咱们次要讲了JavaScript的大抵倒退历史,晚期的浏览器对JavaScript适配不齐全,雷同的JavaScript可能在不同的浏览器上没有统一的行为,而且在写管制DOM结点方面非常繁琐,于是有人推出了JQuery,化繁为简,然而随着网页在越来越简单,因为JQuery间接操纵DOM结点,DOM的节点的扭转就会带来网页的重绘,于是前面的前端框架的思路就是推出虚构DOM,使用diff算法来计算出真正须要更新的节点,最大限度地缩小DOM操作以及DOM操作带来的排版与重绘损耗,从而显著进步性能。 等等,JQuery操纵结点须要重绘,你的Vue也须要重绘啊? 那么你的Vue到底好在哪里呢? 好在,会合并运算,将屡次更改合并为一次,举一个例子,在JQuery中假如须要操纵三次Dom,由三个办法触发,但其实最终不须要更新那么屡次结点,咱们将DOM了解为一个数字,每次操作像是对这个数字进行加减,那么三次DOM操作可能就像是 5+ 3 – 5 , 最终只须要加3渲染一次就行了,这是Vue的做法。然而对于JQuery来说就是运算三次,带来三次页面重绘。这个性能节俭就在这里。 那么对于一个简单的页面,你这个diff算法的计算不须要工夫吗?当然也须要工夫, 其实咱们Vue次要还是在晋升开发效率、代码复用性。 这也就是Angular、Vue、React的思路,然而这些前端框架所带来的并不仅仅是虚构DOM,还带来了响应式、MVVM。但Vue并不具备侵入性,是渐进式的,所谓渐进式也就是说,如果你当初就有一个利用,那么你能够抉择将Vue嵌入到你的利用中,来享受Vue提供的便当,而不会对全局进行扭转。等一等,你说Vue提供的便当,你说到这个我就不困了,能举一个例子来阐明下Vue的便当吗? 好的,上面是一个最终效果图:
对html有一点相熟的同学可能一下子就看进去了,这是四个无序列表标签,列表标签前面是一个json。如果这些json是从服务端传递过去的,那么用JQuery实现下面的思路就是首先应用Ajax获取前端数据,而后拼接成对应的html字符串,通过JQuery选择器选中对应的元素,获取到JQuery对象之后,将对应的html字符串传给对象的append办法,此办法会将咱们拼接的字符串渲染为实在的DOM结点。
<!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>
</head>
<body>
<div id = "app">
</div>
</body>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.min.js">
// 这个标签用于引入JQuery
</script>
<script>
$(document).ready(function(){
// dom加载结点之后触发getJSON,获取的数据会传给result
$.getJSON("http://localhost:8080/hello",function(result){
var products = result.products;
console.log(products);
var targetStr = "";
// 通过foreach办法拼接成最终的字符串
$.each(products, function(i, field){
field = JSON.stringify(field);
targetStr = targetStr + "<li>" + field + "</li>"
});
// 通过append办法创立结点
$("#app").append("<ul>"+targetStr+"</ul>");
});
});
</script>
</html>
最终的后果如下图所示:
// getJson返回的数据格式如下
{
"products": [
{
"id": 1,
"quantity": 1,
"name": "红焖羊肉"
},
{
"id": 2,
"quantity": 0,
"name": "猪肉韭菜饺子"
},
{
"id": 3,
"quantity": 4,
"name": "热干面"
},
{
"id": 4,
"quantity": 5,
"name": "烩面"
}
]
}
上面Vue的写法:
<!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>
</head>
<body>
<div id = "app">
<ul v-for = "product in products" >
<li>
{{product}}
</li>
</ul>
</div>
<div>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">
// 这里代表引入Vue
</script>
<script>
// 代表创立一个Vue实例
const app = new Vue({
el:'#app', // el 代表element 前面跟的是须要Vue接管的元素
data:{
products:[]
},
// 页面加载的时候触发created函数
created(){
// 申请这个地址
fetch('http://localhost:8080/hello').then(response=> response.json()).then(json => {
// 将拿到的值赋给products
this.products = json.products;
})
}
})
</script>
</body>
</html>
下面的v-for 就是循环products,最终的成果与JQuery一样,然而Vue的更为天然一点,如果咱们要再加要求,比方计算出还剩多少份饭,渲染到指定结点上,残余份数为0就显示饭曾经卖光了,如果用JQuery来做,还是用选择器抉择对应的元素,而后写入到对应的元素中,这里不再给出JQuery的写法,咱们间接上Vue的写法:
<!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>
</head>
<body>
<div id = "app">
<ul v-for = "product in products" >
<li>
{{product.name}} {{product.quantity}}
<span v-if = "product.quantity === 0">
曾经售空
</span>
<button @click = "product.quantity += 1">
增加
</button>
</li>
</ul>
<h2> 总库存 {{ totalProducts}}</h2>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">
// 这里代表引入Vue
</script>
<script>
// 代表创立一个Vue实例
const app = new Vue({
el:'#app', // el 代表element 前面跟的是须要Vue接管的元素
data:{
products:[]
},
// 页面加载的时候触发created函数
created(){
// 申请这个地址
fetch('http://localhost:8080/hello').then(response=> response.json()).then(json => {
// 将拿到的值赋给products
this.products = json.products;
})
},
// computed 是计算属性
computed:{
totalProducts(){
// reduce是js提供, 进行累加
return this.products.reduce((sum,product) => {
return sum + product.quantity;
},0);
}
},
})
</script>
</body>
</html>
最终的成果如下图所示:
当咱们点击猪肉韭菜饺子的增加按钮,你会发现曾经售空会隐没,同时总库存会响应的减少。这也就是Vue中响应式的真义: 数据在产生变动的时候,Vue会帮你更新所有网页中用到它的中央。下面的例子中我么首先碰到的就是{{变量名}}, 这种语法被用来获取Vue实例中data对象的属性,这种语法在Vue中咱们称之为模板语法,这在Vue中被称之为申明式渲染,Vue 基于规范 HTML 拓展了一套模板语法,使得咱们能够申明式地形容最终输入的 HTML 和 JavaScript 状态之间的关系。 申明式和响应式是Vue的两个外围性能。
MVVM模式
做过服务端开发大多都对MVC模式不会模式:
view负责图形显示,是提供给用户的操作界面,是程序的外壳。Controller负责转发用户申请,将申请分发给对应的model,由model对提取用户所须要的数据。那MVVM模式呢?上面是一张介绍Vue中mvvm模式的一张经典图片:
页面中的一个惯例操作是咱们用JavaScript对DOM节点的某些事件进行监听,事件产生触发咱们的监听函数,监听函数更新DOM。在Vue中引入了v-model指令来对下面的惯例操作进行封装,咱们无需在写监听事件,借助v-model指令,页面的数据发生变化时候主动达到咱们的函数,函数来更新对应的节点,这所有仅仅须要一个简略v-model指令,让咱们来看上面一个例子:
<!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>
</head>
<div id = "app">
<p>Message is: {{ message }}</p>
<input v-model="message" placeholder="edit me" />
</div>
<body>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script>
var vue = new Vue({
el:'#app',
data:{
'message': 'Hello Vue.js'
}
})
</script>
</body>
</html>
当咱们在输入框中输出值,输出值会主动替换p标签的{{message}}, 你看看这是不是简略很多了, 这里咱们先让v-model漏个面,简略的先意识下,忘了说,这种景象咱们也称之为双向绑定。
Vue 简介
什么是 Vue?Vue2文档的答复是:
Vue (读音 /vjuː/,相似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为能够自底向上逐层利用。
Vue2文档的答复最终只突出渐进式框架, 我感觉这个答复是不够直观的。那咱们接着来看Vue 3是如何答复这个问题:
Vue (发音为 /vjuː/,相似 view) 是一款用于构建用户界面的 JavaScript 框架。它基于规范 HTML、CSS 和 JavaScript 构建,并提供了一套申明式的、组件化的编程模型,帮忙你高效地开发用户界面。无论是简略还是简单的界面,Vue 都能够胜任。
咱们从这个答复中看到的就比拟多了,并且更加直观,绝对于Vue2的答复较新的词是申明式、组件化,申明式在下面咱们曾经介绍过了,那什么是组件化? 或者什么是组件? 组件事实上是一个含意很大的概念,个别是指软件系统的一部分,承当了特定的职责,能够独立于整个零碎进行开发和测试,一个良好设计的组件应该能够在不同的软件系统中被应用(可复用)。例如V8引擎是Chrome浏览器的一部分,负责运行JavaScript代码,这里V8引擎就能够被视为是一个组件。V8引擎同时也是Node.js的JavaScript解释器,这体现了组件的可复用性。Vue组件也是如此,承当了特定的职责,具备可复用性。举一个例子,咱们司空见惯的下拉框,一个按钮事实上分成三块,第一个是骨架也就是html,第二个是css也就是款式,第三个是触发按钮事件(点击)之后的逻辑(JavaScript)。在Vue中咱们就能够将这个按当做一个组件来对待,如下图所示:
<script>
export default {
data() {
return {
count: 0
}
}
}
</script>
<template>
<button @click="count++">Count is: {{ count }}</button>
</template>
<style scoped>
button {
font-weight: bold;
}
</style>
咱们将下面的代码放入一个叫button.vue文件中,如果咱们想在别的中央应用这个组件,在须要用到的中央应用即可,咱们能够将button.vue称之为单文件组件,用英文名为Single-File Component, 缩写为SFC。单文件是组件是Vue的标志性性能。基于此咱们就能够将一个页面切分成若干个组件,组件零碎是 Vue 的另一个重要概念,因为它是一种形象,容许咱们应用小型、独立和通常可复用的组件构建大型利用。认真想想,简直任意类型的利用界面都能够形象为一个组件树:
这个图片来自Vue官网。Vue2的文档在答复何为Vue的时候,突出了渐进式,然而在Vue 3的第一答复中没有渐进式,但这并不意味着Vue具备侵入性,它依然是渐进式的,渐进式呈现了Vue的特点介绍中。在下面的例子中,咱们就是没有借助Vue的构建工具,而是将Vue当作相似JQuery一样的存在,渐进式的加强动态的html。事实上Vue的应用形式是多种多样的,你能够这样应用Vue:
- 无需构建步骤,渐进式加强动态的 HTML
- 在任何页面中作为 Web Components 嵌入
- 单页利用 (SPA)
- 全栈 / 服务端渲染 (SSR)
- Jamstack / 动态站点生成 (SSG)
- 开发桌面端、挪动端、WebGL,甚至是命令行终端中的界面
Vue 实例
在下面的例子中,咱们的利用总是从new 一个Vue对象开始,再看一下咱们的第一个Vue示例,这个示例中咱们用到了Vue实例中的data和el属性、created办法,el属性用来指明Vue实例的作用范畴,在Vue实例的作用范畴中,在html中能够用双大括号能够取出data对象的值,当一个 Vue 实例被创立时,它将 data
对象中的所有的 property 退出到 Vue 的响应式零碎中。当这些 property 的值产生扭转时,视图将会产生“响应”,即匹配更新为新的值。Vue的构造函数会为Vue的成员变量赋值,留神在JavaScript函数也能当做一个变量解决,所以咱们也能够抉择传入一个函数。那Vue实例有哪些成员变量呢,咱们来看以下Vue的API文档:
咱们目前用过的成员变量有data这个属于数据,computed属于计算属性,created办法在Vue的官网文档中被称为钩子,每个 Vue 实例在被创立时都要通过一系列的初始化过程——例如,须要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变动时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段增加本人的代码的机会。还有很多生疏的,不要焦急,咱们会做懒加载。
模板语法
咱们下面应用的是Vue模板语法中最常见的一种,被称为”Mustache“语法(双大括号取值)的文本取值,如果你想取出来的是html,能够通过上面的指令通知Vue:
<!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>
</head>
<body>
<div id = "app">
<span v-html = "product"></span>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">
// 这里代表引入Vue
</script>
<script>
// 代表创立一个Vue实例
const app = new Vue({
el:'#app', // el 代表element 前面跟的是须要Vue接管的DOM元素ID
data:{
product: "<h1>这是被Vue渲染进去的</h1>"
},
})
</script>
</body>
</html>
最终成果:
动静渲染的任意HTML可能会十分危险,因为它很容易导致XSS攻打,请审慎应用动静渲染。那这种模板语法是否作用dom元素的属性呢,在Vue是不能的,然而Vue中提供了另一种曲线救国的形式:v-bind指令。v-bind指令能够帮咱们将dom元素的属性和Vue对象的data实例绑定在一起。上面是v-bind指令的一个例子:
<!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>
</head>
<body>
<div id = "app">
<span v-html = "product"></span>
<div v-bind:id = "dynamicId" >
<button v-bind:disabled="isButtonDisabled">Button</button>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">
// 这里代表引入Vue
</script>
<script>
// 代表创立一个Vue实例
const app = new Vue({
el:'#app', // el 代表element 前面跟的是须要Vue接管的DOM元素ID
data:{
product: "<h1>这是被Vue渲染进去的</h1>",
dynamicId: "dynamicId",
isButtonDisabled: true // 对于布尔类型的属性, false、null、undefined,对应的属性不会呈现在渲染进去的元素中
})
</script>
</body>
</html>
v-bind的语法为: v-bind:绑定属性。
类与款式绑定
操纵元素的class
操纵元素的class列表和内联款式是数据绑定的一个常见须要,它们都是attribute,所以咱们能够用v-bind指令来解决,然而拼接字符串往往是个麻烦的事件,因而在Vue 中专门对class和style 做了加强,表达式的后果除了字符串之外,还能够是对象和数组。让咱们来看上面的例子:
<!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>
</head>
<body>
<div id = "app">
<div v-bind:class="{ active: isActive }" id = "app01">测试</div>
<div v-bind:class="{ active: isActive, 'text-danger': hasError }" id = "app02">这代表对象语法</div>
<div v-bind:class="[activeClass, errorClass]"> 这是数组语法</div>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script>
var vue = new Vue({
el:'#app', // active这个款式的存在与否取决于isActive的true、false
data: {
isActive: true, // #app02 是否具备active和text-danger取决于isActive和hasError的true和false
hasError: true,
activeClass: 'active',
errorClass: 'text-danger'
}
})
</script>
</html>
绑定内联款式
<!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>
</head>
<body>
<div id = "app">
<div v-bind:style="styleObject"> 对象语法</div>
<div v-bind:style="[styleObject, overridingStyles]"> 数组语法,data中申明的overridingStyles、overridingStyles在style中</div>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script>
var vue = new Vue({
el:'#app',
data: {
styleObject: {
color: 'red',
fontSize: '13px'
},
overridingStyles: {
'background-color': 'black',
'width':'500px'
}
}})
</script>
</html>
计算属性
模板外面能够容许呈现一些表达式,如上面的代码所示:
<!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>
</head>
<body>
<div id = "app">
{{number + 1}}
{{message}}
{{ message.split('').reverse().join('') }}
{{tips}}
{{reversedMessage}}
这里间接调用办法{{reversedMessagePlus()}}
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">
// 这里代表引入Vue
</script>
<script>
var vue = new Vue({
el: '#app',
data:{
number: 0,
message: '护维以难,法写种这荐推不',
tips: 'Vue 为咱们筹备了计算属性来应答这样的场景'
},
// 上面是用计算属性实现的
computed:{
// reversedMessage 关联上函数
// 这个函数将被用作reversedMessage的getter 函数
// 当data中的message产生扭转, reversedMessage会主动跟着扭转
// 验证这一点只须要关上浏览器的控制台, 为vue.messsage 赋值即可
reversedMessage:function(){
return this.message.split('').reverse().join('')
}
},
// 留神methods 和 computed中的函数不能同名
methods: {
reversedMessagePlus:function () {
return this.message.split('').reverse().join('')
}
}
})
</script>
</html>
在computed函数中的咱们称之为计算属性,在methods中咱们称之为一般的办法,两种形式的最终计算结果是完全相同的。不同的在于计算属性是基于它们的响应式依赖进行缓存的。只有相干响应式依赖产生扭转时它们才会从新求值。这就意味着只有message还没有产生扭转,屡次拜访reversedMessage会立即返回之前的计算结果,而不用再执行函数。
上面的计算属性不会再页面上更新,起因在于Date.now并不是响应式依赖,不依赖于data对象的值。
computed: {
now: function () {
return Date.now()
}
}
相比之下,每次触发从新渲染,调用办法将再次执行methods中的函数。计算属性的缓存在于,如果咱们须要有一个开销很大的计算属性A,它须要遍历一个微小的数组并作大量的计算。而后咱们可能其余的计算属性依赖于A,如果没有缓存,那么这个计算就会被执行屡次。
条件渲染与列表渲染
所谓条件渲染咱们能够这么了解,满足肯定条件,对应的dom元素才会被渲染进去,就像咱们下面用到的v-if。有v-if 就有v-else。值得注意的时v-else元素必须紧跟v-if或者v-else-if
的元素的前面,否则它将不会被辨认。v-else-if 于Vue在2.10版本推出,充当 v-if
的“else-if 块”,能够间断应用。值得注意的时,Vue会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。这么做除了使 Vue 变得十分快之外,还有其它一些益处。例如,如果你容许用户在不同的登录形式之间切换:
<!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>
</head>
<body>
<div id = "app">
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address">
</template>
<button @click = "toggle">切换登陆形式</button>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">
// 这里代表引入Vue
</script>
<script>
var vue = new Vue({
el: '#app',
data: {
loginType: 'username'
},
// 在这个例子中,用户输出,点击切换形式,并不会清空用户的输出。
methods:{
toggle:function(){
this.loginType = this.loginType === 'username' ? 'email': 'username';
}
}
});
</script>
</html>
如果想点击切换登陆形式之后切换,给每个input的key属性一个惟一的key就行,像上面这样:
<!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>
</head>
<body>
<div id = "app">
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address" key="email-input">
</template>
<button @click = "toggle">切换登陆形式</button>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">
// 这里代表引入Vue
</script>
<script>
var vue = new Vue({
el: '#app',
data: {
loginType: 'username'
},
methods:{
toggle:function(){
this.loginType = this.loginType === 'username' ? 'email': 'username';
}
}
});
</script>
</html>
另一个用于依据条件展现元素的选项是 v-show
指令。用法大抵一样:
<h1 v-show="ok">Hello!</h1>
不同的是带有 v-show
的元素始终会被渲染并保留在 DOM 中。v-show
只是简略地切换元素的 CSS property display
。也就是暗藏。
v-for就是列表渲染,遍历data中的元素,这里不再做介绍。
总结一下
重新学习了一下JavaScript内框架与库的倒退历史,从原生JavaScript到JQuery,再到古代前端框架。古代前端框架更加着眼于代码复用、性能、开发效率。咱们下面介绍了Vue的几大重要个性: MVVM,双向绑定、响应式。MVVM是一种理念,某种程度上双向绑定能够算的上是MVVM在Vue的实现,所谓双向绑定,就是咱们的数据对象和DOM建设关系之后,数据会主动的从DOM结点流向咱们的数据对象,在Vue实例中咱们如果对数据对象再进行操作,不须要咱们间接更新DOM结点,会主动的挂载到对应的数据结点。网页开发中咱们一个常见的需要是依据数据渲染结点,在Vue中咱们能够用模板语法、条件渲染、列表渲染来实现。如果你想要操纵款式,能够通过V-bind指令来实现。
参考资料
- 虚构DOM(Virtual DOM)的劣势在哪里? https://juejin.cn/post/710634…
- 为什么说JS的DOM操作很耗性能 https://zhuanlan.zhihu.com/p/…
- 怎么准确辨别这些名词:库、插件、组件、控件、扩大? https://www.zhihu.com/questio…
- MVC https://developer.mozilla.org…
发表回复