一、开发环境
1.通过CDN引入(暴露了全局的vue类对象)
- 全局构建版本:
这个类对象提供了一个createApp()方法,用来创建一个vue应用
<head>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
<div id="app"></div>
<script>
const { createApp } = Vue // 对象解构
</script>
</body>
- ES模块构建版本:
<script type="module">
import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
</script>
2.工程构建
在命令行中运行 npm create vue@latest
二、创建应用示例
通过createApp()方法创建一个vue应用,通过mount()方法挂载到指定div节点下显示
data选项(函数方法) - 定义数据,返回的属性将会成为响应式的状态
methods选项 - 定义方法,是一些用来更改状态与触发更新的函数
template选项 - 定义模板
为方便vue各选项的理解,这里用template选项定义模板(去vcsode应用商店安装es6-string-html扩展,在template选项上方加/html/注释),也可直接写入到div标签中
<!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>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
<div id="app"></div>
<script>
//方法一
// const app = Vue.createApp({// 创建vue应用
// data() {
// return {
// message: 'helloworld' //定义数据模型
// }
// },
// template: `<p>{{message}}</p>` // 定义模板 模板文本插值语法 {{ }}
// })
// app.mount('#app')// 挂载到指定div节点下显示
//方法二
const { createApp } = Vue // 对象解构
// 根组件(组件本质是有指定选项属性的javascript对象)
const root = {
data() {
return {
message: 'helloworld', //定义数据模型
}
},
/*html*/
template: `<p>{{message}}</p>` // 定义模板 模板文本插值语法 {{ }}
}
createApp(root).mount('#app')// 创建vue应用并挂载到指定div节点下显示
</script>
</body>
</html>
三、基础语法
1. 文本插值
{{ 变量/表达式 }}
2. 指令(带有v-前缀的特殊属性)
2.1 操作内容文本
v-html 解析标签元素(innerHTML)
v-text 不解析标签元素(innerText)
v-pre vue不解析{{ }}
2.2 操作属性
v-bind:属性名=属性值(setAttribute(属性名,属性值),getAttribute(属性名))
:属性名=属性值(简写形式)
2.3 操作样式
:class=”字符 / 对象{样式:控制样式变量} / 数组[,]”(class="")
2.4 操作事件
v-on:事件类型=事件处理函数(onclick="")
@事件类型=事件处理函数(简写形式)
2.5 v-if和v-show
v-if和v-show区别:
v-if 动态添加移除dom节点(满足条件渲染dom节点,不满足不渲染)
v-show 通过css样式display控制dom节点隐藏显示(本质是css样式的 display: none/block)
2.6 列表渲染v-for
(v-for要绑定key,以便虚拟dom diff算法能够快速找到列表项,对列表项进行高效操作)
不建议v-for与v-if合用:
v-for会比v-if优先执行,如果一起用会造成性能浪费,可以v-for外嵌套v-if
如果v-for内嵌套v-if,可以先用计算属性computed过滤遍历数组,再用v-for,优化性能
2.7 表单数据双向绑定v-model
:value="" @input=""/v-model(通过event.target.value获取输入框的值)
2.8 v-cloak 性能优化,用于隐藏未完成编译的DOM模板
网速比较慢或者加载东西比较多时,可能会出现未编译模板闪现情况,用户可能看到还没编译完成的双大括号标签。
v-cloak 会保留在所绑定的元素上,直到相关组件实例被挂载后才移除。配合像[v-cloak]{display:none}这样的CSS规则,它可以在组件编译完毕前隐藏原始模板。
<style>
[v-cloak]{display:none}
</style>
<div v-cloak></div>
3. 指令修饰符模板语法
3.1表单修饰符
number将输入框内容转换为number类型
trim去除前后空格
lazy懒加载,input事件替换成change事件(不是输入时触发,而是输入完成时触发)
<input v-model.lazy="msg" >
3.2事件修饰符
prevent阻止默认行为(链接跳转、表单提交/event.preventDefault())
stop阻止事件传播(事件冒泡、事件捕获)
passive滚动事件的默认行为 (scrolling) 将立即发生,而非等待 onScroll 完成。( 不能同时使用.passive 和 .prevent,因为 .passive 已经向浏览器表明了你不想阻止事件的默认行为。如果同时使用 .prevent 会被忽略,并且会报错。)
self仅当 event.target 是元素本身时才会触发事件处理器
capture添加事件监听器时,指向内部元素的事件,在被内部元素处理前,先被外部处理(事件捕获)
once点击事件最多被触发一次
3.3按键修饰符
enter/tab/delete (捕获“Delete”和“Backspace”两个按键)/esc/space/up/down/left/right
@keyup.enter="bindLogin"
<!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>模板语法</title>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<style>
.p1 {
width: 100px;
height: 100px;
background-color: skyblue;
}
.d1 {
color: pink;
}
.d2 {
background-color: rgb(43, 67, 226);
}
.d3{
width: 400px;
height: 400px;
background-color: skyblue;
}
.d4{
width: 200px;
height: 200px;
background-color: pink;
}
[v-cloak] {
display: none;
}
</style>
</head>
<body>
<div id="app"></div>
<script>
const { createApp } = Vue
const root = {
// 定义数据
data() {
return {
title: '文本插值',
num: 10,
isOk: true,
message: 'helloworld',
contenthtml: '<h1>v-html操作内容</h1>',
contenttext: '<h1>v-text操作内容</h1>',
url: 'http://www.baidu.com',
pic: 'https://img0.baidu.com/it/u=1705694933,4002952892&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1672160400&t=7153143fa69e03b8233f4d808da5c4b9',
onLine: 2, // 0 在线,1 隐身,2 离线
show: true,
list: [
{ id: 1001, name: 'javascript高级编程', price: 88.98 },
{ id: 1002, name: 'vue高级编程', price: 108.89 },
{ id: 1003, name: 'css高级编程', price: 68.89 },
],
modelmsg: '双向绑定',
state: false,
numberValue: '',
trimValue: '',
lazyValue: '',
}
},
// methods选项定义方法
methods: {
onAlert() {
alert('执行onAlert方法 >>>>');
},
// methods选项方法不能用箭头函数
bindInput() {
//this: vue实例对象
this.modelmsg = event.target.value
},
bindNumberConfirm() {
alert(typeof (this.numberValue))
console.log('this.numberValue ', this.numberValue, typeof (this.numberValue))
},
bindTrimConfirm() {
alert(this.trimValue)
console.log('this.trimValue ', this.trimValue)
},
bindBaidu() {
// event.preventDefault()
alert('bindBaidu>>>>')
console.log('bindBaidu>>>>')
},
bindSubmit() {
alert('bindSubmit >>>> ')
console.log('bindSubmit >>>> ')
},
bindStopOne(){
alert('bindStopOne >>>')
console.log('bindStopOne >>>')
},
bindStopTwo(){
alert('bindStopTwo >>>')
console.log('bindStopTwo >>>')
},
bindLogin(){
alert('bindLogin >>>')
console.log('bindLogin >>>')
},
},
// 定义模板
template: `<div v-cloak>
<p>----文本插值-----</p>
<h2>{{title}}</h2>
<p>{{ num+1 }}</p>
<p>{{ isOk?'YES':'NO' }}</p>
<p>{{ message.split('').reverse().join('') }}</p>
<p>----操作内容-----</p>
<p v-html="contenthtml"></p>
<p v-text="contenttext"></p>
<h2 v-pre>{{title}}</h2>
<p>----操作属性-----</p>
<a v-bind:href="url">百度</a>
<div><img :src="pic" alt="图片"/></div>
<p>----操作样式-----</p>
<p class="p1">操作样式字符</p>
<p v-bind:class="{'p1':isOk}">操作样式对象</p>
<p :class="['d1','d2']">操作样式数组</p>
<p>----操作事件-----</p>
<button v-on:click="onAlert">确定1</button>
<button @click="onAlert">确定2</button>
<p>----v-if和v-show-----</p>
<p v-if="onLine === 0">在线</p>
<p v-else-if="onLine === 1">隐身</p>
<p v-else>离线</p>
<p v-show="show">显示</p>
<p>----列表渲染v-for-----</p>
<table>
<tr>
<th>索引号</th>
<th>ID</th>
<th>名称</th>
<th>价格</th>
</tr>
<tr v-for="(item,index) in list ">
<td>{{ index}}</td>
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
<td>{{ item.price }}</td>
</tr>
</table>
<ul>
<li v-for="(item,index) in list" >{{index}} - {{item.id}} - {{item.name}} - {{item.price}}</li>
</ul>
<p>----表单数据双向绑定v-model-----</p>
<p>{{modelmsg}}</p>
<input type="text" :value="modelmsg" @input="bindInput"/>
<input type="text" v-model="modelmsg"/>
{{state?'yes':'no'}}
<input type="checkbox" v-model="state"/>
<p>----表单修饰符-----</p>
<p>{{ numberValue }}</p>
<input type="text" v-model.number="numberValue"> <button @click="bindNumberConfirm">确定</button>
<p>{{ trimValue }}</p>
<input type="text" v-model.trim="trimValue"> <button @click="bindTrimConfirm">确定</button>
<p>{{lazyValue}}</p>
<input type="text" v-model.lazy="lazyValue">
<p>----事件修饰符-----</p>
<a :href="url" @click.prevent="bindBaidu">百度</a>
<form :action="url" @submit.prevent="bindSubmit">
<input type="submit" value="提交">
</form>
<div class="d3" @click="bindStopOne">
<div class="d4" @click.stop="bindStopTwo">按钮1</div>
</div>
<p>----按键修饰符-----</p>
<input type="text" @keyup.enter="bindLogin"/>
</div>`
}
createApp(root).mount('#app')
</script>
</body>
</html>
四、计算属性computed
缓存计算的结果,依赖项变化重新计算(计算属性的值可以修改,要定义成对象形式,语法上用get、set写法,但要避免直接修改计算属性的值,一般是通过依赖项自动修改)
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>计算总价</title>
<script src="../lib/vue.global.js"></script>
</head>
<body>
<div id="app"></div>
<script>
const { createApp } = Vue
const root = {
data() {
return {
list: [
{ id: 1, name: 'js高级编程', price: 88.89 },
{ id: 2, name: 'vue高级编程', price: 118.88 },
]
}
},
methods: {
bindAddBook(){
let product = {id:3,name:'react高级编程',price:200}
this.list.push(product)
}
},
computed: {// computed声明时定义成方法,但本质上是一个属性,一定有一个返回值,在computed方法体中定义依赖,当依赖变化重新
totalPrice(){
// let sum = 0
// for(let i = 0; i < this.list.length; i++){
// let res = this.list[i]
// sum += res.price
// }
//累加方法 .reduce((previous, current) => {return previous + current.price}, 0)
let sum = this.list.reduce((previous, current) => previous + current.price, 0)
return sum.toFixed(2)
}
//计算属性的值可以修改,要定义成对象形式,语法上用get、set写法,但要避免直接修改计算属性的值。一般是通过依赖项自动修改
//fullName:{
//get(){return xx},
//set(newvalue){}
//}
/* html */
template: `<div>
<table>
<tr>
<th>序号</th>
<th>名称</th>
<th>价格</th>
</tr>
<tr v-for="item,index in list">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.price}}</td>
</tr>
</table>
<h2>总价: <span>{{totalPrice}}</span></h2>
<button @click="bindAddBook">添加商品</button>
</div>`
}
createApp(root).mount('#app')
</script>
</body>
</html>
五、侦听属性watch
侦听响应式数据的变化和一些非DOM元素改变,可以获取数据改变前后的值。
默认情况下,组件初次加载完毕不会调用watch侦听器。如果想让watch侦听器立即被调用,需要使用 immediate 选项。
watch:{
username(){},//函数形式
username:{//对象形式,立即执行
handler:(){},//固定写法,自动调用
immediate:true,
deep:true,//侦听的是个对象user:{name:’zc’,age:20},改变属性侦听不到,需要深度侦听
}
}
<!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>watch侦听器</title>
<script src="../lib/vue.global.js"></script>
</head>
<body>
<div id="app"></div>
<script>
const {createApp} = Vue
const App = {
data() {
return {
username:'jack',
keyword:'衣服',
user:{
name:'rose',
age:20
}
}
},
//侦听器
watch: {
username(newValue,oldValue){
console.log('newValue ',newValue, ' oldValue',oldValue);
},
keyword:{
// handler是固定写法,侦听器触发执行的方法。表示当keyword值变化自动调用handler处理函数,
handler(newValue,oldValue){
console.log('keyword newValue ',newValue, ' oldValue',oldValue);
},
// 立即执行
immediate:true
},
user:{
handler(newValue,oldValue){
console.log('user newValue ',newValue, ' oldValue',oldValue);
},
// 深度侦听
deep:true
}
},
/* html */
template:`<div>
<h2>watch侦听器</h2>
</div>`
}
const app = createApp(App).mount('#app')
</script>
</body>
</html>