Vue01-简介与入门
Vue
01. 简介
1.1 前端三大框架
目前前端最流行的三大框架:
- Vue
- React
- angular
1.2 Vue简介
Vue (读音 /vjuː/,类似于 view) ,也可以写成Vue.js。
vue.js是目前前端web开发最流行的工具库,由尤雨溪在2014年2月发布的。
- 一套用于构建用户界面的渐进式 JavaScript框架;
- 基于标准 HTML、CSS 和 JavaScript 构建,
- 提供了一套声明式的、组件化的编程模型;
VUE3文档:https://v3.cn.vuejs.org/guide/introduction.html
什么是渐进式框架呢?
表示我们可以在项目中一点点来引入和使用Vue,而不一定需要全部使用Vue来开发整个项目。
02. 快速上手
Vue的本质,就是一个JavaScript的库,对于Vue的使用:
- 在页面中通过CDN引入
- 下载Vue的JavaScript文件,并且自己手动引入
- 通过npm包管理工具安装并使用它
- 直接通过Vue CLI创建项目
2.1 引入
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--创建由Vue接管的区域-->
<div id="app"></div>
<!--引入Vue:CDN引入-->
<script src="https://unpkg.com/vue@next"></script>
<!--引入Vue:本地引入,需提前下载-->
<!--<script src="../js/vue.js"></script>-->
<script>
// 创建Vue的实例
const app = Vue.createApp({
template: '<h2>Hello</h2>'
})
// 挂载
app.mount('#app')
</script>
</body>
</html>
2.2 体验插值语法
插值语法,官网中的说法是Mustache。(由于使用{{}},形似胡子,所以使用这个单词)。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--创建由Vue接管的区域-->
<div id="app">
<h1>欢迎学习Vue.js</h1>
<div>我是{{name}},微信{{wechat}}</div>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
// 使用Vue
const app = Vue.createApp({
data: function () {
return {
name: '子不语',
wechat: '188888888'
}
},
})
// 挂载
app.mount('#app')
</script>
</body>
</html>
插值语法的更多用法:
- JavaScript表达式
- 三元运算
- 调用函数
<div id="app">
<!-- 1. 基本使用-->
<div>我叫{{name}},我喜欢{{hobby}}</div>
<!-- 2. JavaScript表达式-->
<div>{{ num + 1 + 1 }}</div>
<!-- 3. 三元运算-->
<div>{{ age>=18 ?"成年人":"未成年人"}}</div>
<!-- 4. 调用函数-->
<div>{{demoFunc()}}</div>
<!-- 如果函数需要参数也可传入 -->
</div>
<script>
// 使用Vue
const app = Vue.createApp({
data: function () {
return {
num: 0,
name: 子不语,
age: 22,
hobby: 羽毛球,
dataInfo: {
email: "xxxxx@163.com"
},
}
},
methods: {
demoFunc: function () {
return '2012-12-12'
},
}
})
// 挂载
app.mount('#app')
</script>
2.3 动态展示数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!--这里使用本地引入Vue-->
<script src="./Vue.js"></script>
</head>
<body>
<!--创建由Vue接管的区域-->
<div id="app"></div>
<script>
// 使用Vue
const app = Vue.createApp({
// 将内容放入app的template中
template: `
<h1>欢迎学习Vue.js</h1>
<h2>电影列表</h2>
<ul>
<li v-for="item in movies">{{item}}</li>
</ul>
`,
data: function () {
return {
movies: ['大话西游', '盗梦空间', '流浪地球']
}
},
})
// 挂载
app.mount('#app')
</script>
</body>
</html>
2.4 案例:计数器
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./Vue.js"></script>
</head>
<body>
<!--创建由Vue接管的区域-->
<div id="app"></div>
<script>
// 使用Vue
const app = Vue.createApp({
template: `
<h1>当前计数:{{num}}</h1>
<button @click="add">+1</button>
<button @click="minus">-1</button>
`,
data: function () {
return {
num: 0
}
},
methods: {
add: function () {
this.num++ // 使用this,可以直接访问data中定义的数据
},
minus: function () {
this.num--
},
}
})
// 挂载
app.mount('#app')
</script>
</body>
</html>
当app中定义了template,Vue会用template代替接管区域的内容;
如果app没有定义template,Vue默认渲染接管区域的内容。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./Vue.js"></script>
</head>
<body>
<!--创建由Vue接管的区域-->
<div id="app">
<h1>当前计数:{{num}}</h1>
<button @click="add">+1</button>
<button @click="minus">-1</button>
</div>
<script>
// 使用Vue
const app = Vue.createApp({
data: function () {
return {
num: 0
}
},
methods: {
add: function () {
this.num++
},
minus: function () {
this.num--
},
}
})
// 挂载
app.mount('#app')
</script>
</body>
</html>
2.5 原生js实现计数器
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2>当前计数:<span class="counter"></span></h2>
<button class="add"> +1</button>
<button class="minus"> -1</button>
<script>
// 1. 获取Dom
const counterEl = document.querySelector('.counter')
const addBtnEl = document.querySelector('.add')
const MinusBtnEl = document.querySelector('.minus')
// 2. 定义一个变量,用来记录数据
let counter = 100
counterEl.textContent = counter.toString()
// 3. 监听按钮的点击
addBtnEl.onclick = function () {
counter++
counterEl.textContent = counter.toString()
}
MinusBtnEl.onclick = function () {
counter--
counterEl.textContent = counter.toString()
}
</script>
</body>
</html>
2.6 声明式编程与命令式编程
由2.1.4
与2.1.5
,我们可以体验到声明式编程与命令时编程的不同:
命令式编程关注的是 “how to do”,需要自己完成整个过程。
声明式编程关注的是 “what to do”,由框架(机器)完成整个过程。
在2.1.5
中,我们通过JavaScript编写每一条代码,来给浏览器传达每一个指令,这样的编写代码的过程,我们称之为命令式编程;
在早期的原生JavaScript和jQuery开发的过程中,我们都是通过这种命令式的方式在编写代码的;
而在2.1.4
中,我们使用Vue,在createApp传入的对象中声明需要的内容:
- 模板template
- 数据data
- 方法methods
这样编写代码的过程,我们称之为是声明式编程;
03. 基本属性-optionAPI
3.1 data
data属性是传入一个函数,并且该函数需要返回一个对象:
- 在Vue2.x的时候,也可以传入一个对象(虽然官方推荐是一个函数);
- 在Vue3.x的时候,必须传入一个函数,否则就会直接在浏览器中报错;
data中返回的对象会被Vue的响应式系统劫持,之后对该对象的修改或者访问都会在劫持中被处理。
所以我们在template或者app中通过 {{counter}} 访问counter,可以从对象中获取到数据;修改counter的值时,app中的 {{counter}}也会发生改变;
3.2 methods
methods属性是一个对象,通常我们会在这个对象中定义很多的方法,这些方法可以被绑定到模板中。
在这些方法中,我们可以使用this关键字来直接访问到data中返回的对象的属性。
对官方文档有这么一段描述:
问题一:为什么不能使用箭头函数(官方文档有给出解释)?
问题二:不使用箭头函数的情况下,this到底指向的是什么?(可以作为一道面试题)
事实上Vue的源码当中就是对methods中的所有函数进行了遍历,并且通过bind绑定了this。
3.3 computed
computed称为计算属性。
对于computed,官方并没有给出直接的概念解释。
而是说:对于任何包含响应式数据的复杂逻辑,都应该使用计算属性。
我们通过案例来理解,以下有三个案例:
案例一:我们有两个变量:firstName和lastName,希望它们拼接之后在界面上显示;
案例二:我们有一个分数:score
当score大于60的时候,在界面上显示及格;
当score小于60的时候,在界面上显示不及格;
案例三:我们有一个变量message,记录一段文字:比如Hello World
某些情况下我们是直接显示这段文字;
某些情况下我们需要对这段文字进行反转;
方案一:在模板语法中直接使用表达式;
<div id="app">
<!-- 1.拼接名字 -->
<h2>{{ firstName + " " + lastName }}</h2>
<!-- 2.显示分数等级 -->
<h2>{{ score >= 60 ? '及格': '不及格' }}</h2>
<!-- 3.反转单词显示文本 -->
<h2>{{ message.split(" ").reverse().join(" ") }}</h2>
</div>
思路一虽然直接,但是存在不可避免的缺点:
模板中存在大量的复杂逻辑,不便于维护(模板中表达式的初衷是用于简单的计算);
当需要多次实现同样逻辑时,存在重复的代码;
多次使用时,很多运算也需要多次执行,没有缓存;
方案二:使用method对逻辑进行抽取,模板中进行函数调用;
<div id="app">
<!-- 1.拼接名字 -->
<h2>{{ getFullname() }}</h2>
<!-- 2.显示分数等级 -->
<h2>{{ getScoreLevel() }}</h2>
<!-- 3.反转单词显示文本 -->
<h2>{{ reverseMessage() }}</h2>
</div>
<script>
// 1.创建app
const app = Vue.createApp({
// data: option api
data() {
return {
// 1.姓名
firstName: "kobe",
lastName: "bryant",
// 2.分数: 及格/不及格
score: 80,
// 3.一串文本: 对文本中的单词进行反转显示
message: "Hello World!"
}
},
methods: {
getFullname() {
return this.firstName + " " + this.lastName
},
getScoreLevel() {
return this.score >= 60 ? "及格": "不及格"
},
reverseMessage() {
return this.message.split(" ").reverse().join(" ")
}
}
})
// 2.挂载app
app.mount("#app")
</script>
方案二比方案一有优化,但仍然有缺点:
- 我们想显示的是一个结果,但变成了一种方法调用;
- 多次使用方法的时候,没有缓存,也需要多次计算;
方案三:使用计算属性computed;
<div id="app">
<!-- 1.拼接名字 -->
<h2>{{ fullname }}</h2>
<!-- 2.显示分数等级 -->
<h2>{{ scoreLevel }}</h2>
<!-- 3.反转单词显示文本 -->
<h2>{{ reverseMessage }}</h2>
</div>
<script>
// 1.创建app
const app = Vue.createApp({
// data: option api
data() {
return {
// 1.姓名
firstName: "kobe",
lastName: "bryant",
// 2.分数: 及格/不及格
score: 80,
// 3.一串文本: 对文本中的单词进行反转显示
message: "my name is why"
}
},
computed: {
// 1.计算属性默认对应的是一个函数,模板中可以直接书写该函数名称
fullname() {
return this.firstName + " " + this.lastName
},
scoreLevel() {
return this.score >= 60 ? "及格": "不及格"
},
reverseMessage() {
return this.message.split(" ").reverse().join(" ")
}
}
})
// 2.挂载app
app.mount("#app")
</script>
注意:
无论是直观上还是效果上,计算属性都是更好的选择;
计算属性看起来像是一个函数,但是我们在使用的时候不需要加();并且计算属性是有缓存的。
在computed中,对于函数的调用,运行一次之后,结果会被缓存起来,在数据不发生变化时,计算属性是不需要重新计算的。
计算属性在大多数情况下,只需要一个getter方法即可,所以我们会将计算属性直接写成一个函数。
如果我们需要设置计算属性的值,这时候我们也可以给计算属性设置一个setter的方法。
<div id="app">
<h2>{{ fullname }}</h2>
<button @click="setFullname">设置fullname</button>
</div>
<script src="../lib/vue.js"></script>
<script>
// 1.创建app
const app = Vue.createApp({
// data: option api
data() {
return {
firstname: "coder",
lastname: "easy"
}
},
computed: {
// 语法糖的写法
// fullname() {
// return this.firstname + " " + this.lastname
// },
// 完整的写法:
fullname: {
get: function() {
return this.firstname + " " + this.lastname
},
set: function(value) {
const names = value.split(" ")
this.firstname = names[0]
this.lastname = names[1]
}
}
},
methods: {
setFullname() {
// this中可以直接访问到computed中的值。
this.fullname = "kobe bryant"
}
}
})
// 2.挂载app
app.mount("#app")
</script>
3.4 watch
监听器watch。
在某些情况下,我们希望在代码逻辑中监听某个数据的变化,当该数据发生变化时,执行某一些代码。
这个时候就需要用到监听器watch了。
以下案例:
data中的message发生变化时,watch中的message函数就会执行。
watch中函数的名称必须是数据名称。
<div id="app">
<h2>{{message}}</h2>
<button @click="changeMessage">修改message</button>
</div>
<script>
// 1.创建app
const app = Vue.createApp({
// data: option api
data() {
return {
message: "Hello Vue",
info: {name: "why", age: 18}
}
},
methods: {
changeMessage() {
this.message = "你好啊, 李银河!"
this.info = {name: "kobe"}
}
},
watch: {
// 1.默认有两个参数: newValue、oldValue
message(newValue, oldValue) {
console.log("message数据发生了变化:", newValue, oldValue)
},
info(newValue, oldValue) {
// 2.如果是对象类型, 那么拿到的是代理对象
console.log("info数据发生了变化:", newValue, oldValue)
// console.log(newValue.name, oldValue.name)
// 3.如果想获取原生对象
// console.log({ ...newValue })
// console.log(Vue.toRaw(newValue))
}
}
})
// 2.挂载app
app.mount("#app")
</script>
watch中监听的如果是对象类型, 那么数据变化后,拿到的是代理对象。
如果要获取原生对象,有两种方法:
console.log({ ...newValue })
console.log(Vue.toRaw(newValue))
深度监听
默认情况下,watch只是在侦听info的引用变化,对于内部属性的变化是不会做出响应的。
下面的例子中,changeInfo函数如果是直接赋予了一个新对象,所以,watch可以监听到,
但是,如果是info属性发生变化,默认是监听不到的。
methods: {
changeInfo() {
// 1.创建一个新对象, 赋值给info
// this.info = { name: "kobe" }
// 2.直接修改原对象某一个属性,这种情况监听不到。
this.info.name = "kobe"
}
watch的深度监听:
watch: {
// 进行深度监听
info: {
// 以下为完整写法,handler函数用于处理数据变化逻辑。之前是语法糖写法。
handler(newValue, oldValue) {
console.log("侦听到info改变:", newValue, oldValue)
console.log(newValue === oldValue) // True
},
// 监听器选项:
deep: true, // info进行深度监听
// 第一次渲染直接执行一次监听器
immediate: true
},
// Vue2的语法(了解即可)
"info.name": function(newValue, oldValue) {
console.log("name发生改变:", newValue, oldValue)
}
}
watch的其他写法
但组件被建立时,系统会自动执行created函数,
我们可以在created函数中,使用 $watch
来监听。需要传入三个参数:
第一个参数是要侦听的源;
第二个参数是侦听的回调函数callback;
第三个参数是额外的其他选项,比如deep、immediate;
<script>
// 1.创建app
const app = Vue.createApp({
// data: option api
data() {
return {
message: "Hello Vue"
}
},
methods: {
changeMessage() {
this.message = "你好啊, 李银河!"
}
},
// 生命周期回调函数: 当前的组件被创建时自动执行
// 一般在该函数中, 会进行网络请求
created() {
// ajax/fetch/axios
console.log("created")
this.$watch("message", (newValue, oldValue) => {
console.log("message数据变化:", newValue, oldValue)
}, { deep: true })
}
})
// 2.挂载app
app.mount("#app")
</script>
3.5 其他属性
当然,这里还可以定义很多其他的属性,比如props、emits、setup、components等等;也包括很多的生命周期函数。
04. v-once
当某些值只需要被渲染一次时,可以使用v-once。
需要注意的是,一旦某个标签使用了v-once指令,其后代标签都只渲染一次。
<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">
<!-- 指令: v-once -->
<h2 v-once>
{{ message }}
<span>数字: {{counter}}</span>
</h2>
<h1>{{message}}</h1>
<button @click="changeMessage">改变message</button>
</div>
<script src="../lib/vue.js"></script>
<script>
// 1.创建app
const app = Vue.createApp({
data: function() {
return {
message: "Hello Vue",
counter: 100
}
},
methods: {
changeMessage: function() {
this.message = "你好啊, 李银河"
this.counter += 100
console.log(this.message, this.counter)
}
}
})
// 2.挂载app
app.mount("#app")
</script>
</body>
</html>
05. v-text
v-text指令并不常用,了解即可。
其以指令的形式来渲染内容,比如插值语法灵活。
<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">
<h2> 前面内容 -- {{message}} -- 后面内容 </h2>
<h2 v-text="message"></h2>
</div>
<script src="../lib/vue.js"></script>
<script>
// 1.创建app
const app = Vue.createApp({
data: function() {
return {
message: "Hello Vue"
}
},
})
// 2.挂载app
app.mount("#app")
</script>
</body>
</html>
效果:
06. v-html
如果data中的数据是标签语法,v-text并不会渲染它。
使用v-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">
<h2>{{ content }}</h2>
<h2 v-html="content"></h2>
</div>
<script src="../lib/vue.js"></script>
<script>
// 1.创建app
const app = Vue.createApp({
// data: option api
data: function() {
return {
content: `<span style="color: red; font-size: 30px;">你好,Vue</span>`
}
},
})
// 2.挂载app
app.mount("#app")
</script>
</body>
</html>
效果:
07. v-pre
v-pre用于跳过元素和它的子元素的编译过程,显示原始的内容。
<div id="app">
<div v-pre>
<h2>{{ message }}</h2>
<p>当前计数: {{ counter }}</p>
<p>{{}}</p>
</div>
</div>
效果:
08. v-cloak
浏览器的加载原则是:更快地让用户看到内容。
浏览器在渲染页面的时候,实际上是先展示类似下面的内容:
当执行到Vue.createApp
时,再根据Vue的语法去渲染页面,显示:
在某些极端的情况下,Vue的渲染过程太慢,用户会看到类似{{message}}
的内容。
如果不希望让用户看到这些内容,则可以使用v-cloak指令。
cloak是斗篷的意思。
v-cloak指令需要搭配css语法使用,
通过css语法,指定在未渲染完全时的显示样式。
<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>
<style>
[v-cloak] {
display: none;
}
</style>
</head>
<body>
<div id="app">
<h2 v-cloak>{{message}}</h2>
</div>
<script src="../lib/vue.js"></script>
<script>
setTimeout(() => {
// 1.创建app
const app = Vue.createApp({
// data: option api
data: function() {
return {
message: "Hello Vue"
}
},
})
// 2.挂载app
app.mount("#app")
}, 3000)
</script>
</body>
</html>
09. v-memo
使用v-memo时,只有规定的值发生变化,才会重新渲染。
<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-memo="[name, age]">
<h2>姓名: {{ name }}</h2>
<h2>年龄: {{ age }}</h2>
<h2>身高: {{ height }}</h2>
</div>
<button @click="updateInfo">改变信息</button>
</div>
<script src="../lib/vue.js"></script>
<script>
// 1.创建app
const app = Vue.createApp({
// data: option api
data: function() {
return {
name: "why",
age: 18,
height: 1.88
}
},
methods: {
updateInfo: function() {
// this.name = "kobe"
this.age = 20
}
}
})
// 2.挂载app
app.mount("#app")
</script>
</body>
</html>
10. v-bind
前面的指令都是用来渲染标签内容的,如果需要动态渲染标签的属性,则需要使用到v-bind。
10.1 绑定属性
<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>
<button @click="switchImage">切换图片</button>
</div>
<!-- 1.绑定img的src属性 -->
<img v-bind:src="showImgUrl" alt="">
<!-- 语法糖: v-bind -> : -->
<img :src="showImgUrl" alt="">
<!-- 2.绑定a的href属性 -->
<a :href="href">百度一下</a>
</div>
<script src="../lib/vue.js"></script>
<script>
// 1.创建app
const app = Vue.createApp({
// data: option api
data: function() {
return {
imgUrl1: "http://p1.music.126.net/agGc1qkogHtJQzjjyS-kAA==/109951167643767467.jpg",
imgUrl2: "http://p1.music.126.net/_Q2zGH5wNR9xmY1aY7VmUw==/109951167643791745.jpg",
showImgUrl: "http://p1.music.126.net/_Q2zGH5wNR9xmY1aY7VmUw==/109951167643791745.jpg",
href: "http://www.baidu.com"
}
},
methods: {
switchImage: function() {
this.showImgUrl = this.showImgUrl === this.imgUrl1 ? this.imgUrl2: this.imgUrl1
}
}
})
// 2.挂载app
app.mount("#app")
</script>
</body>
</html>
10.2 绑定class
<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>
<style>
.active {
color: red;
}
</style>
</head>
<body>
<div id="app">
<!-- 1.基本绑定class -->
<h2 :class="classes">Hello World</h2>
<!-- 2.动态class可以写三元运算 -->
<button :class=" isActive ? 'active': '' " @click="btnClick">我是按钮</button>
<!-- 3.class的绑定内容可以传入对象,值必须为布尔值 -->
<button :class="{ active: isActive }" @click="btnClick">我是按钮</button>
<!-- 4.对象语法:传入多个键值对 -->
<button :class="{ active: isActive, why: true, kobe: false }" @click="btnClick">我是按钮</button>
<!-- 5.动态绑定的class是可以和普通的class同时的使用 -->
<button class="abc cba" :class="{ active: isActive, why: true, kobe: false }" @click="btnClick">我是按钮</button>
<!-- 6.通过函数的方式获取对象 -->
<button class="abc cba" :class="getDynamicClasses()" @click="btnClick">我是按钮</button>
<!-- 7.动态class可以写数组语法(了解) -->
<h2 :class="['abc', 'cba']">Hello Array</h2>
<h2 :class="['abc', className]">Hello Array</h2>
<h2 :class="['abc', className, isActive? 'active': '']">Hello Array</h2>
<h2 :class="['abc', className, { active: isActive }]">Hello Array</h2>
</div>
<script src="../lib/vue.js"></script>
<script>
// 1.创建app
const app = Vue.createApp({
// data: option api
data: function() {
return {
classes: "abc cba nba",
isActive: false,
className: "why"
}
},
methods: {
btnClick: function() {
this.isActive = !this.isActive
},
getDynamicClasses: function() {
return { active: this.isActive, why: true, kobe: false }
}
}
})
// 2.挂载app
app.mount("#app")
</script>
</body>
</html>
10.3 绑定style
使用v-bind绑定style,可以传入对象类型,但要注意,以下的写法是不对的。
<h2 v-bind:style="{ color: red, font-size: 30px }">你好,Vue!</h2>
因为-与30px这种写法是不能被检测的。
CSS property 名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用引号括起来) 来命名。
<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">
<!-- 1.普通的html写法 -->
<h2 style="color: red; font-size: 30px;">你好,Vue!</h2>
<!-- 2.style中的某些值, 来自data中 -->
<!-- 2.1.动态绑定style, 在后面跟上 对象类型 (重要)-->
<h2 v-bind:style="{ color: fontColor, fontSize: fontSize + 'px' }">你好,Vue!</h2>
<!-- 2.2.动态的绑定属性, 这个属性是一个对象 -->
<h2 :style="objStyle">你好,Vue!</h2>
<!-- 3.style的数组语法,元素为对象 -->
<h2 :style="[objStyle, { backgroundColor: 'purple' }]">你好,Vue!</h2>
</div>
<script src="../lib/vue.js"></script>
<script>
// 1.创建app
const app = Vue.createApp({
data: function() {
return {
fontColor: "blue",
fontSize: 30,
objStyle: {
fontSize: '50px',
color: "green"
}
}
},
})
// 2.挂载app
app.mount("#app")
</script>
</body>
</html>
如果属性名称不是固定的,我们可以使用 :[属性名]=“值” 的格式来定义;
这种绑定的方式,我们称之为动态绑定属性。
<div id="app">
<h2 :[name]="'aaaa'">Hello World</h2>
</div>
<script>
// 1.创建app
const app = Vue.createApp({
// data: option api
data: function() {
return {
name: "class"
}
},
})
// 2.挂载app
app.mount("#app")
</script>
10.4 绑定对象
<div id="app">
<!-- 各个属性逐一绑定,较为繁琐 -->
<h2 :name="name" :age="age" :height="height">Hello World</h2>
<!-- v-bind绑定对象,常用于给组件传递参数 -->
<h2 v-bind="infos">Hello Bind</h2>
</div>
<script>
// 1.创建app
const app = Vue.createApp({
// data: option api
data: function() {
return {
infos: { name: "why", age: 18, height: 1.88, address: "广州市" },
name: "why",
age: 18,
height: 1.88
}
},
})
// 2.挂载app
app.mount("#app")
</script>
11. v-on
前面的指令是绑定元素的内容和属性,在开发中,还有一个非常重要的特性久是交互。
Vue提供了v-on来绑定事件,比如点击、拖拽、键盘事件等。
11.1 基本使用
<div id="app">
<!-- 1.基本的写法:点击事件 -->
<div class="box" v-on:click="divClick"></div>
<!-- 2.语法糖,简写(重点掌握) -->
<div class="box" @click="divClick"></div>
<!-- 3.绑定的方法位置, 也可以写成一个表达式(不常用, 不推荐) -->
<h2>{{ counter }}</h2>
<button @click="increment">+1</button>
<button @click="counter++">+1</button>
<!-- 4.鼠标移动方法(掌握) -->
<div class="box" @mousemove="divMousemove"></div>
<!-- 5.元素绑定多个事件(掌握) -->
<div class="box" @click="divClick" @mousemove="divMousemove"></div>
<!-- 6.元素绑定多个事件,直接绑定对象 -->
<!-- <div class="box" v-on="{ click: divClick, mousemove: divMousemove }"></div> -->
<!-- <div class="box" @="{ click: divClick, mousemove: divMousemove }"></div> -->
</div>
<script src="../lib/vue.js"></script>
<script>
// 1.创建app
const app = Vue.createApp({
// data: option api
data: function() {
return {
counter: 0
}
},
methods: {
divClick() {
console.log("divClick")
},
increment() {
this.counter++
},
divMousemove() {
console.log("divMousemove")
}
}
})
// 2.挂载app
app.mount("#app")
</script>
11.2 传递参数
在绑定事件时, 没有传递任何的参数, 那么event对象会被默认传递进来;
如果有明确传递参数,则event不会被传递;
如果有明确传递参数,又希望有event参数,可以使用$event传递。
<div id="app">
<!-- 1.默认传递event对象 -->
<button @click="btn1Click">按钮1</button>
<!-- 2.只有自己的参数 -->
<button @click="btn2Click('why', age)">按钮2</button>
<!-- 3.自己的参数和event对象 -->
<!-- 在模板中想要明确的获取event对象: $event -->
<button @click="btn3Click('why', age, $event)">按钮3</button>
</div>
<script>
// 1.创建app
const app = Vue.createApp({
// data: option api
data: function() {
return {
message: "Hello Vue",
age: 18
}
},
methods: {
// 1.默认参数: event对象
// 总结: 如果在绑定事件的时候, 没有传递任何的参数, 那么event对象会被默认传递进来
btn1Click(event) {
console.log("btn1Click:", event)
},
// 2.明确参数:
btn2Click(name, age) {
console.log("btn2Click:", name, age)
},
// 3.明确参数+event对象
btn3Click(name, age, event) {
console.log("btn3Click:", name, age, event)
}
}
})
// 2.挂载app
app.mount("#app")
</script>
11.3 修饰符
v-on支持修饰符,修饰符相当于对事件进行了一些特殊的处理:
- .stop - 调用 event.stopPropagation()。
- .prevent - 调用 event.preventDefault()。
- .capture - 添加事件侦听器时使用 capture 模式。
- .self - 只当事件是从侦听器绑定的元素本身触发时才触发回调。
- .{keyAlias} - 仅当事件是从特定键触发时才触发回调。
- .once - 只触发一次回调。
- .left - 只当点击鼠标左键时触发。
- .right - 只当点击鼠标右键时触发。
- .middle - 只当点击鼠标中键时触发。
- .passive - { passive: true } 模式添加侦听器
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
.box {
width: 100px;
height: 100px;
background-color: orange;
}
</style>
</head>
<div id="app">
<div class="box" @click="divClick">
<button @click.stop="btnClick">按钮</button>
</div>
</div>
<script>
// 1.创建app
const app = Vue.createApp({
// data: option api
data: function() {
return {
message: "Hello Vue"
}
},
methods: {
btnClick(event) {
console.log("btnClick")
},
divClick() {
console.log("divClick")
}
}
})
// 2.挂载app
app.mount("#app")
</script>
12. v-if
Vue提供了一些指令进行条件渲染。
- v-if
- v-else
- v-else-if
- v-show
<div id="app">
<ul v-if="names.length > 0">
<li v-for="item in names">{{item}}</li>
</ul>
<h2 v-else>当前names没有数据, 请求获取数据后展示</h2>
</div>
<script>
// 1.创建app
const app = Vue.createApp({
data: function() {
return {
names: []
}
},
})
// 2.挂载app
app.mount("#app")
</script>
<div id="app">
<!-- v-if="条件",判断是否为空对象 -->
<div class="info" v-if="Object.keys(info).length">
<h2>个人信息</h2>
<ul>
<li>姓名: {{info.name}}</li>
<li>年龄: {{info.age}}</li>
</ul>
</div>
</div>
<script>
// 1.创建app
const app = Vue.createApp({
// data: option api
data() {
return {
info: {}
}
}
})
// 2.挂载app
app.mount("#app")
</script>
因为Vue的指令必须添加到一个元素上才能产生作用。
一般我们选择一个div作为顶层,作为根节点。
但是如果我们希望切换的是多个元素呢?这个时候,我们可以选择使用template;
template元素可以当做不可见的包裹元素,并且在v-if上使用,但是最终template不会被渲染出。
13. v-show
v-show的功能与v-if类似,但有本质的不同。
v-show元素无论是否需要显示到浏览器上,它的DOM实际都是有存在的,只是通过CSS的display属性来进行切换;
v-if当条件为false时,其对应的原生压根不会被渲染到DOM中;
其次要注意的是:v-show是不支持template;
v-show也不可以和v-else一起使用;
开发中如何进行选择呢?
如果我们的原生需要在显示和隐藏之间频繁的切换,那么使用v-show;
如果不会频繁的发生切换,那么使用v-if;
<div id="app">
<div>
<button @click="toggle">切换</button>
</div>
<div v-show="isShowCode">
<img src="https://game.gtimg.cn/images/yxzj/web201706/images/comm/floatwindow/wzry_qrcode.jpg" alt="">
</div>
<div v-if="isShowCode">
<img src="https://game.gtimg.cn/images/yxzj/web201706/images/comm/floatwindow/wzry_qrcode.jpg" alt="">
</div>
</div>
<script src="../lib/vue.js"></script>
<script>
// 1.创建app
const app = Vue.createApp({
// data: option api
data() {
return {
isShowCode: true
}
},
methods: {
toggle() {
this.isShowCode = !this.isShowCode
}
}
})
// 2.挂载app
app.mount("#app")
</script>
14. v-for
遍历数组:
// 1.数组: 存放的字符串
movies: ["星际穿越", "少年派", "大话西游", "哆啦A梦"],
// 2.数组: 存放的是对象
products: [
{ id: 110, name: "Macbook", price: 9.9, desc: "9.9秒杀, 快来抢购!" },
{ id: 111, name: "iPhone", price: 8.8, desc: "9.9秒杀, 快来抢购!" },
{ id: 112, name: "小米电脑", price: 9.9, desc: "9.9秒杀, 快来抢购!" },
]
<div id="app">
<!-- 1.电影列表进行渲染 -->
<h2>电影列表</h2>
<ul>
<li v-for="movie in movies">{{ movie }}</li>
</ul>
<!-- 2.电影列表同时有索引 -->
<ul>
<li v-for="(movie, index) in movies">{{index + 1}} - {{ movie }}</li>
</ul>
<!-- 3.遍历数组复杂数据 -->
<h2>商品列表</h2>
<div class="item" v-for="item in products">
<h3 class="title">商品: {{item.name}}</h3>
<span>价格: {{item.price}}</span>
<p>秒杀: {{item.desc}}</p>
</div>
</div>
遍历对象
message: "Hello Vue",
movies: [],
info: { name: "why", age: 18, height: 1.88 }
<div id="app">
<!-- 1.遍历对象 -->
<ul>
<li v-for="(value, key, index) in info">{{value}}-{{key}}-{{index}}</li>
</ul>
<!-- 2.遍历字符串(iterable) -->
<ul>
<li v-for="item in message">{{item}}</li>
</ul>
<!-- 3.遍历数字 -->
<ul>
<li v-for="item in 100">{{item}}</li>
</ul>
</div>
14.1 数组更新检测
Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。
这些被包裹过的方法包括:
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
替换数组的方法:
上面的方法会直接修改原来的数组;
但是某些方法不会替换原来的数组,而是会生成新的数组,比如 filter()、concat() 和 slice();
<div id="app">
<ul>
<li v-for="item in names">{{ item }}</li>
</ul>
<button @click="changeArray">修改数组</button>
</div>
<script src="../lib/vue.js"></script>
<script>
// 1.创建app
const app = Vue.createApp({
// data: option api
data() {
return {
names: ["abc", "cba", "nba", "aaa", "ccc"]
}
},
methods: {
changeArray() {
// 1.直接将数组修改为一个新的数组
// this.names = ["why", "kobe"]
// 2.通过一些数组的方法, 修改数组中的元素
// this.names.push("why")
// this.names.pop()
// this.names.splice(2, 1, "why")
// this.names.sort()
// this.names.reverse()
// 3.不修改原数组的方法是不能侦听的
const newNames = this.names.map(item => item + "why")
this.names = newNames
}
}
})
// 2.挂载app
app.mount("#app")
</script>
14.2 v-for中的key
在使用v-for进行列表渲染时,我们通常会给元素或者组件绑定一个key属性。
key属性的要求是唯一,一般为id值。
这个key属性有什么作用呢?我们先来看一下官方的解释:
key属性主要用在Vue的虚拟DOM算法,在新旧nodes对比时辨识VNodes;
如果不使用key,Vue会使用一种最大限度减少动态元素并且尽可能尝试就地修改/复用相同类型元素的算法;
而使用key时,它会基于key的变化重新排列元素顺序,并且会移除/销毁key不存在的元素;
<div id="app">
<button @click="insertF">插入f</button>
<ul>
<!-- key要求是唯一: id -->
<li v-for="item in letters" :key="item">{{item}}</li>
</ul>
</div>
<script src="../lib/vue.js"></script>
<script>
// 1.创建app
const app = Vue.createApp({
data() {
return {
letters: ["a", "b", "c", "d", "e"]
}
},
methods: {
insertF() {
this.letters.splice(2, 0, "f")
this.letters.splice()
}
}
})
// 2.挂载app
app.mount("#app")
</script>
14.3 VNode概念
VNode的全称是Virtual Node,也就是虚拟节点;
事实上,无论是组件还是元素,它们最终在Vue中表示出来的都是一个个VNode。
这样做的好处之一是可以更好地实现跨平台。
针对不同的最终设备,比如浏览器、安卓端、iOS、VR等,渲染成不同的内容。
VNode的本质是一个JavaScript的对象。
比如,如果有这一个标签:
<div class="title" style="font-size: 30px;color: red">哈哈哈</div>
那么,Vue会将其转换成为一个VNode对象,
const vnode = {
type: 'div',
props: {
class:'title',
style: {
'font-size': '30px',
'color': 'red',
},
},
children:'哈哈哈'
}
渲染成VNode之后,再将其渲染成正在的DOM对象。
如果不只是一个简单的div,而是有一大堆的元素,那么它们会形成一个VNode Tree
15. v-model
前端开发中,一个很重要的环节就是与用户互动。
- 用户在登录、注册时需要提交账号密码;
- 用户在检索、创建、更新信息时,需要提交一些数据;
此时,数据就需要做一个双向绑定。
15.1 手动实现双向绑定
<div id="app">
<!-- 手动的实现双向绑定 -->
<input type="text" :value="message" @input="inputChange">
<h2>{{message}}</h2>
</div>
<script src="../lib/vue.js"></script>
<script>
// 1.创建app
const app = Vue.createApp({
// data: option api
data() {
return {
message: "Hello Vue",
}
},
methods: {
inputChange(event) {
this.message = event.target.value
},
}
})
// 2.挂载app
app.mount("#app")
</script>
:value="message"
实现了数据的动态绑定,读取message的值,将其显示在页面中;
@input="inputChange"
对“输入”进行监听,本质上是写了inputChange方法,但用户进行输入时,执行inputChange方法;inputChange方法将用户输入的值重新赋值给message。
15.2 绑定input
其实v-model的原理就是这两个操作:
v-bind绑定value属性的值;
v-on绑定input事件监听到函数中,函数会获取最新的值赋值到绑定的属性中;
<div id="app">
<!-- 登录功能 -->
<label for="account">
账号:<input id="account" type="text" v-model="account">
</label>
<label for="password">
密码:<input id="password" type="password" v-model="password">
</label>
<button @click="loginClick">登录</button>
</div>
<script>
// 1.创建app
const app = Vue.createApp({
// data: option api
data() {
return {
account: "",
password: ""
}
},
methods: {
loginClick() {
const account = this.account
const password = this.password
// url发送网络请求
console.log(account, password)
}
}
})
// 2.挂载app
app.mount("#app")
</script>
15.3 绑定textarea
<div id="app">
<textarea cols="30" rows="10" v-model="content"></textarea>
<p>输入的内容: {{content}}</p>
</div>
<script>
// 1.创建app
const app = Vue.createApp({
// data: option api
data() {
return {
content: ""
}
},
})
// 2.挂载app
app.mount("#app")
</script>
15.4 绑定checkbox
checkbox有多选框和单选框:
单选框: 绑定到属性中的值是一个Boolean
多选框当中, 必须明确的绑定一个value值,对应的data中属性是一个数组。
<div id="app">
<!-- 1.checkbox单选框: 绑定到属性中的值是一个Boolean -->
<label for="agree">
<input id="agree" type="checkbox" v-model="isAgree"> 同意协议
</label>
<h2>单选框: {{isAgree}}</h2>
<hr>
<!-- 2.checkbox多选框: 绑定到属性中的值是一个Array -->
<!-- 注意: 多选框当中, 必须明确的绑定一个value值 -->
<div class="hobbies">
<h2>请选择你的爱好:</h2>
<label for="sing">
<input id="sing" type="checkbox" v-model="hobbies" value="sing"> 唱
</label>
<label for="jump">
<input id="jump" type="checkbox" v-model="hobbies" value="jump"> 跳
</label>
<label for="rap">
<input id="rap" type="checkbox" v-model="hobbies" value="rap"> rap
</label>
<label for="basketball">
<input id="basketball" type="checkbox" v-model="hobbies" value="basketball"> 篮球
</label>
<h2>爱好: {{hobbies}}</h2>
</div>
</div>
<script src="../lib/vue.js"></script>
<script>
// 1.创建app
const app = Vue.createApp({
// data: option api
data() {
return {
isAgree: false,
hobbies: []
}
},
})
// 2.挂载app
app.mount("#app")
</script>
15.5 绑定radio
radio与多选框不同,其值是互斥的。比如性别,要么男要么女。
在input标签中,是通过name属性来区分的。只要input标签中,拥有相同的name属性,就可以实现互斥。
因此v-model就绑定在name属性上。
<div id="app">
<div class="gender">
<label for="male">
<input id="male" type="radio" v-model="gender" value="male"> 男
</label>
<label for="female">
<input id="female" type="radio" v-model="gender" value="female"> 女
</label>
<h2>性别: {{gender}}</h2>
</div>
</div>
<script>
// 1.创建app
const app = Vue.createApp({
// data: option api
data() {
return {
gender: "female"
}
},
})
// 2.挂载app
app.mount("#app")
</script>
15.6 绑定select
<div id="app">
<!-- select的单选 -->
<select v-model="fruit">
<option value="apple">苹果</option>
<option value="orange">橘子</option>
<option value="banana">香蕉</option>
</select>
<h2>单选: {{fruit}}</h2>
<hr>
<!-- select的多选 -->
<select multiple size="3" v-model="fruits">
<option value="apple">苹果</option>
<option value="orange">橘子</option>
<option value="banana">香蕉</option>
</select>
<h2>多选: {{fruits}}</h2>
</div>
<script>
// 1.创建app
const app = Vue.createApp({
// data: option api
data() {
return {
fruit: "orange",
fruits: []
}
},
})
// 2.挂载app
app.mount("#app")
</script>
15.7 修饰符
- .lazy:默认v-model绑定的是input事件,lazy修饰符将绑定change事件;
- .number:自动将内容转换成数字;
- .trim:去除收尾的空格
<div id="app">
<!-- 1.lazy: 绑定change事件 -->
<input type="text" v-model.lazy="message">
<h2>message: {{message}}</h2>
<hr>
<!-- 2.number: 自动将内容转换成数字 -->
<input type="text" v-model.number="counter">
<h2>counter:{{counter}}-{{typeof counter}}</h2>
<input type="number" v-model="counter2">
<h2>counter2:{{counter2}}-{{typeof counter2}}</h2>
<hr>
<!-- 3.trim: 去除收尾的空格 -->
<input type="text" v-model.trim="content">
<h2>content: {{content}}</h2>
<hr>
<!-- 4.使用多个修饰符 -->
<input type="text" v-model.lazy.trim="content">
<h2>content: {{content}}</h2>
</div>
<script>
// 1.创建app
const app = Vue.createApp({
// data: option api
data() {
return {
message: "Hello Vue",
counter: 0,
counter2: 0,
content: ""
}
},
watch: {
content(newValue) {
console.log("content:", newValue)
}
}
})
// 2.挂载app
app.mount("#app")
</script>
(结束)
Vue01-简介与入门的更多相关文章
- JS面向对象(1) -- 简介,入门,系统常用类,自定义类,constructor,typeof,instanceof,对象在内存中的表现形式
相关链接: JS面向对象(1) -- 简介,入门,系统常用类,自定义类,constructor,typeof,instanceof,对象在内存中的表现形式 JS面向对象(2) -- this的使用,对 ...
- python3-day1-python简介及入门
python简介及入门 python简介 Python的创始人为Guido van Rossum.1989年圣诞节期间,在阿姆斯特丹,Guido为了打发圣诞节的无趣,决心开发一个新的脚本解释程序,做为 ...
- Robot Framework-工具简介及入门使用
Robot Framework-Mac版本安装 Robot Framework-Windows版本安装 Robot Framework-工具简介及入门使用 Robot Framework-Databa ...
- Linux内核学习笔记-1.简介和入门
原创文章,转载请注明:Linux内核学习笔记-1.简介和入门 By Lucio.Yang 部分内容来自:Linux Kernel Development(Third Edition),Robert L ...
- Akka 简介与入门
Akka 简介与入门 http://www.thinksaas.cn/group/topic/344095/ 参考官网 http://akka.io/ 开源代码 https://github.co ...
- 【转】Docker简介与入门
转自:https://segmentfault.com/a/1190000000448808 Docker是个新生的事物,概念类似虚拟化.网上关于Docker入门的东西已经很多了.不过本文探讨了Doc ...
- Quartz入门例子简介 从入门到菜鸟(一)
转: Quartz入门例子简介 从入门到菜鸟(一) 2016年11月19日 22:58:24 爱种鱼的猫 阅读数:4039 刚接触quartz这个词并不是在学习过程中...而是WOW里面的界面插件 ...
- Lombok简介及入门使用 (转载)
Lombok简介及入门使用 lombok既是一个IDE插件,也是一个项目要依赖的jar包. Intellij idea开发的话需要安装Lombok plugin,同时设置 Setting -> ...
- Shiro简介、入门案例、web容器的集成
目的: shiro简介 Shiro入门案例 Shiro与web容器的集成 shiro简介(中文官网:https://www.w3cschool.cn/shiro/andc1if0.html) 1.什么 ...
- Python【第一章】:简介和入门
ython简介 Python的创始人为Guido van Rossum.1989年圣诞节期间,在阿姆斯特丹,Guido为了打发圣诞节的无趣,决心开发一个新的脚本解释程序,做为ABC 语言的一种继承.之 ...
随机推荐
- [Lua] IT技术熟练度生成器 | 根据IT活动记录生成md表格 | 自创
IT技术熟练度 v1.0 为衡量个人能力水平自创的一套评分机制,根据时间.代码行数.基础理论三个变量生成.最近在学lua,正好练下基本功.效果可见 个人介绍 | 代码统计 - 小能日记 - 博客园 ( ...
- java与es8实战之四:SpringBoot应用中操作es8(无安全检查)
欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本篇是<java与es8实战>系 ...
- springcache+redis实战
前言 有兴趣的同学,可以看我上一篇文章,然后再过来看会比较清楚点:https://www.cnblogs.com/yhc-910/p/14884678.html springcache,简单说,就是用 ...
- Electron创建项目并打包生成exe
安装nodejs 访问这个网站去下载 http://nodejs.cn/download/ 创建项目 创建项目 git clone https://github.com/electron/electr ...
- 大企业才用的分布式唯一Id,它比GUID好
支持.Net Core(2.0及以上)与.Net Framework(4.5及以上) 可以部署在Docker, Windows, Linux, Mac. 分布式唯一Id,顾名思义,是指在全世界任何一台 ...
- KRPANO资源分析工具模板链接下载
KRPano资源分析工具1.4.0加入了模板链接下载,可以批量下载有规律的链接. 模板链接基本规则 数字递增链接 pic[1-100]:会生成pic1,pic2,-pic100的链接 pic[a-z] ...
- zabbix 警报推送至企业微信(图文版)
新增Python脚本 # encoding: utf-8 import sys import requests import json import os import time import re ...
- Falcon-7B大型语言模型在心理健康对话数据集上使用QLoRA进行微调
文本是参考文献[1]的中文翻译,主要讲解了Falcon-7B大型语言模型在心理健康对话数据集上使用QLoRA进行微调的过程.项目GitHub链接为https://github.com/iamaru ...
- 「codeforces - 1486F」Pairs of Paths
link. 还算萌,但是代码有些难写-- 你首先会想要 int n, m, fa[20][300100], pa[300100], dep[300100], cnt[900100]; int ldf[ ...
- Python并发编程——multiprocessing模块、Process类、Process类的使用、守护进程、进程同步(锁)、队列、管道、共享数据 、信号量、事件、 进程池
文章目录 一 multiprocessing模块介绍 二 Process类的介绍 三 Process类的使用 四 守护进程 五 进程同步(锁) 六 队列(推荐使用) 七 管道 八 共享数据 九 信号量 ...