CDN引入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>
<h2>哈哈哈哈</h2>
<div id="app"></div>
<!--CDN地址-->
<script src="https://unpkg.com/vue@next"></script>
<script>
// 使用VUE
const app = Vue.createApp({
template: `<h2>cdn引入vue</h2>`
})
// 挂在
app.mount("#app")
</script>
</body>
</html>
Vue体验
Mystache插值语法
插值语法:
data属性返回的对象是有添加到Vue的响应式系统中。当data中的数据发生改变时,对应的内容也会进行更新。
用法如下:
{{ data_name }}
{{ js表达式 }}
{{ 调用methods/computed属性中函数 }}
<!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>
<h2>哈哈哈哈</h2>
<div id="app"></div>
<!--CDN地址-->
<script src="https://unpkg.com/vue@next"></script>
<script>
// 使用VUE
const app = Vue.createApp({
// 插值语法{{data_name}}
template: `<h2>{{title}}</h2>`,
data: function () {
return {
title: "hello world"
}
}
})
// 挂在
app.mount("#app")
</script>
</body>
</html>
列表数据
v-for 可以用来循环一个可迭代的数据。
<!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>
<h2>哈哈哈哈</h2>
<div id="app"></div>
<!--CDN地址-->
<script src="https://unpkg.com/vue@next"></script>
<script>
// 使用VUE
const app = Vue.createApp({
// v-for 循环一个可迭代的数据
template:
`<ul>
<li v-for='item in dataArr'>{{item}}</li>
</ul>`,
data: function () {
return {
dataArr: ['语文', '数学', '英语']
}
}
})
// 挂在
app.mount("#app")
</script>
</body>
</html>
计数器
methods: 里面写一些功能函数
方式一:
<!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>
<h2>哈哈哈哈</h2>
<div id="app"></div>
<!--CDN地址-->
<script src="https://unpkg.com/vue@next"></script>
<script>
// 使用VUE
const app = Vue.createApp({
// v-for 循环一个可迭代的数据
template:
`<h1>{{count}}</h1>
<button @click="increase">+</button>
<button @click="decrease">-</button>
`,
data: function () {
return {
count: 0
}
},
methods: {
increase: function () { this.count++},
decrease: function () { this.count--}
},
})
// 挂在
app.mount("#app")
</script>
</body>
</html>
方式二:
template里面的数据就是用来替换
<!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>
<h2>哈哈哈哈</h2>
<div id="app">
<h1>{{count}}</h1>
<button @click="increase">+</button>
<button @click="decrease">-</button>
</div>
<!--CDN地址-->
<script src="https://unpkg.com/vue@next"></script>
<script>
// 使用VUE
const app = Vue.createApp({
data: function () {
return {
count: 0
}
},
methods: {
increase: function () { this.count++},
decrease: function () { this.count--}
},
})
// 挂在
app.mount("#app")
</script>
</body>
</html>
Vue的一些指令说明
v-bind(掌握)
动态的绑定一个或多个 attribute,也可以是组件的 prop。
- 缩写:: 或者 . (当使用 .prop 修饰符)
- 期望:any (带参数) | Object (不带参数)
- 参数:attrOrProp (可选的)
<!-- 绑定 attribute -->
<img v-bind:src="imageSrc" />
<!-- 动态 attribute 名 -->
<button v-bind:[key]="value"></button>
<!-- 缩写 -->
<img :src="imageSrc" />
<!-- 缩写形式的动态 attribute 名 -->
<button :[key]="value"></button>
<!-- 内联字符串拼接 -->
<img :src="'/path/to/images/' + fileName" />
<!-- class 绑定 -->
<div :class="{ red: isRed }"></div>
<div :class="[classA, classB]"></div>
<div :class="[classA, { classB: isB, classC: isC }]"></div>
<!-- style 绑定 -->
<div :style="{ fontSize: size + 'px' }"></div>
<div :style="[styleObjectA, styleObjectB]"></div>
<!-- 绑定对象形式的 attribute -->
<div v-bind="{ id: someProp, 'other-attr': otherProp }"></div>
<!-- prop 绑定。“prop” 必须在子组件中已声明。 -->
<MyComponent :prop="someThing" />
<!-- 传递子父组件共有的 prop -->
<MyComponent v-bind="$props" />
<!-- XLink -->
<svg><a :xlink:special="foo"></a></svg>
v-on(掌握)
给元素绑定事件监听器。
- 缩写:@
- 期望的绑定值类型:Function | Inline Statement | Object (不带参数)
- 参数:event (使用对象语法则为可选项)
- 修饰符:
- .stop ——调用 event.stopPropagation()。
- .prevent ——调用 event.preventDefault()。
- .capture ——在捕获模式添加事件监听器。
- .self ——只有事件从元素本身发出才触发处理函数。
- .{keyAlias} ——只在某些按键下触发处理函数。
- .once ——最多触发一次处理函数。
- .left ——只在鼠标左键事件触发处理函数。
- .right ——只在鼠标右键事件触发处理函数。
- .middle ——只在鼠标中键事件触发处理函数。
- .passive ——通过 { passive: true } 附加一个 DOM 事件。
<!-- 方法处理函数 -->
<button v-on:click="doThis"></button>
<!-- 动态事件 -->
<button v-on:[event]="doThis"></button>
<!-- 内联声明 -->
<button v-on:click="doThat('hello', $event)"></button>
<!-- 缩写 -->
<button @click="doThis"></button>
<!-- 使用缩写的动态事件 -->
<button @[event]="doThis"></button>
<!-- 停止传播 -->
<button @click.stop="doThis"></button>
<!-- 阻止默认事件 -->
<button @click.prevent="doThis"></button>
<!-- 不带表达式地阻止默认事件 -->
<form @submit.prevent></form>
<!-- 链式调用修饰符 -->
<button @click.stop.prevent="doThis"></button>
<!-- 按键用于 keyAlias 修饰符-->
<input @keyup.enter="onEnter" />
<!-- 点击事件将最多触发一次 -->
<button v-on:click.once="doThis"></button>
<!-- 对象语法 -->
<button v-on="{ mousedown: doThis, mouseup: doThat }"></button>
条件渲染 (掌握)
v-if :
- 基于表达式值的真假性,来条件性地渲染元素或者模板片段。
- 期望的绑定值类型:any
- 详细信息
- 当 v-if 元素被触发,元素及其所包含的指令/组件都会销毁和重构。如果初始条件是假,那么其内部的内容根本都不会被渲染。
- 可用于 表示仅包含文本或多个元素的条件块。
- 当条件改变时会触发过渡效果。
- 当同时使用时,v-if 比 v-for 优先级更高。我们并不推荐在一元素上同时使用这两个指令 — 查看列表渲染指南详情。
<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>
template元素
因为v-if是一个指令,所以必须将其添加到一个元素上,但是如果我们希望切换的是多个元素呢?此时我们渲染的是div,但是我们并不希望div这种元素被渲染。此时,我们可以使用template。
<div v-if="{条件}">
<h1>xxxx</h1>
<h2>xxxx</h2>
</div>
<!-- 推荐使用template,不会增加多余的div元素 -->
<template v-if="{条件}">
<h1>xxxx</h1>
<h2>xxxx</h2>
</template>
案例
<!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>
<style>
[v-cloak] {
display: none;
}
</style>
</head>
<body>
<div id="app">
<!--1.默认传递event对象-->
<button @click="btn1Click">事件1</button>
<!--2.只有自己的参数-->
<button @click="btn2Click('李四', 18)">事件2</button>
<!--3.event对象和自己的参数-->
<!-- 在模板中想要明确的获取event对象:$event -->
<button @click="btn3Click('李四', 17, $event)">事件3</button>
</div>
<!--CDN地址-->
<script src="https://unpkg.com/vue@next"></script>
<script>
// 使用VUE
const app = Vue.createApp({
data: function () {
return {
name: '张三',
age: 12,
sex: '男'
}
},
methods: {
// 1.默认参数:event对象
// 如果在绑定事件的时候,没有传递任何的参数,那么event对象会被默认传递进来
btn1Click: function (event) {
console.log(event)
},
btn2Click: function (name, age) {
console.log(name, age)
},
btn3Click: function (name, age, event) {
console.log(name, age, event)
}
},
})
// 挂在
app.mount("#app")
</script>
</body>
</html>
v-show
- 基于表达式值的真假性,来改变元素的可见性。
- 期望的绑定值类型:any
- 详细信息
v-show 通过设置内联样式的 display CSS 属性来工作,当元素可见时将使用初始 display 值。当条件改变时,也会触发过渡效果。
注意:
v-show是不支持template
v-show不可以和v-else一起使用
v-once(了解)
只渲染一次,即使该改变了data_name的值,也不会重新渲染加了此指令的标签。可用于性能优化。
<h1 v-once>{{ data_name }}<h1>
如果是子节点,也是只会渲染一次:
<div v-once>
<h1>{{ data_name }}</h1>
</div>
v-text(了解)
用于更新元素的textContent
<h1 v-text="data_name"></span>
等价于
<h1>{{ data_name }}</h1>
v-html(了解)
默认情况下,如果我们栈式的内容本身是html,vue并不对其进行解析。
如果希望这个内容被Vue进行解析,可以使用v-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">
<h1>{{content}}</h1>
<h1 v-html="content"></h1>
</div>
<!--CDN地址-->
<script src="https://unpkg.com/vue@next"></script>
<script>
// 使用VUE
const app = Vue.createApp({
data: function () {
return {
content: '<span style="font-size: 20px;">哈哈哈</span>'
}
},
})
// 挂在
app.mount("#app")
</script>
</body>
</html>
v-pre(了解)
v-pre用于跳过元素和它的子元素的编译过程,显示原始的Mustache标签:
- 跳过不需要编译的节点,加快编译速度
<!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">
<h1>没有用v-pre {{ content }}</h1>
<h1 v-pre>用了v-pre {{content}}</h1>
</>
<!--CDN地址-->
<script src="https://unpkg.com/vue@next"></script>
<script>
// 使用VUE
const app = Vue.createApp({
data: function () {
return {
content: '哈哈哈哈'
}
},
})
// 挂在
app.mount("#app")
</script>
</body>
</html>
v-cloak(了解)
这个指令保持在元素上直到关联组件实例结束编译。
v-cloak和CSS规则一起使用。比如:[v-cloak] {display: none},这个指令可以隐藏未编译的Mustache标签直到组件实例准备完成。
<!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>
<style>
[v-cloak] {
display: none;
}
</style>
</head>
<body>
<div id="app">
<h1 v-cloak> {{ content }}</h1>
</>
<!--CDN地址-->
<script src="https://unpkg.com/vue@next"></script>
<script>
setTimeout(() => {
// 使用VUE
const app = Vue.createApp({
data: function () {
return {
content: '哈哈哈哈'
}
},
})
// 挂在
app.mount("#app")
}, 3000)
</script>
</body>
</html>
v-memo(了解)
期望的绑定值类型:any[]
详细信息:
缓存一个模板的子树。在元素和组件上都可以使用。为了实现缓存,该指令需要传入一个固定长度的依赖值数组进行比较。如果数组里的每个值都与最后一次的渲染相同,那么整个子树的更新将被跳过。举例来说:
<div v-memo="[valueA, valueB]">
...
</div>
当组件重新渲染,如果 valueA 和 valueB 都保持不变,这个
<!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>
<style>
[v-cloak] {
display: none;
}
</style>
</head>
<body>
<div id="app">
<div v-memo="[name]">
<h1> {{ name }}</h1>
<h1> {{ age }}</h1>
<h1> {{ sex }}</h1>
</div>
<button @click="changeName">改变名字</button>
<button @click="changeAge">改变年龄</button>
</div>
<!--CDN地址-->
<script src="https://unpkg.com/vue@next"></script>
<script>
// 使用VUE
const app = Vue.createApp({
data: function () {
return {
name: '张三',
age: 12,
sex: '男'
}
},
methods: {
changeName: function () {
console.log('改变名字')
this.name = '李四'
},
changeAge: function () {
console.log('改变年龄')
this.age = 18
}
},
})
// 挂在
app.mount("#app")
</script>
</body>
</html>
这个例子中只有点击改变name值才会重新渲染。
MVVM模型
Vue虽然并没有完全遵守MVVM的模型,但是整个设计是收到它的启发。
Vue一些属性说明
data属性
- Vue2.x: 可以是一个函数(建议),也可以是一个对象;
- Vue3.x: 必须是一个函数,否则浏览器中会报错。
const app = Vue.createApp({
data: function () {
return {
count: 0
}
},
})
methods属性
methods属性是一个对象,通常我们会在这个对象中定义很多的方法:
- 这些方法可以绑定到模板中
- 在这些方法中,我们可以使用this关键字来直接访问到data中返回的对象的属性
为什么不能使用箭头函数?
不应该使用箭头函数来定义method函数(例如:plus: () => this.a++)。
原因:箭头函数绑定了父级作用域的上下文,所以this将不会按照期望指向组件实例,this.a将是undefined。
<!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>
<h2>哈哈哈哈</h2>
<div id="app">
<h1>{{count}}</h1>
<button @click="increase">+</button>
<button @click="decrease">-</button>
</div>
<!--CDN地址-->
<script src="https://unpkg.com/vue@next"></script>
<script>
// 使用VUE
const app = Vue.createApp({
data: function () {
return {
count: 0
}
},
methods: {
increase: () => console.log(this),
// decrease: function () { this.count--}
},
})
// 挂在
app.mount("#app")
</script>
</body>
</html>
this到底指向了什么?
事实上Vue的源码当中就是对methods中所有函数进行了遍历,并且通过bind绑定了this:
<!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>
<h2>哈哈哈哈</h2>
<div id="app">
<h1>{{count}}</h1>
<button @click="increase">+</button>
<button @click="decrease">-</button>
</div>
<!--CDN地址-->
<script src="https://unpkg.com/vue@next"></script>
<script>
// 使用VUE
const app = Vue.createApp({
data: function () {
return {
count: 0
}
},
methods: {
increase: function () { console.log(this)},
decrease: function () { this.count--}
},
})
// 挂在
app.mount("#app")
</script>
</body>
</html>
computed属性
总体来说,methods和computed使用上差不多,但是需要主要的是computed是有缓存的。下面这个例子中computed和methods的方法同样是引入了三次,但是computed的方法只调用了一次。
注意:computed必须要有返回值
<!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>
<style>
[v-cloak] {
display: none;
}
</style>
</head>
<body>
<div id="app">
<h1>{{ cFullName }}</h1>
<h1>{{ cFullName }}</h1>
<h1>{{ cFullName }}</h1>
<h1>{{ fullName() }}</h1>
<h1>{{ fullName() }}</h1>
<h1>{{ fullName() }}</h1>
</div>
<!--CDN地址-->
<script src="https://unpkg.com/vue@next"></script>
<script>
// 使用VUE
const app = Vue.createApp({
data: function () {
return {
name: '三',
firstName: '张',
}
},
methods: {
fullName () {
console.log('methods调用了')
return this.firstName + this.name
}
},
computed: {
cFullName () {
console.log('计算属性调用了')
return this.firstName + this.name
}
}
})
// 挂在
app.mount("#app")
</script>
</body>
</html>
computed语法格式
<!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>
<style>
[v-cloak] {
display: none;
}
</style>
</head>
<body>
<div id="app">
<h1>{{ cFullName }}</h1>
<button @click="changeName">改变名字</button>
</div>
<!--CDN地址-->
<script src="https://unpkg.com/vue@next"></script>
<script>
// 使用VUE
const app = Vue.createApp({
data: function () {
return {
name: ['三', '张']
}
},
methods: {
changeName () {
this.cFullName = '李四'
}
},
computed: {
// 语法糖的写法
// cFullName () {
// console.log('计算属性调用了')
// return this.firstName + this.name
// }
// 完整写法
cFullName: {
get: function () {
return this.name[0] + this.name[1]
},
set: function (value) {
console.log(value)
const arr = value.split('')
this.name[0] = arr[0]
this.name[1] = arr[1]
}
}
}
})
// 挂在
app.mount("#app")
</script>
</body>
</html>
监听器watch
开发中我们在data返回的对象中定义了数据,这个数据通过插值语法等方式绑定到template中;当数据变化时,template会自动进行更新来显示最新的数据;但是在某些情况下,我们希望在代码逻辑中监听某个数据的变化,这个时候就需要用监听器watch来完成了。
<!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>
<style>
[v-cloak] {
display: none;
}
</style>
</head>
<body>
<div id="app">
<h1>{{ fullName.name }}</h1>
<button @click="changeName">改变名字</button>
</div>
<!--CDN地址-->
<script src="https://unpkg.com/vue@next"></script>
<script>
// 使用VUE
const app = Vue.createApp({
data: function () {
return {
fullName: {name: '张三'}
}
},
methods: {
changeName () {
this.fullName = {name: '李四'}
}
},
watch: {
// 监听函数的名字和所监听的属性名字一致
// 默认不进行深度监听
fullName (newValue, oldValue) {
console.log(newValue)
console.log(oldValue)
},
// 进行深度监听
// fullName: {
// handler (newValue, oldValue) {
// },
// // 开启深度监听
// deep: true,
// // 第一次渲染直接执行一次监听器
// immediate: true
// }
// 只监听对象的某个属性
"fullName.name" (newValue, oldValue) {
}
}
})
// 挂在
app.mount("#app")
</script>
</body>
</html>