今日内容
一、Vue简介
1.1 简介
1.2 MVVM 模式的实现者——双向数据绑定
模式
1.3 其它 MVVM 实现者
1.4 为什么要使用 Vue.js
1.5 Vue.js 的两大核心要素
1.5.1 数据驱动
1.5.2 组件化
二、Vue的初体验
2.1在页面引入vue的js文件
<script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.min.js"></script>
2.2 准备dom
<!-- 创建一个div,id是app -->
<div id="app"></div>
2.3 创建vue对象,设计对象的内容
<script>
new Vue({
el:"#app",
data:{
title:"hello vue!",
nowdate:"hi!",
age:18,
flag:true
}
});
</script>
# el: element的简称,也就是Vue实例挂载的元素节点,值可以是 CSS 选择符,或实际 HTML 元素,或返回 HTML 元素的函数。
# data: 用于提供数据的对象,里面存放键值对数据。
2.4 在页面的元素中使用插值表达式来使用vue对象中的内容
<div id="app">
{{ title }}
</div>
三、 插值表达式
3.0 运算
<div id="app">
{{ 1 + 1}}<br>
{{ 1 - 1}}<br>
{{ 2 * 2}}<br>
{{ 2 / 2}}<br>
{{ 2 +"--"+ 2}}<br> <!-- 字符串拼接 -->
{{ 2 > 1 ? "2大":"1大"}}<br>
</div>
3.1 取数据
<body>
<div id="app">
{{ title }},
{{arr}},
{{user}},
{{user.age}},
{{user.username}}
</div>
</body>
<scrip>
new Vue({
el:"#app",
data:{
title:"hello world!",
arr:[11,22,33],
user:{
age:18,
username:"taotie"
}
},
methods:{
sayHello:function(){
return "hello vue";
}
}
});
</script>
3.2 获取数组中的内容
<div id="app">
{{arr[2]}}
</div>
3.3 获取对象中的属性
<div id="app">
{{ user.username }}
</div>
3.4 调用Vue中的方法
<div id="app">
{{ fun1()}} <!-- 注意还要加参数列表() -->
</div>
<script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.min.js"></script>
<script>
new Vue({
el: "#app",
data: { // 定义数据
},
methods: { // 定义函数
// key:value
fun1 : function(){
alert("调用fun1执行")
console.log("fun1输出");
},
// 上面函数定义,有简化写法
fun2(){
console.log("fun2输出")
// 返回值在页面展现
return "fun22222"
}
}
})
</script>
四、Vue对象总结
五、Vue的分支 v-if
5.1 v-if
5.2 v-show
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="app">
<p v-show="rich">
有钱!
</p>
<p v-if="rich">
有钱!
</p>
<button type="button" @click="rich=!rich">今晚彩票开奖</button>
</div>
</body>
<script src="https://cdn.bootcss.com/vue/2.6.10/vue.js"></script>
<script>
new Vue({
el:'#app',
data:{
rich:false
},
methods:{
}
});
</script>
</html>
六、Vue的循环 v-for【重点】
6.1 普通的for循环
<body>
<div id="app">
<ul>
<!-- in是关键词,args是下方data中定义的数组,a是遍历出的结果变量 -->
<li v-for="a in args">{{a}}</li>
</ul>
</div>
</body>
<script src="https://cdn.bootcss.com/vue/2.6.10/vue.js"></script>
<script>
new Vue({
el:'#app',
data:{
args:[1,2,3,4,5,6]
}
});
</script>
6.2 带着索引的for
<body>
<div id="app">
<ul>
<li v-for=" (a,i) in args" :key='i'>{{i}}{{a}}</li>
</ul>
</div>
</body>
<script src="https://cdn.bootcss.com/vue/2.6.10/vue.js"></script>
<script>
new Vue({
el:'#app',
data:{
args:[1,2,3,4,5,6]
}
});
</script>
6.3 遍历一个对象中的信息: v、k、i【了解】
<body>
<div id="app">
<ul>
<li v-for="(v,k,i) in student">{{i+1}}--{{k}}--{{v}}</li>
</ul>
</div>
</body>
<script src="https://cdn.bootcss.com/vue/2.6.10/vue.js"></script>
<script>
new Vue({
el:'#app',
data:{
student:{
username:'小鱼',
age:20,
girl:'如花'
}
}
});
</script>
页面效果如下: |
---|
![]() |
6.4 遍历对象数组填充表格【重点】
<body>
<div id="app">
<h3>for循环-遍历对象数组</h3>
<table border="2">
<tr>
<td>sid</td>
<td>sname</td>
<td>age</td>
<td>sex</td>
</tr>
<tr v-for="stu in stuArr" >
<td>{{stu.sid}}</td>
<td>{{stu.sname}}</td>
<td>{{stu.age}}</td>
<td>{{stu.sex}}</td>
</tr>
</table>
</div>
<script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.min.js"></script>
<script>
var vue = new Vue({
el:"#app",
data:{
stuArr:[
{
sid:"2020101",
sname:"瑞虎",
age:23,
sex:"男"
},
{
sid:"2020102",
sname:"奇瑞",
age:24,
sex:"男"
},
{
sid:"2020103",
sname:"道奇",
age:24,
sex:"男"
},
{
sid:"2020103",
sname:"冠道",
age:24,
sex:"男"
}
]
}
})
</script>
</body>
页面效果 |
---|
![]() |
七、Vue的属性绑定【重点】
7.1 v-model
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<div id="app">
<input type="text" v-model="title">
{{title}}
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script type="text/javascript">
new Vue({
el:'#app',
data:{
title:"hello vue"
}
})
</script>
</html>
页面效果如下: |
---|
![]() |
7.2 v-bind
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<div id="app">
<a v-bind:href="link"></a>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script type="text/javascript">
new Vue({
el:'#app',
data:{
link:'http://www.baidu.com'
}
})
</script>
</html>
<a v-bind:href='link'></a> 等价于==> <a :href='link'>
八、Vue的事件绑定【重点】
8.1 事件【重点】
<button v-on:click="start()">开始</button>
<button @click="begin()">开始</button>
事件中触发的函数,在vue实例中的methods中进行定义,可以按照如下两种方式进行定义:
<script type="text/javascript">
var vue = new Vue({
el : "#app",
data: {
},
methods:{
// 方式1
// 函数名: function(参数)
start : function(){
},
// 方式2
// 函数名(参数)
begin(){
}
}
})
</script>
练习: 设计一个div,其中有数字,再设计一个按钮,点击按钮使数字递增10
练习
输入A,B值后,点击计算按钮,在结果处展示相加后的结果
<div id="app">
<h3>简易加法计算器</h3>
<div>
数字A:<input type="text" v-model="valA"><br>
数字B:<input type="text" v-model="valB"><br>
<button v-on:click="add">计算</button>
结果:<span>{{result}}</span>
</div>
</div>
<script type="text/javascript" src="js/vue.min.js"></script>
<script type="text/javascript">
var app = new Vue({
el:'#app',
data:{
valA:0,
valB:0,
result:0
},
methods:{
add:function(){
this.result = parseInt(this.valA) + parseInt(this.valB);
}
}
});
</script>
练习1中涉及到表单数据转字符串问题,获取的表单数据是字符串,需要使用parseInt()转成数字
vue提供了表单修饰符表单输入绑定 — Vue.js (vuejs.org)
其中: .number
,可以使表单的输入的数据直接就是数字,不需要再解析
<input v-model.number="age" type="number">
除了.number修饰符外,还有其他的修饰符, 比如.trim
.lazy
8.2 事件修饰符[熟悉]

