一、创建项目
1.先要安装node.js 16以上的版本
安装成功后查看版本:node -v
2.在要创建vue项目的文件夹中运行命令:
npm init vue@latest
此命令用于创建一个使用最新版本Vue.js的项目
3.在“Project name: ...”后面给项目命名为“vue-base”(小写)
Project name: ... vue-base
4.进入创建好的项目:
cd vue-base
5.在项目中安装所需的依赖包:
npm install 或者 cnpm install(这个快)
6.运行项目:
npm run dev
7.运行之后,会看到一个地址,在浏览器能访问这个地址,就说明vue项目创建好了
Local: http://localhost:5173/
二、开发工具
1.选择合适的开发工具
2.Vue前端开发一般使用vscode + Volar插件,但我是后端开发人员,所以用的idea
三、目录结构
认识Vue项目的目录结构
刚刚创建好的“vue-base”项目,在idea中打开是这样的:
这些文件的作用
.vscode VSCode工具的配置文件
node_modules Vue项目的运行依赖文件
public 资源文件夹(浏览器图标)
src 源码文件夹
.gitignore git忽略文件
index.html 入口HTML文件
package.json 信息描述文件
package-lock.json 确保项目在不同环境中都能复现相同的结果
README.md 注释文件
vite.config.js Vue配置文件
四、模板语法
1.文本插值
删除一些文件,来试着写一个纯净的案例
- 新建一个vue项目
- 删除components文件夹中的所有内容
- 删除main.js中的:import ‘./assets/main.css’
- 在App.vue中写以下代码:
<template>
<h3>模板语法</h3>
<p>{{ msg }}</p>
</template>
<script>
export default {
data() {
return {
msg: "vue语法"
}
}
}
</script>
浏览器运行效果:
2.使用JavaScript表达式
<template>
<h3>模板语法</h3>
<!--1.文本插值-->
<p>{{ msg }}</p>
<!--2.使用JavaScript表达式-->
<!--简单运算-->
<p>{{ num + 3}}</p>
<!--三目运算-->
<p>{{ ok ? '没毛病' : '有毛病'}}</p>
<!--空字符串切割-反转-合并-->
<p>{{message.split("").reverse().join("")}}</p>
</template>
<script>
export default {
data() {
return {
msg: "vue语法",
num:10,
ok:true,
message:'大家好'
}
}
}
</script>
无效
<!--这是一个语句,而非表达式-->
{{ var a = 1 }}
<!--不支持条件控制,请使用三元表达式-->
{{ if (ok) {return message }}}
3.原始html
<template>
<!--原始html-->
<!--文本-->
<p>{{ rawHtml}}</p>
<!--链接-->
<p v-html="rawHtml"></p>
</template>
<script>
export default {
data() {
return {
rawHtml:"<a href='https://www.baidu.com/'>茶碗儿学Vue</a>"
}
}
}
</script>
浏览器效果
4.属性绑定
<template>
<!--属性绑定-->
<div v-bind:id="dynamicId" v-bind:class="dynamicClass" :title="dynamicTitle">{{ msg }}</div>
<!--isButtonDisabled为true时,不可点击-->
<button :disabled="isButtonDisabled">这是按钮</button>
<!--绑定对象-->
<div v-bind="arrObject">绑定对象</div>
</template>
<script>
export default {
data() {
return {
msg: "这是HelloWord文件",
dynamicClass: "appClass",
dynamicId: "appId",
dynamicTitle:null,
isButtonDisabled:true,
// 对象
arrObject:{
class: "arrClass",
id: "arrId"
}
}
}
}
</script>
<style>
.appClass {
color: red;
}
</style>
浏览器效果
注意:
- 属性绑定时,v-bind可以省略不写
- 属性绑定的值为null或者undefined时,会自动忽略
5.条件渲染
- v-if
- v-else
- v-else-if
- v-show
1. v-if
指令表达式返回为真的时候才会被渲染
案例:
<template>
<h3>条件渲染</h3>
<!--v-if为true时显示-->
<div v-if="flag">v-if测试</div>
</template>
<script>
export default {
data() {
return {
flag: true
}
}
}
</script>
浏览器效果
2. v-else,v-else-if,v-show
- v-if:为假的时候,才返回v-else
- v-else-if:相当于“else if”,可以连续多次重复使用
- v-show:跟v-if用法一样,为真时显示,为假时不显示
案例:
<template>
<h3>条件渲染</h3>
<!--v-if为true时显示-->
<div v-if="flag">v-if测试</div>
<!--v-if为false时显示这条内容-->
<div v-else>v-else测试</div>
<!--v-else-if案例-->
<div v-if="type==='A'">A</div>
<div v-else-if="type==='B'">B</div>
<div v-else-if="type==='C'">V</div>
<div v-else>It's D,Not A/B/C</div>
<!--v-show案例-->
<div v-show="vsFlag">v-show测试</div>
</template>
<script>
export default {
data() {
return {
flag: false,
type:"D",
vsFlag:true
}
}
}
</script>
浏览器效果
3. v-if和v-show的区别
- 1.控制手段不同:v-show隐藏则是为该元素添加css–display:none,dom元素依旧还在。v-if显示隐藏是将dom元素整个添加或删除。
- 2.编译过程不同:v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件;v-show只是简单的基于css切换。
- 3.编译条件不同:v-if是真正的条件渲染,它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。只有渲染条件为假时,并不做操作,直到为真才渲染。v-show由false变为true的时候不会触发组件的生命周期。
- 4.性能消耗不同:v-if有更高的切换消耗;v-show有更高的初始渲染消耗。
- 5.用途不同:v-if更适合于带有权限的操作,渲染时判断权限数据。v-show更适合于日常使用,可以减少数据的渲染,减少不必要的操作。
4. v-if和v-show的使用场景
v-if和v-show虽然看起来很相似,但是它们的使用方法和场景是有很大区别的。
- v-if适合用在数据不会频繁切换的场景。
- v-show适合用在数据会频繁切换的场景。
6.列表渲染
v-for的作用
- 遍历数组中的元素
- 遍历对象中的属性
1. 遍历数组中的元素
使用 v-for 指令基于数组来渲染一个列表
- 值需要使用 item in items 形式的语法(in可以写成of)
- 此时item代表数组中的一个元素,items代表数组
v-for 也支持使用可选的第二个参数表示当前项的索引
- (item,index) in items index表示索引下标
案例1
<template>
<h3>列表渲染</h3>
<!--遍历数组-->
<p v-for="name in names">{{ name }}</p>
<!--遍历元素是对象的数组-->
<div v-for="user in result">
<p>{{ user.id }}-{{ user.address }}-{{ user.say }}</p>
</div>
</template>
<script>
export default {
data() {
return {
names: ["张大仙", "马保国", "蔡徐坤", "沙悟净", "流川枫"],
result: [
{
"id": 10,
"address": "杭州",
"say": "亚运会"
},
{
"id": 13,
"address": "北京",
"say": "村委会"
},
{
"id": 21,
"address": "上海",
"say": "刘奶奶喝牛奶"
},
{
"id": 35,
"address": "杭州",
"say": "不抽烟不喝酒"
},
{
"id": 61,
"address": "杭州",
"say": "饿了就吃饭"
}
]
}
}
}
</script>
浏览器效果
案例2
<template>
<!--数组:names
元素:name
索引:index-->
<!--遍历数组时,展示索引-->
<div v-for="(name,index) in names">
<p>{{ index }}:{{ name }}</p>
</div>
</template>
<script>
export default {
data() {
return {
names: ["张大仙", "马保国", "蔡徐坤", "沙悟净", "流川枫"]
}
}
}
</script>
浏览器效果
2. 遍历对象中的属性
v-for 也可以遍历一个对象的所有属性
- 使用 item in items 形式的语法(in可以写成of)
- 此时item代表对象中的一个属性,items代表对象
案例
<template>
<!--遍历对象中的属性-->
<!--对象:user 属性:item-->
<p v-for="item of user">{{ item }}</p>
<!--对象:user 键:key 值(属性):value 索引:index-->
<p v-for="(value,key,index) of user">{{ index}}:{{ key }}-{{value}}</p>
</template>
<script>
export default {
data() {
return {
user: {
name: "林雨薇",
age: "1999年5月2日",
sex: "女"
}
}
}
}
</script>
浏览器效果
五、在html中使用语法
1.一个案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- CDN方式,引入Vue3 -->
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
<div id="app">
<!-- 响应式文本 -->
<p>{{ message }}</p>
<!-- 静态文本 -->
<p>{{ msg }}</p>
<!-- 方法调用 -->
<p>{{ cc() }}</p>
<!-- 计算属性缓存 -->
<p>{{ aa }}</p>
</div>
<script>
// 必须写:创建应用,响应式数据
const { createApp, ref } = Vue
createApp({
setup() {
//响应式数据
const message = ref('Hello Vue3!')
return {
message,
//静态文本
msg:"茶碗儿学Vue3",
//方法
cc(){
console.log("这是一个方法")
return "方法被调用"
}
}
},
// 计算属性在这里面写
computed: {
aa(){
console.log('本事要大,脾气要小')
return "计算属性被计算"
}
}
}).mount('#app')
</script>
</body>
</html>
浏览器效果
2.代码写在视图中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<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">
<!-- 事件调用 -->
<button @click="hello">{{message}}</button><br>
<button @click="study('Vue3')">{{msg}}</button>
<!-- 拆分字符串为字符数组:[ "学", "习" ] -->
<P>拆分字符串为字符数组:{{msg.split('')}}</P>
<!-- 反转字符串数组:[ "学", "习" ] -->
<P>反转字符数组:{{msg.split('').reverse()}}</P>
<!-- 字符数组转为字符串:习,学 -->
<P>字符数组转为字符串:{{msg.split('').reverse().join('')}}</P>
<!-- 缺点:大量代码逻辑写在视图中,页面代码不简洁 -->
</div>
<script>
const { createApp, ref } = Vue
createApp({
setup() {
//响应式数据
const message = ref('点击')
return {
message,
//静态数据
msg:"学习",
//方法
hello(){
alert("WOC,Vue3真难……")
},
study(str){
alert(str+"真令人头大……")
}
}
}
}).mount('#app')
</script>
</body>
</html>
解决:大量代码逻辑写在视图中,页面代码不简洁
- 方法:缺点【多次使用会重复调用方法】
- 计算属性:优点【多次调用也只执行一次】
3.代码写在方法和计算属性中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<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">
<!-- 方法 -->
<p>方法:{{reversed()}}</p>
<p>方法:{{reversed()}}</p>
<p>方法:{{reversed()}}</p>
<!-- 计算属性 调用时不写方法小括号-->
<p>计算属性:{{reversedMsg}}</p>
<p>计算属性:{{reversedMsg}}</p>
<p>计算属性:{{reversedMsg}}</p>
</div>
<script>
const { createApp, ref } = Vue
createApp({
setup() {
//响应式数据
const message = ref('好好学习')
return {
message,
//方法
reversed(){
console.log('reversed()方法被调用')
return this.message.split('').reverse().join('')
}
}
},
// 计算属性
computed: {
//在计算属性里面写方法,多次调用也只执行一次
reversedMsg(){
console.log('reversedMsg()计算属性被计算')
return this.message.split('').reverse().join('')
}
}
}).mount('#app')
</script>
</body>
</html>
查看控制台
4.计算属性的setter和getter
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- CDN方式,引入Vue3 -->
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
<div id="app">
<!-- v-model:双向绑定 -->
姓:{{firstName}}<input type="text" v-model="firstName"><br>
名:{{lastName}}<input type="text" v-model="lastName"><br>
全名:{{fullName}}<input type="text" v-model="fullName"><br>
</div>
<script>
const { createApp, ref } = Vue
createApp({
//data.return
setup() {
//响应式数据
const firstName = ref('迈克尔')
const lastName = ref('乔丹')
return {
firstName,
lastName
}
},
// 计算属性在这里面写
computed: {
//计算属性的setter和getter
fullName:{
set(value){
console.log("运行fullName计算属性的set方法,fullName="+value)
// 将fullName通过-分割后,再传给firstName和lastName
const names = value.split("-")
this.firstName = names[0]
this.lastName = names[1]
},
get(){
console.log("运行fullName计算属性的get方法")
return this.firstName+"-"+this.lastName;
}
}
}
}).mount('#app')
</script>
</body>
</html>
5.监听
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- CDN方式,引入Vue3 -->
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
<div id="app">
姓:{{firstName}}<input type="text" v-model="firstName"><br>
名:{{lastName}}<input type="text" v-model="lastName"><br>
全名:{{fullName}}<input type="text" v-model="fullName"><br>
</div>
<script>
const { createApp, ref } = Vue
createApp({
setup() {
const firstName = ref('迈克尔')
const lastName = ref('乔丹')
const fullName = ref('')
return {
firstName,
lastName,
fullName
}
},
// 监听
watch: {
// firstName变化时执行
firstName(value){
// firstName变化时打印
console.log("firstName变化:"+value)
// 此时的fullName为
this.fullName = value + "-" + this.lastName
},
// lastName变化时执行
lastName(value){
// lastName变化时打印
console.log("lastName变化:"+value)
// 此时的fullName为
this.fullName = this.firstName + "-" + value
},
// fullName变化时执行
fullName(value){
// 将fullName通过-分割后,再给到firstName和lastName
const names = value.split("-")
this.firstName = names[0]
this.lastName = names[1]
}
}
}).mount('#app')
</script>
</body>
</html>
6.条件渲染
需求:如果复选框被勾选,则能点击"确定按钮",反之则不能点击"确定"按钮
- 方式一:v-if, v-else (删除 / 创建节点)
- 方式二:v-show (隐藏 / 展示节点)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<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">
<!-- 方式一: v-if,v-else -->
<!-- 复选框 -->
<input type="checkbox" v-model="ok">是否同意许可?<br>
<!-- 条件渲染 disabled表示不能被操作(禁用表单元素) -->
<button v-if="ok">确定</button>
<button v-else disabled>确定</button>
<br>
<br>
<!-- 方式二: v-show -->
<input type="checkbox" v-model="ok1">是否同意许可?<br>
<button v-show="ok1">确定</button>
<button v-show="!ok1" disabled>确定</button>
</div>
<script>
const { createApp, ref } = Vue
createApp({
setup() {
//设置响应式数据的初始值
const ok = ref(false)
const ok1 = ref(false)
return {
ok,
ok1
}
}
}).mount('#app')
</script>
</body>
</html>
7.列表渲染
- 遍历数组
- 遍历对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<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">
<!--遍历数组-->
<p v-for="name in names">{{ name }}</p>
<!-- 遍历对象 -->
<!-- 格式:item in items -->
<!-- 带索引的格式:(item,index) in items -->
<ul>
<li v-for="(user,index) in result">
{{index+1}},{{ user.id }},{{ user.address }},{{ user.say }}
</li>
</ul>
</div>
<script>
const { createApp} = Vue
createApp({
setup() {
return {
// 数组
names: ["张大仙", "马保国", "蔡徐坤", "沙悟净", "流川枫"],
// 对象
result: [
{
"id": 10,
"address": "杭州",
"say": "亚运会"
},
{
"id": 13,
"address": "北京",
"say": "村委会"
},
{
"id": 21,
"address": "上海",
"say": "刘奶奶喝牛奶"
},
{
"id": 35,
"address": "杭州",
"say": "不抽烟不喝酒"
},
{
"id": 61,
"address": "杭州",
"say": "饿了就吃饭"
}
]
}
}
}).mount('#app')
</script>
</body>
</html>
8.实例生命周期
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<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">
<h1 id="msg">{{message}}</h1>
</div>
<script>
const { createApp, ref } = Vue
createApp({
setup() {
const message = ref('我爱油泼面')
return {
message,
// 方法可以在这里写
add(){
console.log("访问add方法")
}
}
},
// 方法可以在这里写
methods: {
show(){
console.log('访问show方法')
}
},
// 创建完成
// 先执行,可以访问到数据模型,可以访问到成员方法
created () {
console.log('vue实例创建完成')
console.log('created中获取message的定义:'+this.message)
this.show()
this.add()
// 没有被渲染到页面上,所以无法获取到元素内容
// 遗留问题:预期获取不到元素,但应该会打印"{{message}}",但其实会报错,这块我还不知道为什么
console.log("created中获取元素内容:"+document.getElementById("msg").innerText)
},
// 渲染完成
// 后执行,可以访问到数据模型,可以访问到成员方法
mounted () {
console.log('vue页面渲染完成')
console.log('mounted中获取message的定义:'+this.message)
this.show()
this.add()
// 页面渲染完成,可以获取到元素
console.log("mounted中获取元素内容:"+document.getElementById("msg").innerText)
}
}).mount('#app')
</script>
</body>
</html>