vueopen in new window vue.jsopen in new window

一、快速开始

1.1 环境安装

# 安装nodejs
npm -v

# 安装yarn
# npm install -g yarn

# 安装vue
npm install vue -g

# 安装vue-cli
npm install -g @vue/cli

1.2 创建 vue 项目

$ npm create vue@latest

Vue.js - The Progressive JavaScript Framework

✔ 请输入项目名称: … vue-book
✔ 是否使用 TypeScript 语法? … 否 / 是
✔ 是否启用 JSX 支持? … 否 / 是
✔ 是否引入 Vue Router 进行单页面应用开发? … 否 / 是
✔ 是否引入 Pinia 用于状态管理? … 否 / 是
✔ 是否引入 Vitest 用于单元测试? … 否 / 是
✔ 是否要引入一款端到端(End to End)测试工具? › 不需要
✔ 是否引入 ESLint 用于代码质量检测? … 否 / 是
✔ 是否引入 Prettier 用于代码格式化? … 否 / 是
✔ 是否引入 Vue DevTools 7 扩展用于调试? (试验阶段) … 否 / 是
$ npm init vue@latest

Vue.js - The Progressive JavaScript Framework

✔ Project name: … `vue-admin`
✔ Add TypeScript? … No / `Yes`
✔ Add JSX Support? … `No` / Yes
✔ Add Vue Router for Single Page Application development? … No / `Yes`
✔ Add Pinia for state management? … `No` / Yes
✔ Add Vitest for Unit Testing? … `No` / Yes
✔ Add an End-to-End Testing Solution? › `No` / Yes
✔ Add ESLint for code quality? … No / `Yes`
✔ Add Prettier for code formatting? … No / `Yes`
# 1.使用 vue-cli 命令行创建
vue create <vue-project>

# 2.使用网页图形化界面创建
vue ui

# 3.使用 vite 创建
yarn create vite <project-name> --template vue

1.3 项目结构

├── public
│   ├── favicon.ico
│   └── index.html
└── src

1.4 vue 组件

<script>
export default {
  data() {
    return {
      count: 0
    }
  },
  methods: {
    increment() {
      this.count++
    }
  },
  mounted() {
    this.increment()
  }
}
</script>

Overview

元素渲染

元素渲染
<template>
	<div>Counter: {{ count }}</div>
</template>

<script>
export default {
	data: () => ({
		count: 0,
	}),
}
</script>

<style></style>

列表渲染

列表渲染
<template>
	<div id="list-rendering">
		<ul>
			<li v-for="item in list">{{ item }}</li>
		</ul>
	</div>
</template>

<script>
export default {
	data() {
		return {
			list: ["JavaScript", "Vue", "React"],
		}
	},
}
</script>

<style></style>

对象渲染

对象渲染
<template>
	<div id="object-rendering">
		<ol>
			<li v-for="todo in todos" :key="todo.id">
				{{ todo.text }}
			</li>
		</ol>
	</div>
</template>

<script>
export default {
	data: () => ({
		todos: [
			{id: 0, text: "Learn JavaScript"},
			{id: 1, text: "Learn Vue"},
			{id: 2, text: "Build something awesome"},
		],
	}),
}
</script>

<style></style>

vue-data

vue-data.vue
<template>
	<div>{{ message }}</div>
</template>

<script>
export default {
	data() {
		return {
			message: "You loaded this page on " + new Date().toLocaleString(),
		}
	},
	/*
  data: () => ({
    count: 0,
  })
  */
}
</script>

<style></style>

vue-methods

vue-methods.vue
<template>
	<div id="event-handling">
		<p>{{ message }}</p>
		<button @click="reverseMessage">反转 Message</button>
	</div>
</template>

<script>
export default {
	data() {
		return {
			message: "Hello Vue.js!",
		}
	},
	methods: {
		reverseMessage() {
			this.message = this.message.split("").reverse().join("")
		},
	},
}
</script>

<style>
button {
	padding: 10px;
	font-size: 1rem;
	border: 1px solid #323232;
	background: transparent;
	cursor: pointer;
	transition: all 0.3s ease;
}
button:hover {
	background: #323232;
	color: #f8f8f8;
}
</style>

vue-bind

<div :class="['progress-color', color]"></div>
<div :style="{width: item.amount, background: item.color}"></div>
<!-- 连接 -->
<img :src="['/src/assets/icons/' + icon]" alt="" />

vue-bind.vue
<template>
	<div id="vue-bind">
		<span :title="message">鼠标悬停几秒钟查看此处动态绑定的提示信息!</span>
	</div>
</template>

<script>
export default {
	data() {
		return {
			message: "You loaded this page on " + new Date().toLocaleString(),
		}
	},
}
</script>

<style></style>

vue-for