Vue阻止事件冒泡操作


8.3 按键修饰符[熟悉]
练习: 改造上题,输入完数字,按下回车即计算数据
8.4 练习
效果图如下,输入数据,动态的添加到页面中
<body>
<div id="app">
<!-- 输入框 -->
<div>
<label>ID
<input type="text" v-model="id">
</label>
<label>Name
<input type="text" v-model="name">
</label>
<button v-on:click="add">添加</button>
</div>
<!-- 列表 -->
<div>
<ul>
<li v-for="item in list">{{item.id +'---'+item.name}}</li>
</ul>
</div>
</div>
<script type="text/javascript" src="js/vue.min.js"></script>
<script type="text/javascript">
var app = new Vue({
el:'#app',
data:{
id: 0,
name:'',
list:[
{id:1,name:'zs'},
{id:2,name:'ls'},
{id:3,name:'ww'}
]
},
methods:{
add:function(){
// 获得输入的值
var id_ = this.id;
var name_ = this.name;
// 向数组中添加元素
this.list.push({id:id_,name:name_});
}
}
});
</script>
九、计算属性:computed
9.1 什么是计算属性
9.2 演示
官网演示很详细…计算属性 — Vue.js (vuejs.org)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
{{ message.split('').reverse().join('-') }}<br>
{{ message.split('').reverse().join('-') }}<br>
<hr>
{{reverseStr}}<br>
{{reverseStr}}
</div>
<script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.min.js"></script>
<script>
new Vue({
el:'#app' ,
data:{
message:'abcdef'
},
methods:{
sayHello(){
alert("hello")
}
},
computed:{ // 计算属性,理解: 将{{}}中重复的代码抽取,复用
reverseStr(){
return this.message.split('').reverse().join('*')
}
}
})
</script>
</body>
</html>
9.3 计算属性与方法的区别
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>布局篇 计算属性</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script>
</head>
<body>
<div id="vue">
<p>调用当前时间的方法:{{currentTime1()}}</p>
<p>当前时间的计算属性:{{currentTime2}}</p>
</div>
<script type="text/javascript">
var vm = new Vue({
el: '#vue',
data: {
message: 'Hello Vue'
},
methods: {
currentTime1: function () {
return Date.now();
}
},
computed: {
currentTime2: function () {
this.message;
return Date.now();
}
}
});
</script>
</body>
</html>
测试效果
仔细看图中说明,观察其中的差异
9.4 结论
自学: 侦听器侦听器 — Vue.js (vuejs.org)
十、Vue的组件化【理解】
10.1 组件的全局注册
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue组件的全局注册</title>
</head>
<body>
<div id="app">
<model1></model1>
<model1></model1>
<model1></model1>
</div>
<hr/>
<div id="app1">
<model1></model1>
<model1></model1>
<model1></model1>
</div>
</body>
<script src="https://cdn.bootcss.com/vue/2.6.10/vue.js"></script>
<script>
//通过Vue.component实现组件的全局注册,全局注册后的组件可以被重复使用。
// 名字小写,不能驼峰
Vue.component("model1",{
template:"<div><h1>{{title}}</h1><button type='button' @click='btnfn'>点我</button></div>",
data:function(){
return {
title:"hello vue"
}
},
methods:{
btnfn:function(){
alert("hello !!!");
}
}
});
new Vue({
el:'#app'
})
new Vue({
el:'#app1'
})
</script>
</html>
10.2 组件的本地(局部)注册
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue组件的本地(局部)注册</title>
</head>
<body>
<div id="app">
<model11></model11>
</div>
<hr/>
<!--在这里使用组件model11会报错-->
<div id="app1">
<model11></model11>
</div>
</body>
<script src="https://cdn.bootcss.com/vue/2.6.10/vue.js"></script>
<script>
new Vue({
el:'#app',
components:{
"model11":{
template:"<div><h1>{{title}}</h1><button type='button' @click='btnfn'>点我</button></div>",
data:function(){
return {
title:"hello vue"
}
},
methods:{
btnfn:function(){
alert("hello !!!");
}
}
}
}
})
new Vue({
el:'#app1'
})
</script>
10.3 注意特性【重点】
十一、 组件的生命周期【面试】
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.min.js"></script>
</head>
<body>
<div id="app">
<p>{{name}}</p>
<button @click="update">update</button>
<button @click="destroy">destroy</button>
</div>
<script type="text/javascript">
new Vue({
el: "#app",
data: {
a: 1,
name: "haha"
},
methods: {
update() {
this.name = Math.random() + "hehe";
},
destroy() {
this.$destroy();
}
},
// 声明钩子函数放在methods方法外
beforeCreate() {
console.log("创建vue实例之前");
console.log(this.a) // undefined
},
created() {
//
console.log("vue实例创建成功");
console.log(this.a);
},
beforeMount() {
console.log("挂载之前");
},
mounted() {
// 页面加载完之后执行
console.log("挂载完毕")
},
beforeUpdate() {
// 可执行多次
console.log("data更新之前执行");
},
updated() {
// 可执行多次
console.log("data更新之后执行");
},
beforeDestroy() {
// 只执行一次
console.log("vue实例销毁之前执行");
},
destroyed() {
// 只执行一次
console.log("vue实例销毁之后执行");
}
});
</script>
</body>
</html>
组件的生命周期钩子 |
---|
![]() |
钩子函数 | 解释 |
---|---|
beforeCreate | 在实例初始化之后,数据观测和事件配置之前被调用 此时data 和 methods 以及页面的DOM结构都没有初始化 什么都做不了 |
created | 在实例创建完成后被立即调用此时data 和 methods已经可以使用 但是页面还没有渲染出来,可以在这里进行数据的初始化、异步请求数据、监听事件等操作 |
beforeMount | 在挂载开始之前被调用 此时页面上还看不到真实数据 只是一个模板页面而已 |
mounted | mounted 钩子函数是组件挂载到 DOM 后被调用的。在这个阶段可以访问到组件所依赖的 DOM 元素,进行 DOM 操作、绑定事件等 |
beforeUpdate | 数据更新时调用,发生在虚拟DOM打补丁之前。 页面上数据还是旧的 |
updated | 由于数据更改导致的虚拟DOM重新渲染和打补丁,在这之后会调用该钩子。 页面上数据已经替换成最新的 |
beforeDestroy | 实例销毁之前调用 |
destroyed | 实例销毁后调用 |
十二、Vue-Cli搭建Vue项目【重点】
12.1 什么是vue-cli
12.2 node.js的介绍及安装
node.js的介绍
node.js的安装





