Vue3
发表于|更新于
|字数总计:5.9k|阅读时长:30分钟|阅读量:
简介
官网:cn.vuejs.org
官方文档:https://v3.cn.vuejs.org/guide/installation.html
菜鸟:https://www.runoob.com/vue3/vue3-tutorial.html
可以联网导入,也可以下载下来本地导入。本文章全以本地导入为主
<script src="https://unpkg.com/vue@next"></script>
Hello Vue
熟悉一下语法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <script src="./js/v3.2.8/vue.global.prod.js" type="text/javascript" charset="utf-8"></script> </head>
<body> <div id="app"> {{message}} </div>
<script type="text/javascript">
const app = { data() { return { message: `Hello Vue` } } }
Vue.createApp(app).mount("#app");
</script> </body>
</html>
|
声明式渲染
插值表达式{ { } }
Vue.js 的核心是一个允许你采用简洁的模板语法来声明式的将数据渲染进 DOM 的系统:
1 2 3 4 5 6 7 8 9 10 11 12 13
| <div id="app"> <h4>{{message}}</h4> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"> </script> <script> var app = new Vue({ el:"#app", data:{ message:"Hello Vue.js" } }); </script>
|
参数 $event
事件对象有$event
,如果需要利用必须是最后一个参数
如果事件直接绑定函数名称(不带括号),默认会传递事件对象作为事件处理函数的第一个参数
如果事件是函数调用绑定(带括号),必须显式传递事件参数对象(参数名:$event)
例子:
当你触发input事件时,$event 是当前的事件对象。
而$event.target.value指向的是当前的input的值。
1
| <input @keydown.enter="test($event)">
|
1 2 3 4
| test(event){ let num = event.target.value; }
|
指令
指令是带有v-
开头的特殊属性,其值限定为单个表达式。
指令的作用是,当表达式的值发生变化,将其产生的连带影响应用到DOM节点中。
v-html
用于更新元素的innerHTML,该根部内容会被当做HTML代码插入。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <body> <div id="app"> <p v-html="message"></p> </div>
<script type="text/javascript"> Vue.createApp({ data() { return { message: `<h1>Hello Vue.js</h1>` } } }).mount("#app"); </script> </body>
|
v-text
将字符串以普通文本的形式输出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <html> <head> <meta charset="utf-8"> <title></title> <script src="../js/v3.2.8/vue.global.prod.js" type="text/javascript" charset="utf-8"></script> </head>
<body> <div id="app"> <p v-text="message"></p> </div>
<script type="text/javascript"> Vue.createApp({ data() { return { message: `<h1>Hello Vue.js</h1>` } } }).mount("#app"); </script> </body> </html>
|
v-bind
主要用于响应更新HTML元素属性,将一个或者多个属性动态绑定
到表达式。
v-bind
可省略,如v-bind:src
可简写为:src
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <head> <meta charset="utf-8"> <title></title> <script src="../js/v3.2.8/vue.global.prod.js" type="text/javascript" charset="utf-8"></script> </head>
<body> <div id="app"> <img v-bind:src="imgUrl" width="100" height="100" /> <p :title="message">把鼠标放在这里停留几秒</p> </div>
<script type="text/javascript"> Vue.createApp({ data() { return { imgUrl: `https://img2.baidu.com/it/u=281572882,1041305488&fm=26&fmt=auto`, message: "这个是绑定了title属性的p元素" } } }).mount("#app"); </script> </body>
|
v-model
该指令用于在表单元素
中的双向数据绑定。
v-model会忽略所有表单元素的value checked、selected特性的初始值。因为它会选择vue实例的数据来作为具体的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| <!DOCTYPE html> <html>
<head> <meta charset="utf-8"> <title></title> <script src="../js/v3.2.8/vue.global.prod.js" type="text/javascript" charset="utf-8"></script> </head>
<body> <div id="app"> <h2>1.文本输入</h2> <p>{{message}}</p> <input v-model="message" type="text" />
<h2>2.单选框</h2> <p>{{gender}}</p> 性别: 男:<input type="radio" name="gender" value="male" v-model="gender" /> 女:<input type="radio" name="gender" value="female" v-model="gender" />
<h2>3.复选框</h2> <p>{{hobby}}</p> 爱好: 健身<input type="checkbox" value="健身" v-model="hobby" /> 踢球<input type="checkbox" value="踢球" v-model="hobby" /> 游戏<input type="checkbox" value="游戏" v-model="hobby" /> 游泳<input type="checkbox" value="游泳" v-model="hobby" /> 拳击<input type="checkbox" value="拳击" v-model="hobby" />
<h2>4.下拉选框</h2> <p>{{city}}</p> <select v-model="city"> <option value="0">--请选择--</option> <option value="gz">广州</option> <option value="nj">南京</option> <option value="bj">北京</option> <option value="sh">上海</option> </select>
<hr /> <button type="button" @click="show">点击</button> </div>
<script type="text/javascript"> Vue.createApp({ data() { return { message: "zhangsan", gender: "male", hobby: ['拳击'], city: "0" } }, methods: { show() { alert(this.city); } } }).mount("#app"); </script> </body>
</html>
|
v-show 与 v-if
根据表达式的真假,来显示或者隐藏HTML元素。
区别:
v-show会生成节点然后使用dispaly属性进行显示和隐藏
。
v-if在值是false的时候不生成节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <head> <meta charset="utf-8"> <title></title> <script src="../js/v3.2.8/vue.global.prod.js" type="text/javascript" charset="utf-8"></script> </head>
<body> <div id="app"> <h1 v-show="yes">yes</h1> <h1 v-show="no">no</h1> <h1 v-show="age >= 26">{{age}}</h1> <h1 v-show="name.indexOf('s') >= 0">{{name}}</h1> </div> <script type="text/javascript"> Vue.createApp({ data() { return { yes: true, no: false, age: 26, name: "smith" } } }).mount("#app"); </script> </body>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <head> <meta charset="utf-8"> <title></title> <script src="../js/v3.2.8/vue.global.prod.js" type="text/javascript" charset="utf-8"></script> </head>
<body> <div id="app"> <h1 v-if="yes">yes</h1> <h1 v-if="no">no</h1> <h1 v-if="age >= 26">{{age}}</h1> <h1 v-if="name.indexOf('s') >= 0">{{name}}</h1> </div> <script type="text/javascript"> Vue.createApp({ data() { return { yes: true, no: false, age: 26, name: "smith" } } }).mount("#app"); </script> </body>
|
v-else-if 与 v-else
互斥条件,当一个条件满足时,后续条件都不会再判断。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <head> <meta charset="utf-8"> <title></title> <script src="../js/v3.2.8/vue.global.prod.js" type="text/javascript" charset="utf-8"></script> </head>
<body> <div id="app"> <span v-if="score >= 95">优秀</span> <span v-else-if="score >= 80">良好</span> <span v-else-if="score >= 60">及格</span> <span v-else>不及格</span> </div> <script type="text/javascript"> Vue.createApp({ data() { return { score: 79 } } }).mount("#app"); </script> </body>
|
v-for
通过循环的方式来渲染一个列表,循环对象可以是数组,也可以是JS对象。
遍历数组语法:item in items
遍历对象语法:value,key,index in Obj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <body> <div id="app"> <h1>1.迭代数组</h1> <ul> <li v-for="(city,index) in citys">{{index + 1}}--{{city}}</li> </ul> <h1>2.迭代对象</h1> <ul> <li v-for="(value,key,index) in book">{{index}}--{{key}}--{{value}}</li> </ul> </div> <script type="text/javascript"> Vue.createApp({ data() { return { citys: ['广州', '南京', '上海', '北京'], book: { name: "《从入门到放弃》", isbn: "1234567890", author: "葫芦", price: 65.00 } } } }).mount("#app"); </script> </body>
|
v-on
事件绑定指令,而且JS的所有事件都可以用v-on绑定
全写形式:v-on-click
简写形式:@click
其他常用事件:https://pengyirui.gitee.io/posts/d3d6.html#%E4%BA%8B%E4%BB%B6
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| <body> <div id="app"> <h1>1.点击事件</h1> {{message}}
<h1>2.焦点失去事件</h1> <input type="text" @blur="print" /> <hr /> <button type="button" @click="changeMessage">点击改变message的值</button> </div>
<script type="text/javascript"> Vue.createApp({ data() { return { message: "Hello Vue.js" } }, methods: { changeMessage() { this.message = "Hello World"; }, print() { alert("焦点失去事件被触发..."); } } }).mount("#app"); </script> </body>
|
绑定HTML 的class
class是每个HTML元素都有的属性。
用vue控制css样式是否生效
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| <head> <meta charset="utf-8"> <title></title> <style type="text/css"> .active { width: 100px; height: 100px; background-color: greenyellow; }
.border-style { border-radius: 10px; cursor: pointer; } </style>
<script src="../js/v3.2.8/vue.global.prod.js" type="text/javascript" charset="utf-8"></script> </head>
<body> <div id="app"> <div :class="{'active':isActive,'border-style':isBorderStyle}"></div> <div :style=""></div> </div>
<script type="text/javascript"> Vue.createApp({ data() { return { isActive: true, isBorderStyle: true } }, }).mount("#app"); </script> </body>
|
组件
可以 扩展 HTML 元素 和 封装 可重用的代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <body> <div id="app"> <first-component></first-component> <first-component></first-component> </div>
<script type="text/javascript"> const app = Vue.createApp({});
app.component("first-component", { template: ` <div> <h1>Hello Component</h1> <h2>这是我的第一个VUE组件...</h2> </div> ` }); app.mount("#app"); </script> </body>
|
局部组件注册
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <body> <div id="app"> {{message}} <login></login> </div> <script type="text/javascript">
Vue.createApp({ data() { return { message: "这是Vue实例的message" } }, components: { login: { template: `<h1>这是登录的局部组件--{{this.message}}</h1>`, data() { return { message: "这是局部组件的message" } } } } }).mount("#app"); </script> </body>
|
静态值传递 props
关键字props:用于设定组件中的属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <body> <div id="app"> <site-name title="Google"></site-name> <site-name title="Runoob"></site-name> <site-name title="Taobao"></site-name> </div>
<script> const app = Vue.createApp({})
app.component('site-name', { props: ['title'], template: `<h4>{{ title }}</h4>` })
app.mount('#app') </script> </body>
|
动态值传递
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| <body> <div id="app"> <login :post="obj"></login> <button type="button" @click="changeData">点击</button> </div>
<script type="text/javascript"> Vue.createApp({ data() { return { obj: { id: 1, title: "《标题》", content: "内容...." } } }, methods: { changeData() { alert('点击触发事件执行'); this.obj = { 'id': 2, 'title': '关于...', 'content': '疫情防御....' } } }, components: { login: { template: ` <div> <h1>{{post.id}}</h1> <h1>{{post.title}}</h1> <h1>{{post.content}}</h1> </div>`, props: ['post'] } } }).mount("#app"); </script> </body>
|
计算属性 computed
是用来简化vue页面中 文本插值的js表达式。
computed 与 methods区别:
我们可以使用 methods 来替代 computed,效果上两个都是一样的,但是 computed 是基于它的依赖缓存,只有相关依赖发生改变时才会重新取值。而使用 methods ,在重新渲染的时候,函数总会重新调用执行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| <body> <div id="app"> <p>未改变之前的数据:{{message}}</p> <p>改变之后的数据:{{upperCase}}</p> <p>{{msg}}</p> <button type="button" @click="upperCase1">点击</button> </div>
<script type="text/javascript"> Vue.createApp({ data() { return { message: "Hello World", msg: "" } }, computed: { upperCase() { return this.message.toUpperCase(); } }, methods: { upperCase1() { this.msg = this.message.toUpperCase(); } } }).mount("#app"); </script> </body>
|
路由
在vue的基础上,再导入路由文件
下载 或 在线导入路由:<script src="https://unpkg.com/vue-router@4"></script>
路由允许我们通过不同的url访问不同的内容
通过vue可以实现多视图的单页web应用
配置文件
router文件夹下有个index.js文件夹用来修改配置的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
|
import Vue from 'vue' import VueRouter from 'vue-router' import Login from '@/components/Login' import ProductList from '@/components/ProductList'
Vue.use(VueRouter)
const routes = [ { path: '/', name: 'ProductList', component: ProductList }, { path: '/login/:id', name: 'Login', component: Login } ]
const router = new VueRouter({ mode: 'history', base: process.env.BASE_URL, routes })
export default router
|
点击切换路由
两种方法
1 2 3 4 5 6 7 8 9 10
| <router-link to="/login"></router-link>
<router-link :to="{name:'Login'}"></router-link>
<router-view></router-view>
|
获取路由的参数
注意!!!获取路由是$route没有r的!!!
1 2 3 4
| this.$route.params;
let id = this.$route.params.id;
|
带参切换路由
1 2 3
|
this.$router.push({name:'name',query:{name:name}})
|
路由监听
1 2 3 4 5
| watch:{ $route(){ } }
|
跨域请求
当前端端口是8080,后端是9090时,存在跨域问题
可以改变前端端口,做跨域请求
在主目录下新建vue.config.js文件,写入以下内容(/api只是用来更好区分)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| module.exports = { devServer: { port: 3000, proxy: { '/api': { target: 'http://localhost:9090', pathRewrite: { '^/api': '' } }, } } }
前端将端口改为3000,
例如: 后端开放的端口是127.0.0.1:9090/products 配置完后前端输入127.0.0.1:3000/api/products 获得的是相同的数据
|
js对象
例如构造个UserService.js
1 2 3 4 5 6 7 8 9
| export default class UserService { constructor() {
}, saveUser(xxx) { }
|
使用对象
1 2 3 4 5 6 7 8
| 先导包 import UserService from "@/service/UserService"
实例化对象 let userService = new UserService();
使用对象中的方法 userService.saveUser(xxx);
|
axios
官网:https://www.npmjs.com/package/axios
vue中的ajax技术。可以理解为vue封装的ajax技术。
axios是基于vue.js开发的的,所以要先导入vue.js
下载 或 在线导入:<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
在vue里面添加
vue add axios
npm 安装
npm install axios
在vue cli 中添加axios
命令:npm导入:npm install --save axios
.vue
文件中导入axios
import axios from 'axios'
1 2 3 4 5 6 7 8
| 语法: axios({method,url,params}then().catch();
get语法: axios.get('',{params}).then(resp=>{}).catch(error=>{});
post语法(需要转换): axios.post('',{});
|
具体实现:把name与time发送到后台,后台发送json对象到前台
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
|
axios({ method:"post", url:"http://localhost:8080/axiosAjax", params:{ name:this.name, time:"2021-10-8 16:52" } }).then(resp=>{ this.info = resp.data; })
axios.get('http://localhost:8080/axiosget',{ params:{ name:this.name, time:"2021-10-8 16:52" } }).then(resp=>{ this.users = resp.data; });
let params = new URLSearchParams(); params.append("name",this.name); params.append("time","2021-10-8 16:52");
axios.post('http://localhost:8080/axiospost',params).then(resp => { this.users = resp.data; });
|
传的是json对象,并且带头部
1 2 3 4 5 6
| axios.post("/api/orders",JSON.stringify(order),{ headers:{ "Content-Type":"application/json", "key":"value" } }
|
常用的官方解释
Method |
Api |
GET |
axios.get(url).then(successCallback).catch(errorHandler) |
POST |
axios.post(url, data).then(successCallback).catch(errorHandler) |
PUT |
axios.put(url, data).then(successCallback).catch(errorHandler) |
DELETE |
axios.delete(url).then(successCallback).catch(errorHandler) |
GET传参:
axios.get(url,{key:value,key:value}).then(function(data){});
POST/PUT传参
(1)使用json对象传参(在服务器端控制器要求@RequestBody)—-默认方式
axios.post(url,{username:'accp',password:'123'}).then(function(data){});
(2)使用URLSearchParams传参—表单传参
1 2 3 4 5 6 7
| let param = new URLSearchParams();
param.append('username', this.username);
param.append('password', this.password);
axios.post(url,param).then(function(data){});
|
vue cli
Vue CLI 是一个基于 Vue.js进行快速开发的一个完整的系统。
Vue CLI安装需要使用npm命令,npm命令需要基于node.js,所以要先安装node.js
node.js官网:https://nodejs.org/zh-cn/
搭建:npm install -g @vue/cli
选一个目录创建项目
vue create 项目名
进入项目目录,运行服务,用浏览器测试。
npm run serve
以.vue
为后缀的文件,这个文件可以包含,HTML、CSS、JS
HTML是写在<template></template>
JS是写在<script></script>
CSS是写在<style></style>
todo list 练习
一个小练习,
!(图片)[]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| <template> <Head @todotitle="addtodo"></Head> <Body :todolist="todolist" @delindex="deltodo"></Body> <Tail :todolist="todolist"></Tail> <br> <button @click="loadData">加载数据</button> <button @click="saveData">保存数据</button> </template>
<script> import Body from "./components/Body.vue"; import Head from "./components/Head.vue"; import Tail from "./components/Tail.vue";
export default { name: "App", components: { Head, Body, Tail, },
data() { return { todolist: [ { title: "学习ES6新语法", finished: false, }, { title: "学习Spring Boot", finished: false, }, { title: "背诵单词", finished: true, }, ], }; },
methods: { addtodo(title) { var todo = { title: title, finished: false, }; this.todolist.push(todo); },
deltodo(index) { this.todolist.splice(index, 1); }, loadData() { var data = localStorage.getItem("todolist"); if (data) { this.todolist = JSON.parse(data); } }, saveData() { localStorage.setItem("todolist", JSON.stringify(this.todolist)); }, }, }; </script>
<style> </style>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| <template> <h2>Todo App</h2> 待办事务:<input type="text" v-model="title" /> <button @click="addtodo">添加</button> <hr /> </template>
<script> export default { data() { return { title: "", }; }, methods: { addtodo() { this.$emit("todotitle", this.title); this.title = ""; }, }, }; </script>
<style> </style>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| <template> <table border="1"> <tr> <td>完成</td> <td>待办事项</td> <td>删除</td> </tr> <tr v-for="(todo, index) in todolist" :key="todo"> <td><input type="checkbox" v-model="todo.finished" /></td> <td :class="{ text: todo.finished }">{{ todo.title }}</td> <td><button @click="deltodo(index)">删除</button></td> </tr> </table> </template>
<script> export default { props: ["todolist"], methods: { deltodo(index) { this.$emit("delindex", index); }, }, }; </script>
<style>
.text { text-decoration: line-through; } </style>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| <template> <hr /> <spam>共有{{ todolist.length }}条,已完成{{finallytodo}}条,未完成{{unfinallytodo}}条</spam> </template>
<script> export default { props: ["todolist"], computed: { finallytodo() { var count = 0; this.todolist.forEach((x) => { if (x.finished) count++; }); return count; },
unfinallytodo() { var count = 0; this.todolist.forEach((x) => { if (!x.finished) count++; }); return count; }, }, }; </script>
<style> </style>
|
script标签
注意:自定义组件命名规则
1.短横线 my-component
2.驼峰式 MyComponent:在使用组件的时候只能在模板字符串中(组件中嵌套个组件)使用驼峰命名,在普通的标签中使用必须转换为短横线的方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| <script> export default { import CartService from "@/service/CartService";
components: { 子组件, ... },
props:[ '属性1', '属性2', ... ],
name:"App"
template: 'html字符串模板'
data() { return { name: '', age: '' }; },
mounted() { this.name = "葫芦"; this.age = 23; },
computed: { allQuantity() { return this.cart.totalQuantity(); } },
methods: { eat(){ console.log("正在吃饭~~") } },
watch:{
} } </script>
|
浏览器存储
localStorage
和sessionStorage
一样都是用来存储客户端临时信息的对象。
localStorage
生命周期是永久
sessionStorage
生命周期为当前窗口或标签页
sessionStorage
将用户数据存入session
1
| sessionStorage.setItem("user",JSON.stringify(user));
|
获取session数据
1
| let user = sessionStorage.getItem("user");
|
json转换为Object类型
1
| let user = JSON.parse(json);
|
Object类型 转换为json
1
| let user = JSON.stringify(Object)
|
localStorage
localStorage保存到浏览器
1
| localStorage.setItem("cart", JSON.stringify(this.items));
|
清空指定key的localStorage
1
| localStorage.removeItem("cart");
|
加载localStorage
1
| let cart = localStorage.getItem("cart");
|