vue-for-list.vue
<template>
	<ul>
		<li v-for="(item, index) in list" :key="index">{{ item }}</li>
	</ul>
</template>

<script>
export default {
	data() {
		return {
			list: ["JavaScript", "Vue", "React"],
		}
	},
}
</script>

<style></style>
vue-for-object.vue
<template>
	<div id="list-rendering">
		<ol>
			<li v-for="(item, index) in todos" :key="index">
				{{ item.text }}
			</li>
		</ol>
	</div>
</template>

<script>
export default {
	data() {
		return {
			todos: [
				{id: 0, text: "Learn JavaScript"},
				{id: 1, text: "Learn Vue"},
				{id: 2, text: "Build something awesome"},
			],
		}
	},
}
</script>

<style></style>

vue-template

vue-temp
<script>
export default {
	data: () => ({
		branches: ["main", "v2-compat"],
		currentBranch: "main",
	}),
}
</script>

<template>
	<template v-for="branch in branches">
		<input type="radio" :id="branch" :value="branch" name="branch" v-model="currentBranch" />
		<label :for="branch">{{ branch }}</label>
	</template>
	<p>vuejs/vue@{{ currentBranch }}</p>
</template>
vue-temp-2
<template>
	<ol>
		<TodoItem v-for="item in groceryList" :todo="item" :key="item.id"></TodoItem>
	</ol>
</template>

<script>
import TodoItem from "./TodoItem.vue"

export default {
	components: {
		TodoItem,
	},
	data() {
		return {
			groceryList: [
				{id: 0, text: "Vegetables"},
				{id: 1, text: "Cheese"},
				{id: 2, text: "Whatever else humans are supposed to eat"},
			],
		}
	},
}
</script>
<!-- TodoItem.vue -->
<script>
export default {
	props: {
		todo: Object,
	},
}
</script>

<template>
	<li>{{ todo.text }}</li>
</template>

vue-model

vue-model.vue
<template>
	<div id="two-way-binding">
		<p>{{ message }}</p>
		<input v-model="message" />
	</div>
	<!-- onChange -->
</template>

<script>
export default {
	data() {
		return {
			message: "Hello Vue.js!",
		}
	},
}
</script>

<style>
input {
	outline: none;
	padding: 10px 5px;
	/* border-radius: 30px; */
	border: 1px solid rgba(32, 32, 32, 0.3);
	letter-spacing: 1px;
	width: 300px;
	transition: all 0.3s ease;
}
input:focus {
	border-color: #323232;
}
</style>

vue-if

vue-if.vue
<template>
	<div id="conditional-rendering">
		<span v-if="seen">现在你看到我了</span>
	</div>
</template>

<script>
export default {
	data() {
		return {
			seen: true,
		}
	},
}
</script>

<style></style>

vue-fetch

vue-fetch
<script>
const API_URL = `https://api.github.com/repos/vuejs/core/commits?per_page=3&sha=`

export default {
	data: () => ({
		branches: ["main", "v2-compat"],
		currentBranch: "main",
		commits: null,
	}),

	created() {
		// 在初始化的时候进行获取
		this.fetchData()
	},

	watch: {
		// 当 currentBranch 改变时重新获取
		currentBranch: "fetchData",
	},

	methods: {
		async fetchData() {
			const url = `${API_URL}${this.currentBranch}`
			this.commits = await (await fetch(url)).json()
		},
		truncate(v) {
			const newline = v.indexOf("\n")
			return newline > 0 ? v.slice(0, newline) : v
		},
		formatDate(v) {
			return v.replace(/T|Z/g, " ")
		},
	},
}
</script>

<template>
	<h1>Latest Vue Core Commits</h1>
	<template v-for="branch in branches">
		<input type="radio" :id="branch" :value="branch" name="branch" v-model="currentBranch" />
		<label :for="branch">{{ branch }}</label>
	</template>
	<p>vuejs/vue@{{ currentBranch }}</p>
	<ul>
		<li v-for="{html_url, sha, author, commit} in commits">
			<a :href="html_url" target="_blank" class="commit">{{ sha.slice(0, 7) }}</a>
			-
			<span class="message">{{ truncate(commit.message) }}</span>
			<br />
			by
			<span class="author">
				<a :href="author.html_url" target="_blank">{{ commit.author.name }}</a>
			</span>
			at
			<span class="date">{{ formatDate(commit.author.date) }}</span>
		</li>
	</ul>
</template>

<style>
a {
	text-decoration: none;
	color: #42b883;
}
li {
	line-height: 1.5em;
	margin-bottom: 20px;
}
.author,
.date {
	font-weight: bold;
}
</style>

@click

<script>
export default {
  data() {
	  return {
    	counter: 0
  	}
	}
}
</script>