不要勾选这个,否则会下载很多东西

测试node.js是否安装成功: 在DOS窗口中输入“node -v” 查看版本,如果看到版本,就表示安装成功。(环境变量已经自动配置好) |
---|
![]() |
# 【推荐这个】
npm config set registry https://registry.npmmirror.com
# 安装完vue-cli后再来执行这句话,开启镜像,使镜像生效
vue config --set useTaobaoRegistry true
12.3 使用node.js 安装 vue-cli
(管理员权限)使用如下命令安装vue-cli
npm install @vue/cli -g
# 如果出错,可以卸载,重新执行上一步安装
npm uninstall @vue/cli -g
当出现以下界面,表示正在安装: |
---|
![]() ![]() |
12.4 使用vue-cli命令创建项目
12.5 使用图形界面方式创建
会自动打开浏览器,弹出页面


12.6 项目结构
文件名 | 解释 |
---|---|
build | webpack的一些配置 |
config | 不同环境的配置,比如开发环境,生产环境等 |
node_modules | npm install下载的依赖包 |
public | 用于存放公共js文件夹、json文件和图片等 |
dist | 存放项目打包后的文件 |
src | 项目的源码 |
src/assets | 存放静态资源文件,如图片等 |
src/components | 存放公共组件 |
src/router | 静态路由表 |
src/store | vuex |
src/views | 开发的页面资源,路由页面相关的 |
src/main.js | 对应App.vue创建vue实例,也是入口文件 |
src/App.vue | 入口页面 |
gitignore | git管理时,忽略的文件或文件夹 |
package.json | 项目的核心配置记录,可以查看当前安装依赖的版本号 |
index.html | 首页的入口 |
vue.config.js | 可选的配置文件,存放在根目录中,@vue/cli-service 启动的时候会自动加载 |
12.7 启动项目
进入项目,使用命令行输入npm run serve
启动
十三、idea开发vue
BUG总结
十四、单文件组件【重点】
14.1 介绍
14.2 使用
<template>
<div>
<h1 class="red">这是测试单vue文件组件</h1>
<h3>{{info}}</h3>
<button @click='show()'>show</button>
</div>
</template>
<script>
export default {
name: "TestSingleVuePage",
data:function (){
return {
info:"data-信息"
}
},
methods:{
show(){
alert("单页面内弹出...")
}
}
}
</script>
<style scoped>
.red {
color: red;
}
</style>
14.3 练习
练习: 再创建一个单页面TestSingleVuePage2.vue页面,定义一些内容, 然后在TestSingleVuePage.vue页面内使用该页面
十五、Vue组件间的参数传递[熟悉]
15.1 父传子
创建子组件,设置参数 等待父组件给其传值
<template>
<div>
<h1>这是 子组件</h1>
<span>{{name}}</span> --
<span>{{age}}</span> --
<span>{{sex}}</span>
</div>
</template>
<script>
export default {
name: "MySon",
props:{
name: {
// 类型
type: String,
// 默认值
default: '无名'
},
age: Number,
sex: Boolean
}
}
</script>
<style scoped>
</style>
创建父组件,给子组件传值
<template>
<div>
<h1>这是 父组件 </h1>
<!-- 父组件使用子组件 -->
<!--
可以通过 v-bind 动态赋值,比如 v-bind:name="",
也可以简写:age=""
也可以静态赋值,比如 messages="" , 注意没有冒号
-->
<MySon v-bind:name="username" :age="age" sex="true"></MySon>
</div>
</template>
<script>
import MySon from "@/components/MySon";
export default {
name: "MyFather",
components: {
MySon
},
data: function () {
return {
username: "小儿砸",
age: 18
}
}
}
</script>
<style scoped>
</style>
在App.vue注册父组件并使用父组件演示效果即可
15.2 子传父
子组件
<template>
<div>
<h1>这是 子组件2</h1>
<button @click="sendNum">子组件将值num=10传递给父组件</button>
</div>
</template>
<script>
export default {
name: "MySon2",
props: {},
data: function () {
return {
num: 10
}
},
methods: {
sendNum() {
// 触发父组件的事件,同时给事件传参
this.$emit('addFun', this.num)
}
}
}
</script>
<style scoped>
</style>
父组件
<template>
<div>
<h1>这是 父组件2 </h1>
<span>sum = {{sum}}</span>
<MySon2 @addFun="addSum(num)"></MySon2>
</div>
</template>
<script>
import MySon2 from "@/components/MySon2";
export default {
name: "MyFather2",
components: {
MySon2
},
data: function () {
return {
sum: 0
}
},
methods:{
addSum(v){
this.sum += v;
}
}
}
</script>
<style scoped>
</style>
在App.vue注册父组件并使用父组件演示效果即可

