技术选型
vue
组合式API
单文件组件
语法
typescript
构建工具
vite
路由
vue-router
共享存储
pinia
视图组件
Ant Design Vue
快速上手 - Ant Design Vue (antdv.com)
创建一个 Vue 应用
#安装脚手架 (项目名不能有大写)
npm init vite@latest / vue@latest
#进入项目文件
cd <your-project-name>
#安装依赖
npm/cnpm install
#启动开发服务器
npm run dev
项目文件结构
node_modules 运行依赖
index.html 主页面
package.json npm信息描述配置文件
tsconfig.json typescript配置文件
vite.config.ts/js vite配置文件
pub1ic 静态资源(favicon.ico网页图标)
-src 源码文件夹
-assets
-components 可重用组件
-mode1 模型定义
-router 路由
-store 共享存储
-views视图组件
推荐的 IDE 配置是 Visual Studio Code + Volar 扩展。
devtools 插件网址: Installation | Vue Devtools
#发布到生产环境时
npm run build
#在本地启动一个静态 Web 服务器,将 dist 文件夹运行在http://localhost:4173
npm run preview
可以通过 --port 参数来配置服务的运行端口。
{
"scripts": {
"preview": "vite preview --port 8080"
}
}
修改端口vite.config.ts
export default defineConfig({
plugins: [vue()],
server: {
port: 7070,
//开放所有地址
host: "0.0.0.0",
//代理 影响性能
proxy: {
'/api': {
target:'http://localhost:8080',
changeOrigin: true
}
}
}
})
vite环境变量
根目录下创建环境变量文件:
.env.production(生产环境)
对象名必须是 VITE_ 开头的才能被自动识别到
VITE_BACKEND_API_BASE_URL = ' http://localhost:8080'
.env.development(开发环境)
VITE_BACKEND_API_BASE_URL = ' http://itheima.com'
vite特殊对象获取:
import.meta.env.VITE_BACKEND_API__BASE_URL
默认不提示 src/env.d.ts 并添加如下内容
常用的指令
-
v-if:根据表达式的值的真假条件渲染元素。在切换时元素及它的数据绑定 / 组件被销毁并重建。
-
v-show:根据表达式之真假值,切换元素的 display CSS 属性。
-
v-for:循环指令,基于一个数组或者对象渲染一个列表,vue 2.0以上必须需配合 key值 使用。
-
v-bind:动态地绑定一个或多个特性,或一个组件 prop 到表达式。
-
v-on:用于监听指定元素的DOM事件,比如点击事件。绑定事件监听器。
-
v-model:实现表单输入和应用状态之间的双向绑定
-
v-pre:跳过这个元素和它的子元素的编译过程。可以用来显示原始 Mustache 标签。跳过大量没有指令的节点会加快编译。
-
v-once:只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。
var和let区别
-
var是函数作用域,let是块作用域。
在函数中声明了var,整个函数内都是有效的,比如说在for循环内定义的一个var变量,实际上其在for循环以外也是可以访问的
而let由于是块作用域,所以如果在块作用域内定义的变量,比如说在for循环内,在其外面是不可被访问的,所以for循环推荐用let
-
let不能在定义之前访问该变量,但是var可以。
-
let不能被重新定义,但是var是可以的
选项式API&单文件组件
根据 JavaScript 的状态来描述 HTML 应该是什么样子。当状态改变时,HTML 会自动更新。
<script>
export default {
data() {
return {
message: 'Hello World!',
counter: {
count: 0
}
}
}
}
</script>
<template>
<!--
注意我们不需要在模板中写 .value,
因为在模板中 ref 会自动“解包”。
-->
双花括号内可以使用任何有效的 JavaScript 表达式
<h1>{{ message.split('').reverse().join('') }}</h1>
<p>Count is: {{ counter.count }}</p>
</template>
组合式API&单文件组件✔
Vue 的核心功能是声明式渲染:通过扩展于标准 HTML 的模板语法,我们可以根据 JavaScript 的状态来描述 HTML 应该是什么样子的。当状态改变时,HTML 会自动更新。
能在改变时触发更新的状态被称作是响应式的。我们可以使用 Vue 的 reactive() API 来声明响应式状态。由 reactive() 创建的对象都是 JavaScript Proxy,其行为与普通对象一样:
reactive() 只适用于对象 (包括数组和内置类型,如 Map 和 Set)。而另一个 API ref() 则可以接受任何值类型。ref 会返回一个包裹对象,并在 .value 属性下暴露内部值。
<!--块中声明的响应式状态-->
<script setup>
import { ref , reactive } from 'vue'
//reactive只适用于对象(数组和内置类型,如:Map\Set)
const counter = reactive({
count: 0
})
console.log(counter.count) // 0
counter.count++
//ref可以而接受任何类型值,返回一个包裹对象,并在.value属性下暴露内部值
const message = ref('Hello World!')
console.log(message.value) // "Hello World!"
message.value = 'Changed'
// 组件逻辑
// 此处声明一些响应式状态
</script>
<template>
<h1>{{ message }}</h1>
<p>count is: {{ counter.count }}</p>
</template>
v-bind 属性绑定
使元素id属性的值与dynamicId属性保持同步
<div v-bind:id="dynamicId"></div>
<div :id="dynamicId">简写语法</div>
用于class和style时表达式结果类型除了字符串还可以是对象或数组。也可以通过三元表达式来进行判断切换class。
v-bind:class 指令也可以与普通的 class 属性共存。
<script setup>
import { ref } from 'vue'
//判断是否显示active这个class
const isActive = ref(true)
</script>
<template>
<div class="static" v-bind:class="{ active: isActive }"></div> ;
//这里我们使用isActive 这个变量动态判断active是否显示到html
//渲染结果
<div class="active"></div>
</template>
<template>
<p>
<span :title="message">
Hover your mouse over me for a few seconds to see my dynamically bound title!
</span>
</p>
<!--
除了普通字符串之外,
class 绑定还特别支持了对象和数组
-->
<p :class="{ red: isRed }" @click="toggleRed">
This should be red... but click me to toggle it.
</p>
<!-- 样式绑定也支持对象和数组 -->
<p :style="{ color }" @click="toggleColor">
This should be green, and should toggle between green and blue on click.
</p>
</template>
v-on 监听DOM事件
<button v-on:click="increment"></button>
<button @click="increment">简写语法</button>
<script setup>
import { ref } from 'vue'
const count = ref(0)
function increment() {
count.value++
}
</script>
<template>
<button @click="increment">count is: {{ count }}</button>
</template>
<!--
绑定到一个方法/函数。
这个 @click 语法是 v-on:click 的简写。
-->
<button @click="reverseMessage">Reverse Message</button>
<!-- 也可以写成一个内联表达式语句 -->
<button @click="message += '!'">Append "!"</button>
<!--
Vue 也为一些像 e.preventDefault() 和 e.stopPropagation()
这样的常见任务提供了修饰符。
-->
<a href="https://vuejs.org" @click.prevent="notify">
A link with e.preventDefault()
</a>
<template>
显示开启关闭
<button @click="show = !show">Toggle List</button>
数组追加
<button @click="list.push(list.length + 1)">Push Number</button>
移除数组最后一个元素
<button @click="list.pop()">Pop Number</button>
数组倒序
<button @click="list.reverse()">Reverse List</button>
条件渲染
<ul v-if="show && list.length">
列表渲染
<li v-for="item of list">{{ item }}</li>
</ul>
条件渲染
<p v-else-if="list.length">List is not empty, but hidden.</p>
<p v-else>List is empty.</p>
</template>
this.
直接访问组件实例data()中的数据属性。this.count++
v-model 表单绑定input值
指令在状态和表单输入之间创建双向绑定。
<script>
export default {
data() {
return {
text: 'Edit me',
checked: true,
checkedNames: ['Jack'],
picked: 'One',
selected: 'A',
multiSelected: ['A']
}
}
}
</script>
Text Input
<input v-model="text" placeholder="请输入">{{ text }}
placeholder 属性规定可描述输入字段预期值的简短的提示信息(比如:一个样本值或者预期格式的短描述)。
该提示会在用户输入值之前显示在输入字段中。
注意:placeholder 属性适用于下面的 input 类型:text、search、url、tel、email 和 password。
单个复选框 Checkbox
<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">Checked: {{ checked }}</label>
<!--
多个复选框可以绑定到
相同的 v-model 【数组】
-->
多个复选框 Multi Checkbox
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mike</label>
<p>Checked names: <pre>{{ checkedNames }}</pre></p>
单选按钮 Radio
<input type="radio" id="one" value="One" v-model="picked">
<label for="one">One</label>
<br>
<input type="radio" id="two" value="Two" v-model="picked">
<label for="two">Two</label>
<br>
<span>Picked: {{ picked }}</span>
下拉框 Select
<select v-model="selected">
<option disabled value="">Please select one</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<span>Selected: {{ selected }}</span>
多选下拉框 Multi Select
<select v-model="multiSelected" multiple style="width:100px">
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<span>Selected: {{ multiSelected }}</span>
v-if 条件渲染
<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no 😢</h1>
<button @click="toggle">toggle</button>
通过toggle() {this.awesome = !this.awesome}实现两个标签之间切换
<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>
使用v-else v-else-if 的元素必须紧跟在一个 v-if 或一个 v-else-if 元素后面。
可以在 <template> 上使用。
v-show 条件显示
<h1 v-show="ok">DOM 渲染中会保留该元素</h1>
v-show 仅切换了该元素上名为 display 的 CSS 属性。
不支持在 <template> 元素上使用,也不能和 v-else 搭配使用。
v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。
切换频繁使用v-show。
v-for 列表渲染
<ul>
<li v-for="todo in todos" :key="todo.id">
todo 是一个局部变量
todos 是data()中的属性值
key绑定遍历的id
{{ todo.text }}
</li>
</ul>
.push() 数组添加
.filter() 过滤数组中符合条件的元素
@submit.prevent 表单提交
<form @submit.prevent="addTodo">
<input v-model="newTodo">
<button>Add Todo</button>
</form>
computed:{} 计算属性
computed 选项声明一个响应式的属性,它的值由其他属性计算而来
computed: {
filteredTodos() {
//对done属性进行取反
return this.hideCompleted
? this.todos.filter((t) => !t.done)
: this.todos
}
}
添加&删除指定元素
<script>
export default {
data() {
return {
todos: [
{ id: id++, text: 'Learn HTML', done: true },
{ id: id++, text: 'Learn JavaScript', done: true },
{ id: id++, text: 'Learn Vue', done: false }
]
}
},
methods: {
addTodo() {
this.todos.push({ id: id++, text: this.newTodo, done: false })
this.newTodo = ''
},
removeTodo(todo) {
//过滤掉当前传入对象
this.todos = this.todos.filter((t) => t !== todo)
}
}
}
</script>
ref 生命周期和模板引用
<script>
export default {
//钩子函数,页面初始化完成后执行
mounted() {
// 此时组件已经挂载。修改它的 textContent
this.$refs.p.textContent = 'mounted!'
}
}
</script>
<p ref="p">hello</p>
此元素将作为 this.$refs.p 暴露在 this.$refs 上。然而,你只能在组件挂载之后访问它。
侦听器
<script>
export default {
data() {
return {
count: 0
}
},
//watch 选项侦听count属性的变化
//当count改变
watch: {
count(newCount) {
// 没错,console.log() 是一个副作用
console.log(`new count is: ${newCount}`)
}
}
}
</script>
导入组件
App.vue
<script>
//父组件可以在模板中渲染另一个组件作为子组件。
import ChildComp from './ChildComp.vue'
export default {
//注册组件
components: {
ChildComp
}
}
</script>
<template>
<p>在模板中使用组件</p>
<ChildComp />
</template>
ChildComp.vue
<template>
<h2>A Child Component!</h2>
</template>
Props 子组件接收
子组件可以通过 props 从父组件接受动态数据。
App.vue
<script>
import ChildComp from './ChildComp.vue'
export default {
components: {
ChildComp
},
data() {
return {
greeting: 'Hello from parent'
}
}
}
</script>
<template>
//使用 v-bind 语法传递动态值
<ChildComp :msg="greeting" />
</template>
ChildComp.vue
<script>
export default {
//在子组件中需要声明所接受的 props
props: {
msg: String
}
}
</script>
<template>
<h2>{{ msg || 'No props passed yet' }}</h2>
</template>
Emits 子组件发送
App.vue
<script>
import ChildComp from './ChildComp.vue'
export default {
components: {
ChildComp
},
data() {
return {
childMsg: 'No child msg yet'
}
}
}
</script>
<template>
父组件可以使用 v-on 监听子组件触发的事件
这里的处理函数接收了子组件触发事件时的额外参数并将它赋值给了本地状态
<ChildComp @response="(msg) => childMsg = msg" />
<p>{{ childMsg }}</p>
</template>
ChildComp.vue
<script>
export default {
//声明触发的事件
emits: ['response'],
created() {
//带参数触发
this.$emit('response', 'hello from child')
}
}
</script>
<template>
<h2>Child component</h2>
</template>
slots 插槽 将模板片段传递给子组件
App.vue
<script>
import ChildComp from './ChildComp.vue'
export default {
components: {
ChildComp
},
data() {
return {
msg: 'from parent'
}
}
}
</script>
<template>
没有给 ChildComp 传递任何插槽内容,所以你将看到子组件默认内容。
<ChildComp>Message: {{ msg }}</ChildComp>
</template>
ChildComp.vue
<template>
作为插槽出口渲染父组件中的插槽内容
<slot>Fallback content</slot>
</template>
xhr-promise改造(了解)
try {
const resp = await new Promise((resolve,reject)=>{
const xhr = new XMLHttpRequest()
xhr.onload = function() {
if(xhr.status === 200) {
resolve(xhr.response)
} else if(xhr.status === 400) {
reject(xhr.response)
}
}
xhr.open('GET',"http://localhost/api/students")
xhr.responseType = 'json'
xhr.send()
})
console.log(resp)
} catch (e) {
console.error(e)
}
//简化
function get(url: string) {
return await new Promise((resolve,reject)=>{
const xhr = new XMLHttpRequest()
xhr.onload = function() {
if(xhr.status === 200) {
resolve(xhr.response)
} else if(xhr.status === 400) {
reject(xhr.response)
}
}
xhr.open('GET',url)
xhr.responseType = 'json'
xhr.send()
})
}
axios
安装:npm install axios
import axios from 'axios'
import { ref } from 'vue'
const count = ref(0)
async function get() {
const resp = await axios.get('http://localhost/api')
//请求体,json格式
const resp1 = await axios.post('http://localhost/api',count.value)
console.log(resp.data)
count.value = resp.data.length
}
//加载完执行
onMounted(()=>{
get()
})
Java类名 implements WebMvcConfigurer
//解决跨域
@0verride
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping( pathPattern: "/**")
.allowedorigins( "http://localhost:7070")
.allowCredentials(true);
}