<template>
	<button @click="counter++">Add 1</button>
	<p>The button above has been clicked {{ counter }} times.</p>
</template>

组建通信

传参

父组件向子组件传递参数

<template>
	<!-- 传参 -->
	<chart-circle :percent="80" :color="{circle_color: '#00cfde', circle_bg: '#557b88'}"></chart-circle>
</template>
<script>
export default {
	props: {
		percent: Number, // 数字
		message: String, // 字符串
		flag: Boolean, // 布尔值
		arr: Array, // 数组
		color: Object, // 对象
	},
}
</script>

参数默认值

未传参时使用参数默认值

<template>
	<!--  没有传参时使用默认值 -->
	<chart-circle :percent="80"></chart-circle>
</template>
<script>
export default {
	props: {
		percent: {
			type: Number,
			required: true,
			// 设置默认值
			default: () => 20,
		}
		message: String,
		flag: Boolean,
		arr: Array,
		color: {
			type: Object,
			required: false,
			// 设置默认值
			default: () => {
				return {
					circle_color: "#ff9f00",
					circle_bg: "#776547",
				};
			},
    	},
	}
}
</script>

组件别名导入

父组件

<template>
	<!-- 组件别名 -->

	<!-- <ChartCirCle /> -->
	<!-- <ChartCirCle></ChartCircle> -->
	<chart-circle></chart-circle>
</template>
<script setup>
import ChartCircle from "@/components/Chart/Circle.vue"
</script>

子组件

<!-- components/Circle.vue -->
<script>
export default {
	// 使用"chartCircle" 替代 "Circle"
	name: "ChartCircle",
}
</script>

应用案例

单行输入框

单行输入框
<template>
	<p>Message is: {{ message }}</p>
	<input v-model="message" placeholder="edit me" />
</template>

<script>
export default {
	data() {
		return {
			message: "",
		}
	},
}
</script>

多行文本框

多行文本框
<template>
	<p>Multiline message is: {{ message }}</p>
	<textarea v-model="message"></textarea>
</template>
<script>
export default {
	data() {
		return {
			message: "",
		}
	},
}
</script>

多选框

多选框
<template>
	<select v-model="selected">
		<option v-for="option in options" :value="option.value">
			{{ option.text }}
		</option>
	</select>
	<div>Selected: {{ selected }}</div>
</template>

<script>
export default {
	data() {
		return {
			selected: "A",
			options: [
				{text: "One", value: "A"},
				{text: "Two", value: "B"},
				{text: "Three", value: "C"},
			],
		}
	},
}
</script>

package

Vue-Router

  • lnzy-loaded
// method 1
const HomeView = () => import('@/views/HomeView.vue')
component: HomeView,

// method 2
component: () => import("@/views/AboutView.vue"),
  • build history

build 之后出现页面空白

// router/index.js
import {createRouter, createWebHistory, createWebHashHistory} from "vue-router"
// import HomeView from '@/views/HomeView.vue'
const HomeView = () => import("@/views/HomeView.vue")

const router = createRouter({
	// history: createWebHistory(import.meta.env.BASE_URL),
	// build 环境
	history: createWebHashHistory("./"),
	routes: [
		{
			path: "/",
			name: "home",
			component: HomeView,
		},
		{
			path: "/about",
			name: "about",
			// which is lazy-loaded when the route is visited.
			component: () => import("@/views/AboutView.vue"),
		},
	],
})

export default router
<script>
import {RouterLink, RouterView} from "vue-router"
</script>

<template>
	<nav>
		<RouterLink to="/">Home</RouterLink>
		<RouterLink to="/about">About</RouterLink>
	</nav>
	<RouterView />
</template>
// vite.config.js
base: "./"

path

// main.js
import router from './router'
app.use(router)
import path from 'path'


resolve: {
	alias: {
		"@": path.resolve(__dirname, "./src"),
	},
},

Router

// router/index.js
import {createRouter, createWebHashHistory} from "vue-router";
import routes from "./routes";



const router = createRouter({
  history: createWebHashHistory(),
  routes,
});

vue3.2

vue-ref
<template>
	<div>Counter: {{ count }}</div>
</template>

<script setup>
import {ref} from 'vue'
const count = ref(0)
</script>

<script setup>
// import
import {ref} from 'vue'

// 定义变量
const count = ref(0)
// 修改变量
count.value = 1

// 定义新变量
// const doubleCount = computed(() => count.value * 2);

// 定义函数
function incrementCount() {
	count.value++
}

// v-model
const text = ref('')
</script>


<template>
	<!-- 使用变量 -->
	<div>Counter: {{ count }}</div>
	<!--
	<div>{{doubleCount}}</div>
	-->
	<button @click="incrementCount">Click me +1</button>
	<p>{{ text }}</p>
	<input v-model="text" placeholder="Type here">
</template>