十六、Vue-router 路由【重点】
16.1 介绍
16.2 vue的路由
16.3 安装路由模块
npm install vue-router
# 如果报错,可能是npm版本过高,存在兼容性问题,那么使用如下命令
npm install --legacy-peer-deps vue-router@3.5.2
# 或
npm install --legacy-peer-deps vue-router@3.1.3
ps: 今天练习过一次以后,后续在创建项目时可以直接选择路由部分内容,创建出的项目直接就配置好了
16.5 声明式路由
16.5.1 创建MyInfo.vue
<template>
<div>
<h1>个人中心</h1>
</div>
</template>
<script>
export default {
name: "MyInfo"
}
</script>
<style scoped>
</style>
16.5.2 创建静态路由表
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '../components/HelloWorld'
import MyInfo from "../views/MyInfo";
Vue.use(Router)
// export是导出路由对象,只有在这里导出了,main.js文件头上面才能 import 导入
export default new Router({
routes: [
{
path: '/', // 匹配<router-link to="">中的路径
name: 'HelloWorld', // 这个name属性可写可不写
component: HelloWorld // 要跳转的组件对象
},
{
path: '/MyInfo',
name: 'MyInfo',
component: MyInfo
}
],
// mode: 'history'
mode: 'hash'
})
16.5.3 main.js引入路由模块并使用
import Vue from 'vue'
import App from './App'
import router from './router' //引入上一步导出的路由模块,并设置名字为router
Vue.config.productionTip = false
new Vue({
render: h => h(App),
// router:router // 使用路由,可以简写为router
router
}).$mount('#app')
16.5.4 App.vue使用路由
<template>
<div id="app">
<ul>
<li>
<!--
<router-link>用于导航,其实就是a标签
to表示要跳转的资源的路径
tag 将router-link渲染成想要的原生标签,默认是a标签,可以改成button
-->
<router-link to="/" tag="button">首页</router-link>
</li>
<li>
<router-link to="/MyInfo">个人信息</router-link>
</li>
</ul>
<!-- router-view 路由填充位,要跳转的组件在此展示,位置任意 -->
<router-view/>
</div>
</template>
<script>
export default {
name: 'App',
components: {}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
启动测试
16.6 编程式路由
创建公告页Note.vue
<template>
<div>
<h1>公告页面</h1>
<ol>
<li>老杨不瞌睡了</li>
<li>萌萌也+1</li>
<li>相宇明天好好做操</li>
</ol>
</div>
</template>
<script>
export default {
name: "Note"
}
</script>
<style scoped>
</style>
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
},
{
path: '/MyInfo',
name: 'MyInfo',
component: MyInfo
},
{
path: '/Note',
name: 'Note',
component: Note
}
],
// mode: 'history'
mode: 'hash'
})
this.$router.push("/路径") --> <router-link to="/路径">
this.$router.push("/Note")
// 注意!!!!别写错,有个叫做this.$route
bug: 第一次点击跳转没事,再点一次报错
解决:
- 方式1: 设置异常捕获 (推荐)
// 在router中的index.js中加上以下代码,注意加在use之前写
const routerPush = Router.prototype.push;
Router.prototype.push = function (location) {
return routerPush.call(this, location).catch((err) => {});
};
- 方式2:
const currentRoute = this.$router.currentRoute;
if (currentRoute.path !== '/Note') {
this.$router.push({
path:"/Note",
query:{username:"社恐的少聪"}
})
}
16.7 参数的传递
16.7.1 声明式路由传参
在路由表中设参
export default new Router({
routes: [
...
{
path:'/MyInfo/:id', //设参
component:MyInfo
}
]
})
在App.vue中传参
<template>
<div id="app">
<ul>
<li>
<router-link to="/" tag="button">首页</router-link>
</li>
<li>
<!-- 跳转至MyInfo,并携带id 1001 -->
<router-link to="/MyInfo/1001">个人信息</router-link>
</li>
</ul>
<!-- router-view 用于显示匹配的组件,类似显示路由到的组件的区域,位置任意 -->
<router-view/>
</div>
</template>
<script>
...
</script>
<style>
...
</style>
<template>
<div>
<h1>个人信息</h1>
<span>id-->{{id}}</span>
</div>
</template>
<script>
export default {
name: "EmployeeList",
data:function(){
return {
id:this.$route.params.id // 注意是$route不是$router
}
}
}
</script>
<style scoped>
</style>
16.7.2 编程式路由传参
App.vue的编程跳转js中设置要传递的数据
methods:{
toNote(){
//this.$router.push("/Note")
this.$router.push({path:"/Note",query:{username:'老王'}})
}
}
Note.vue中接收参数
<template>
<div>
<h1>网站公告</h1>
<span>id --> {{id}}</span>
</div>
</template>
<script>
export default {
name: "Note",
data:function(){
return {
id:this.$route.query.username
// 注意是query,因为是按照路径方式发送,注意查看浏览器url
}
}
}
</script>
ps: 后续也可以通过VueX来完成传递数据
16.8 嵌套路由
创建三个组件页面Touxiang.vue,Family.vue,School.vue
在MyInfo组件中设置路由链接发出请求路 径,并且设置路由填充位
<template>
<div>
<h1>个人中心</h1>
<h3>id = {{id}}</h3>
<!-- /my/tx-->
<!-- /my/family-->
<!-- /my/school-->
<router-link to="/my/tx">头像</router-link>|
<router-link to="/my/family">家庭信息</router-link>|
<router-link to="/my/school">学校信息</router-link>|
<router-view></router-view>
</div>
</template>
在router/index.js中设置myinfo组件的子组件
{
path:'/my',
name:'MyInfo',
component:MyInfo,
children:[
// 子路径要与父类拼接成完整路径,此处不需要加/
{ path:'tx',component:Touxiang},
{ path:'family',component:Family},
{ path:'school',component:School},
]
},
<!-- MyInfo.Vue-->
<template>
<div>
<h1>个人中心</h1>
<h3>id = {{id}}</h3>
<!-- /my/tx-->
<!-- /my/family-->
<!-- /my/school-->
<router-link to="/my/1001/tx">头像</router-link>|
<router-link to="/my/1002/family">家庭信息</router-link>|
<router-link to="/my/1003/school">学校信息</router-link>|
<router-view></router-view>
</div>
</template>
{
path:'/my/:id',// :id是用来匹配 路由路径中的变量的
name:'MyInfo',
component:MyInfo,
children:[
// 子路径要与父类拼接成完整路径
{ path:'tx',component:Touxiang},
{ path:'family',component:Family},
{ path:'school',component:School},
]
},
子组件Touxiang.vue,Family.vue,School.vue中可以使用this.$route.params.id
取出路径中的数据1001,1002,1003
16.9 其他
路由重定向,导航守卫等等信息,查看官网自查
重定向| Vue Router (vuejs.org)
十七、 Vuex【重点】
17.1 什么是Vuex
17.2 安装
# 本例使用的vue2,所以安装vuex装的是vuex3!!! vue3对应的Vuex4
npm install vuex@3
17.3 配置 vuex
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
},
mutations: {
}
})
import Vue from 'vue'
import App from './App.vue'
// 引入路由模块
import router from './router'
// 引入Vuex模块
import store from './store'
Vue.config.productionTip = false
// vue2 创建方式
new Vue({
render: h => h(App),
router,
store // 使用Vuex
}).$mount('#app')
17.4 演示
17.4.1 存&取
// store/index.js文件的state中定义数据
export default new Vuex.Store({
state: {
username:"无名",
count:443,
tga:"tga"
},
mutations: {
}
})
在任何组件中使用 以下命令取值
this.$store.state.username
// username是state中定义的key
17.4.2 计算属性使用state[熟悉]
<template>
<div>
计算属性取值:{{num}}
</div>
</template>
<script>
export default {
name: "TestVueX",
computed:{ // 【注意: 计算属性的写法】
num() {
return this.$store.state.count
}
}
}
</script>
17.4.3 mapState[熟悉]
<template>
<div>
计算属性取值:{{count}}|
计算属性取值:{{tga}}|
计算属性取值:{{username}}|
</div>
</template>
<script>
// 【注意】 是 {} 引入
// 使用 import mapState from 'vuex' 的方式会将整个 vuex 模块导入,并将其中的 mapState 函数赋值给 mapState 变量。
// 而使用 import { mapState } from 'vuex' 的方式则是只导入 vuex 模块中的 mapState 函数
import {mapState} from 'vuex'
export default {
name: "TestVueX",
// 如果使用和状态名一样的计算属性名,还可以这样写
// 映射 this.count 为 store.state.count
// computed: mapState(['count','tga','username']),
// 如果有其他的计算属性,并且需要将vuex的state与其混合使用
// 可以使用对象展开运算符'...'
computed: {
// 使用对象展开运算符将此对象混入到外部对象中
// 映射为当前组件的计算属性
...mapState(['count','tga','username']),
},
}
</script>
<style scoped>
</style>
17.4.4 修改数据
// store/index.js文件的mutations中定义方法修改数据
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
username:"无名"
},
mutations: {
// 参数1 是Vuex-state对象
// 参数2 是其他组件使用时传过来的值,这个参数叫做payload
updateName(state,v){
state.username = v // 修改Vuex中的值
}
}
})
在其他组件中通过事件触发函数,在其中使用Vuex的方法修改数据
<template>
<div id="app">
<!-- 演示Vuex取值 -->
<h1>Vuex --> {{ username }}</h1>
<input v-model="name">
<button @click="editName">修改vuex中的值</button>
</div>
</template>
<script>
export default {
name: 'App',
methods: {
editName(){
// 修改Vuex数据
// updateName是 src/store/index.js中mutations中定义的函数名
this.$store.commit('updateName', this.name)
}
},
data: function () {
return {
// 从Vuex中取出数据
username: this.$store.state.username,
name:""
}
}
}
</script>
17.5.解决浏览器刷新后 Vuex 数据消失问题
- 问题描述
- 解决方案
-
安装插件
npm install vuex-persistedstate
-
配置
在/src/store/index.js中实现配置
import Vue from 'vue' import Vuex from 'vuex' // 引入持久化插件 import vuexPersistedstate from "vuex-persistedstate"; Vue.use(Vuex) export default new Vuex.Store({ state: { username:"无名66" }, mutations: { updateName(state,v){ state.username = v } }, plugins:[vuexPersistedstate()] // 加入插件 })
-
测试
浏览器刷新测试效果
17.6 其他Vuex知识
Vue总结
十八、Promise
18.1 以前ajax中的问题
// ajax async JavaScript and xml --> 异步请求技术
$.ajax({
url:'http://localhost:8080/login',
type:'get',
//data:'username=zs&password=123456',
data:{username:'zs',password:'123456'},
success:function(ret){
},
error:function(){
}
})
console.log()
演示:
像上面这样,下面的那个打印日志的结果是:
并没有将ajax中请求的结果拼接,因为ajax是异步请求,即执行ajax时,会不等待回调执行就会去执行后续代码,也就是说,执行那个输出日志时,ajax的回调可能还没执行呢
分别多测试几次
多次刷新,多次请求,会发现结果顺序跟代码的上下顺序并不一样.
假如,三个请求的结果确实需要等输出了hello1再输出hello2,最后输出hello3的话,就需要嵌套处理.
18.2 Promise
<script type="text/javascript">
var p = new Promise(function(resolve,reject){
/**
* resolve和reject都是方法
* 成功是调用resolve([参数])函数
* 失败时调用reject([参数])函数
*/
// 异步请求
$.ajax({
url:'http://localhost:8080/vue/hello',
success:function(data) {
resolve(data);
},
error:function(){
reject("出错啦");
}
})
});
p.then(function(ret){
console.log(ret);
},function(ret){
console.log(ret);
})
</script>
将以上代码封装成一个函数,就可以将jQuery中ajax嵌套调用的那种情况变得优雅一点
<script type="text/javascript">
function queryData(path){
var p = new Promise(function(resolve,reject){
/**
* resolve和reject都是方法
* 成功是调用resolve([参数])函数
* 失败时调用reject([参数])函数
*/
// 异步请求
$.ajax({
url:path,
success:function(data) {
resolve(data);
},
error:function(){
reject("出错啦");
}
})
});
return p;
}
queryData('http://localhost:8080/vue/hello1')
.then(function(ret){
console.log(ret);
})
</script>
十九、Axios【重点】
19.1 什么是 Axios
Axios 是一个开源的可以用在浏览器端和 NodeJS 的异步通信
框架,它的主要作用就是实现 AJAX 异步通信,其功能特点如下:
-
从浏览器中创建 XMLHttpRequests
-
从 node.js 创建
http 请求
-
支持 Promise API
-
拦截请求和响应
-
转换请求数据和响应数据
-
取消请求
-
自动转换 JSON 数据
-
客户端支持防御 XSRF(跨站请求伪造)
-
官网基本用例 | Axios 中文文档 | Axios 中文网 (axios-http.cn)
由于 Vue.js 是一个 视图层框架 并且作者(尤雨溪)严格准守 SoC (关注度分离原则),所以 Vue.js 并不包含 AJAX 的通信功能,为了解决通信问题,作者单独开发了一个名为 vue-resource 的插件,不过在进入 2.0 版本以后停止了对该插件的维护并推荐了 Axios 框架
19.2 Axios的使用
19.2.1 安装vue axios
npm install --save axios vue-axios
19.2.2 在需要使用的页面中引入
比如UserInfo.vue页面需要发请求,那就在页面的script中引入即可
import axios from 'axios'
19.2.3 发送axios请求
需求: 点击按钮,发送请求,从后端服务器获得部门列表,并且在前端使用表格table展示所有部门信息
<template>
<div>
<button @click="getInfo">查询数据</button>
<hr>
{{deptList}}
<hr>
<table>
<th>
部门编号
</th>
<th>
部门名称
</th>
<th>
部门地址
</th>
<tr v-for="dept in deptList">
<td>{{dept.deptno}}</td>
<td>{{dept.dname}}</td>
<td>{{dept.loc}}</td>
</tr>
</table>
</div>
</template>
<script>
// 引入axios
import axios from 'axios'
export default {
name: "TestAxios",
data(){
return {
deptList:null
}
},
methods:{
getInfo(){
// axios.get('/api/dept').then(function(ret){
// console.log(ret)
// this.deptList = ret.data // 【有bug,因为this问题】
// })
axios.get('/api/dept').then((ret)=>{
console.log(ret) // 【注意:这个返回值不一般】
// 详情请见19.4章节【19.4 Axios的响应】
// 可以查看官网https://www.axios-http.cn/docs/res_schema
this.deptList = ret.data.data
})
}
}
}
</script>
<style scoped>
</style>
19.2.4 服务端解决跨域问题
SpringBoot的controller层类上添加@CrossOrigin注解即可
19.2.5 BUG
在axios的回调中,无法使用this.数据 获得vuedata中的数据
造成axios取不到值得原因主要是this回调问题。当执行完函数function时,this指向放生变化。导致this指向函数体本身。这时this.data里的数据取不到。
简单直接的解决就是把function写成箭头函数形式,箭头函数不是构造函数,不会指定this,而是抓取上下文this作为自己的this
19.3 其他api演示
可以查看官网请求配置 | Axios 中文文档 | Axios 中文网 (axios-http.cn)
也可以看示例
<!-- get请求(1) 路径拼接参数 -->
axios.get('http://localhost:8080/vue/user?id=456').then(function(ret){
console.log(ret.data);
})
<!-- get请求(2) Restful风格参数 -->
axios.get('http://localhost:8080/vue/user/123').then(function(ret){
console.log(ret.data.);
})
<!-- get请求(3) 使用params传递参数 -->
axios.get('http://localhost:8080/vue/user',{
params:{
id:20001
}
}).then(function(ret){
console.log(ret.data);
})
<!-- post请求,发送的是json,后台需要使用@RequestBody -->
axios.post('http://localhost:8080/vue/user/json',{
username:'张三',
password:'987654'
}).then(function(ret){
console.log(ret.data);
})
<!-- put请求 -->
axios.put('http://localhost:8080/vue/user/form',{
username:'张三丰',
password:'11111'
}).then(function(ret){
console.log(ret.data);
}).catch(function (err){
console.log(err)
})
19.4 Axios的响应
19.5 axios的全局配置
19.6 响应拦截
二十、综合练习
前端vue+后端SpringBoot实现crud
附录
对象展开运算符
对象展开运算符 ...
(也称为扩展运算符)是一种用于展开对象或数组的语法,它允许将一个对象或数组拆分成单独的元素,并在其他对象或数组中使用。
在 JavaScript 中,...
运算符可以用在多种场景中,下面分别介绍它们的用法。
-
展开对象:
可以使用对象展开运算符...
来创建一个新对象,并将另一个对象中的属性和值复制到新对象中。这可以用于对象浅拷贝或对象合并。示例:
const obj1 = { name: 'John', age: 30 }; const obj2 = { ...obj1, city: 'New York' }; console.log(obj2); // 输出:{ name: 'John', age: 30, city: 'New York' }
-
合并对象:
将多个对象合并成一个新对象的简便方法。如果有相同的属性,后面的对象的属性值会覆盖前面的对象的属性值。示例:
const obj1 = { name: 'John', age: 30 }; const obj2 = { city: 'New York' }; const obj3 = { ...obj1, ...obj2 }; console.log(obj3); // 输出:{ name: 'John', age: 30, city: 'New York' }
-
展开数组:
在数组中使用...
可以将一个数组展开为独立的元素,可以用于创建一个新数组或者在函数调用时传递参数。示例:
const arr1 = [1, 2, 3]; const arr2 = [...arr1, 4, 5]; console.log(arr2); // 输出:[1, 2, 3, 4, 5]
const arr = [1, 2, 3]; someFunction(...arr); // 将数组中的元素作为参数传递给函数
password:‘987654’
}).then(function(ret){
console.log(ret.data);
})
axios.put(‘http://localhost:8080/vue/user/form’,{
username:‘张三丰’,
password:‘11111’
}).then(function(ret){
console.log(ret.data);
}).catch(function (err){
console.log(err)
})
## 19.4 Axios的响应
> 官网: https://www.axios-http.cn/docs/res_schema
>
> 响应结果的主要属性:
>
> - data: 服务器响应回的数据
> - headers: 响应头信息
> - status: 响应状态码
> - statusText: 响应状态信息
>
> ---
>
> **需要特别注意**,我们后台返回的数据在data中,即data中是后台返回的R,我们ret.data获得到的是R,如果还有继续获得其中的数据,还需要再ret.data.data
## 19.5 axios的全局配置
> 官网: [默认配置 | Axios 中文文档 | Axios 中文网 (axios-http.cn)](https://www.axios-http.cn/docs/config_defaults)
> 我们讲一个特别实用的,我们在项目中调用数十次乃至百次接口是很常见的,后期一旦根域名发生改变,所有接口都需要修改,非常繁琐且容易出错。
>
> **axios提供了设置根域名的方法**。
> 在main.js全局入口文件中,设置:
>
> ```js
> import axios from "axios";
> axios.defaults.baseURL = 'http://localhost:8888'
> ```
>
> 在其他vue页面中使用axios发请求的时候
>
> ```js
> axios.get('/api/dept').then((ret)=>{
> console.log(ret)
> this.deptList = ret.data.data
> })
> ```
## 19.6 响应拦截
> 还有请求拦截,暂时用不上先不讲
> 响应拦截可以拦截到axios发请求后的那个回调response对象,然后对其进行处理
>
> - 实战,将response数据简化后返回
>
> ```js
> // 添加Axios响应拦截器
> axios.interceptors.response.use(function (response) {
> //console.log('响应拦截',response)
> return response.data;
> }, function (error) {
> console.log(error)
> });
> ```
>
> 这样,在使用axios的页面,从回调中获得数据时,只需要ret.data,而不需要再ret.data.data
# 二十、综合练习
前端vue+后端SpringBoot实现crud
> 登录
[外链图片转存中...(img-3mzvrhim-1702287645913)]
> 跳转主页,查询全部
[外链图片转存中...(img-0xdwLdq2-1702287645914)]
> 主页按钮,点击跳转添加页面(注意是子路由)
[外链图片转存中...(img-SwTM49Pk-1702287645914)]
> 表格每行后有更新按钮,点击跳转更新页面,要携带数据,因为要查询数据回显(组件间传值)
[外链图片转存中...(img-wexw5r9W-1702287645914)]
> 删除
> 模糊搜索
[外链图片转存中...(img-QQG4SE1D-1702287645914)]
# 附录
## 对象展开运算符
对象展开运算符 `...`(也称为扩展运算符)是一种用于展开对象或数组的语法,它允许将一个对象或数组拆分成单独的元素,并在其他对象或数组中使用。
在 JavaScript 中,`...` 运算符可以用在多种场景中,下面分别介绍它们的用法。
1. 展开对象:
可以使用对象展开运算符 `...` 来创建一个新对象,并将另一个对象中的属性和值复制到新对象中。这可以用于对象浅拷贝或对象合并。
示例:
```js
const obj1 = { name: 'John', age: 30 };
const obj2 = { ...obj1, city: 'New York' };
console.log(obj2);
// 输出:{ name: 'John', age: 30, city: 'New York' }
-
合并对象:
将多个对象合并成一个新对象的简便方法。如果有相同的属性,后面的对象的属性值会覆盖前面的对象的属性值。示例:
const obj1 = { name: 'John', age: 30 }; const obj2 = { city: 'New York' }; const obj3 = { ...obj1, ...obj2 }; console.log(obj3); // 输出:{ name: 'John', age: 30, city: 'New York' }
-
展开数组:
在数组中使用...
可以将一个数组展开为独立的元素,可以用于创建一个新数组或者在函数调用时传递参数。示例:
const arr1 = [1, 2, 3]; const arr2 = [...arr1, 4, 5]; console.log(arr2); // 输出:[1, 2, 3, 4, 5]
const arr = [1, 2, 3]; someFunction(...arr); // 将数组中的元素作为参数传递给函数