Vue
vue官网:https://cn.vuejs.org/
一、Vue概述
1. Vue简介
Vue是一个渐进式(真正用到才引用)的JavaScript框架与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。
Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,与现代化的工具以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
Vue.js属于SPA一员。
英文全称:Single Page Web Application ,SPA。
中文全称:单页Web应用。
整个应用就一个页面,客户端页面通过与服务端的交互动态更新页面中内容。
2.1 优点
符合前后端分离工作模式:单页面应用可以结合Restful,符合前后端分离开发。
良好的用户体验:应用没有页面跳转,全是局部刷新,整体页面更流畅。
减轻服务器端压力:由于都是局部刷新对服务器压力更小。
多平台共享:无论是移动端、电脑端都可以共享服务端接口。
2.2 缺点
首页渲染耗时长首页需要一次加载多个请求,渲染时间可能会比较长。
3. MVVM介绍
MVVM (Model-View-ViewModel)是一种软件架构设计模式,Vue是基于Mvvm设计的前端框架;
MVVM分为M、V、VM:
-
M(Model) 也就是页面中单独数据。
-
V (View)是页面中HTML结构。
-
VM(View-Model) 当V需要调用M中数据时,由VM做中间处理。
MVVM 源自于经典的MVC (ModI-View-Controller) 模式。MVVM的核心是ViewModel层,负责转换Model中的数据对象来让数据变得更容易管理和使用,其作用如下:
-
该层向上与视图层进行双向数据绑定
-
Vue 是 MVVM 模式的实现者
-
m model
-
数据层 Vue 中 数据层 都放在 data 里面
-
-
v view 视图
-
Vue 中 view 即 我们的HTML页面
-
-
vm (view-model) 控制器 将数据和视图层建立联系
-
二、Vue模板语法
Vue.js 使用了基于 HTML 的模板语法,允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据。
所有 Vue.js 的模板都是合法的 HTML,所以能被遵循规范的浏览器和 HTML 解析器解析。
在底层的实现上,Vue 将模板编译成虚拟 DOM 渲染函数。
结合响应系统,Vue 能够智能地计算出最少需要重新渲染多少组件,并把 DOM 操作次数减到最少。
1. 基础指令
1.1 Vue插值表达式
<div id="app"> {{ 2*3 + message + '你好 vue'}} </div> <script> Vue.config.productionTip = false; var app = new Vue({ el: '#app', data: { message: 'Hello Vue!' } }) </script>
1.2 v-cloak 指令
为防止插值表达式出现闪烁问题,可以使用v-cloak指令解决。
<style> /* 定义 v-cloak 的样式,使元素隐藏 通过给 <div> 元素添加 v-cloak 属性,并定义对应的 CSS 样式, 可以确保在 Vue 实例加载完成之前,该元素的内容不会显示在页面上。 */ [v-cloak]{ display: none; } </style> </head> <body> <!-- 添加 v-cloak 属性 --> <div id="app" v-cloak> {{ 2*3 + message + '你好 vue'}} </div>
1.3 v-text 指令
v-text指令用于将数据填充到标签中,作用于插值表达式类似,但是没有闪动问题;如果数据中有HTML标签会将html标签直接输出。
<div id="app"> <p v-text="age"></p> </div> <script> Vue.config.productionTip = false; var app = new Vue({ el: '#app', data: { age: 18 } }) </script>
1.4 v-html 指令
<div id="app"> <p v-html="name"></p> </div> <script> Vue.config.productionTip = false; var app = new Vue({ el: '#app', data: { name: '<b>Arvin</b>' } }) </script>
1.5 v-pre 指令
显示原始信息跳过编译过程,跳过这个元素和它的子元素的编译过程。
<div id="app" v-pre> <!-- 直接输出{{message}} --> {{message}} <!-- 不输出 --> <p v-text="age"></p> <!-- 不输出 --> <p v-html="name"></p> <!-- 输出 --> <p>你好啊</p> </div> <script> Vue.config.productionTip = false; var app = new Vue({ el: '#app', data: { message: 'Hello Vue!', age: 18, name: '<b>Arvin</b>' } }) </script>
1.5 v-once 指令
执行一次性的插值,当数据改变时,插值处的内容不会继续更新。
<div id="app"> <!-- 页面加载后只渲染一次,即使message数据改变也不会重新渲染--> <p v-once>{{message}}</p> </div> <script> Vue.config.productionTip = false; var app = new Vue({ el: '#app', data: { message: 'Hello Vue!' } }) </script>
2. Vue的双向绑定指令
什么是双向绑定?
-
input中的v-model绑定了message,所以会实时将输入的内容传递给message,message发生改变。
-
message发生改变时,将message的值插入到DOM中,所以DOM会发生响应的改变。
注意:v-model是双向绑定指令,只能使用在 <input>、<select>、<textarea>
等表单组件中使用。
3. Vue的事件指令
3.1 v-on 指令
<div id="app"> <!-- 方法名() | 方法名 --> <button v-on:click="fun1">点击</button> <button @click="fun2">清零</button> <p>您点击了 {{count}} 次</p> </div> <script> Vue.config.productionTip = false; var app = new Vue({ el: '#app', data: { count: 0 }, methods: { fun1(){ ++this.count; }, fun2(){ if (confirm("是否归零")){ this.count = 0; } } } }) </script>
3.2 v-on 传入参数
-
-
@click="方法名()" 或 v-on:click="方法名()":不会传递事件对象作为参数,若要传递需要写一个名为$event的参数
-
<div id="app"> <button @click="fun1">按钮1</button> <button @click="fun2($event,2)">按钮2</button> <button @click="fun3(1, $event)">按钮3</button> </div> <script> Vue.config.productionTip = false; var app = new Vue({ el: '#app', data: { count: 1 }, methods: { fun1(e){ console.log(e); }, fun2(e){ console.log(e); }, fun3(i, e){ console.log(i, e); } } }) </script>
3.4 事件修饰符
1. stop
<div id="app"> <div @click="fun1" style="border: 1px solid black"> <button @click.stop="fun2">按钮</button> </div> </div> <script> Vue.config.productionTip = false; var app = new Vue({ el: '#app', data: { count: 1 }, methods: { fun1(){ console.log("fun1"); }, fun2(){ console.log("fun2"); } } }) </script>
@click.self或v-on:click.self 只当事件在该元素本身触发时。
<div id="app"> <div @click.self="fun1" style="border: 1px solid black"> <button @click="fun2">按钮</button> </div> </div> <script> Vue.config.productionTip = false; var app = new Vue({ el: '#app', data: { count: 1 }, methods: { fun1(){ console.log("fun1"); }, fun2(){ console.log("fun2"); } } }) </script>
3. prevent
@click.prevent或v-on:click.self阻止事件的默认行为。
例如:超链接跳转,表单submit按钮提交等。
<div id="app"> <a href="http://www.baidu.com" @click.prevent>百度</a> <a href="http://www.baidu.com" @click.prevent="fun1">百度</a> </div> <script> Vue.config.productionTip = false; var app = new Vue({ el: '#app', methods: { fun1(){ console.log("fun1"); } } }) </script>
4. once
@click.once 或v-on:click.once 事件只触发一次。
<div id="app"> <div> <button @click.once="fun1">按钮</button> </div> </div> <script> Vue.config.productionTip = false; var app = new Vue({ el: '#app', data: { count: 1 }, methods: { fun1(){ console.log("fun1"); } } }) </script>
3.5 按键修饰符
在监听键盘事件时,我们经常需要检查详细的按键。Vue 允许为v-on
在监听键盘事件时添加按键修饰符。.enter .tab .delete (“删除”和“退格”键) .esc .space .up .down .left .right
.其它按键 https://www.cnblogs.com/LinkinPark/p/5233127.html
<!-- keyup键盘抬起,keydown键盘按下 --> <div id="app"> <input type="submit" @keyup.enter="fun1"> <button id="btn" @keyup.right="fun2">按钮</button> </div> <script> Vue.config.productionTip = false; var app = new Vue({ el: '#app', data: { count: 0 }, methods: { fun1(){ console.log("提交"); }, fun2(e) { e.srcElement.style.marginLeft = (this.count+=10) +"px"; } } }) </script>
3.6 系统修饰键
可以用如下修饰符来实现仅在按下相应按键时才触发鼠标或键盘事件的监听器。
-
.ctrl
-
.alt
-
.shift
<!-- Alt + C --> <input @keyup.alt.67="clear"> <!-- Ctrl + Click --> <div @click.ctrl="doSomething">Do something</div>
4. Vue 属性绑定指令
4.1 v-bind 基本使用
<div id="app"> <img :src="path"> </div> <script> Vue.config.productionTip = false; var app = new Vue({ el: '#app', data: { path: '4.png' } }) </script>
4.2 v-bind 绑定对象
<head> <meta charset="UTF-8"> <title>Title</title> <script src="js/vue.js"></script> <style> .a{ height: 100px; } .b{ width: 100px; } </style> </head> <body> <div id="app"> <img :src="path" :class="{a:h,b:w}"> </div> <script> Vue.config.productionTip = false; var app = new Vue({ el: '#app', data: { path: '4.png', h: true, w: true } }) </script> </body>
4.3 v-bind 绑定数组
v-bind可以绑定数组,数组元素是data的数据。
<head> <meta charset="UTF-8"> <title>Title</title> <script src="js/vue.js"></script> <style> .a{ height: 100px; } .b{ width: 100px; } </style> </head> <body> <div id="app"> <img :src="path" :class="[h,w]"> </div> <script> Vue.config.productionTip = false; var app = new Vue({ el: '#app', data: { path: '4.png', h: 'a', w: 'b' } }) </script> </body>
-
绑定对象的时候 对象的属性 即要渲染的类名 对象的属性值对应的是 data 中的数据。
-
4.4 绑定style
v-bind可以直接绑定style,style的内容可以是对象,可以是数组。
<div id="app"> <span :style="{border:br, fontSize:fz}">span1</span> <span :style="[style1, style2]">span2</span> </div> <script> Vue.config.productionTip = false; var app = new Vue({ el: '#app', data: { br: '1px solid black', fz: "30px", style1: { color: "red" }, style2:{ fontSize: '20px' } } }) </script>
1. 分支结构
1.1 v-if
示例1:
<div id="app"> <span v-if="name != null">{{name}}</span> </div> <script> Vue.config.productionTip = false; var app = new Vue({ el: '#app', data: { name: "zs" } }) </script>
示例2:
<div id="app"> <span v-if="name == 'zs'">aa</span> <span v-else-if="name == 'ls'">bb</span> <span v-else>cc</span> </div> <script> Vue.config.productionTip = false; var app = new Vue({ el: '#app', data: { name: "ls" } }) </script>
1.2 v-show
v-show 可以判断标签隐藏或显示。
<div id="app"> <button v-show="flag">按钮</button> </div> <script> Vue.config.productionTip = false; var app = new Vue({ el: '#app', data: { flag: true } }) </script>
1.3 v-if 与 v-show 的区别
-
v-show本质就是标签display设置为none,控制隐藏
-
v-show只编译一次,后面其实就是控制css,而v-if不停的销毁和创建,故v-show性能更好一点。
-
-
v-if是动态的向DOM树内添加或者删除DOM元素
-
v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件
-
2. 循环结构
v-for 可以遍历数组也可以遍历对象。
示例,遍历数组:
<div id="app"> <p :key="str" v-for="(str, i) in strs"> {{str}} </p> </div> <script> Vue.config.productionTip = false; var app = new Vue({ el: '#app', data: { strs:[ "aa","bb","cc" ] } }) </script>
v-for="(value,index) in arr"
-
strs:遍历的数组名
-
str:遍历出的每个元素
-
i:遍历出的每个元素索引
:key 的作用:
-
key来给每个节点做一个唯一标识
-
key的作用主要是为了高效的更新虚拟DOM
示例,遍历对象:
<div id="app"> <p :key="i" v-for="(v, k, i) in user"> {{k + " : " +v}} </p> </div> <script> Vue.config.productionTip = false; var app = new Vue({ el: '#app', data: { user: { id: 1, name: '二麻子', age: 18 } } }) </script>
v-for="(v,k,i) in user"
-
user:遍历的对象名
-
v:遍历对象的value
-
k:遍历对象的key
-
i:遍历对象的索引
key 的作用
-
key来给每个节点做一个唯一标识
-
五、Vue 表单操作
1. 表单基本操作
可以通过v-model双向绑定操作表单

<div id="app"> <form action="http://psjj.top/java"> <div> 姓名:<input type="text" id="username" v-model="username"/> </div> <div> 性别: <label for="male">男</label> <input type="radio" id="male" v-model="gender" name="gender" value="男"/> <label for="female">女</label> <input type="radio" id="female" v-model="gender" name="gender" value="女"/> </div> <div> 爱好: <label for="chouyan">抽烟</label> <input type="checkbox" id="chouyan" v-model="hobby" name="hobby" value="抽烟" checked/> <label for="hejiu">喝酒</label> <input type="checkbox" id="hejiu" v-model="hobby" name="hobby" value="喝酒"/> <label for="code">写代码</label> <input type="checkbox" id="code" v-model="hobby" name="hobby" value="写代码"/> </div> <div> 地址: <select v-model="address"> <option value="0">请选择</option> <option value="北京">北京</option> <option value="上海">上海</option> <option value="广州">广州</option> </select> </div> <div> 个人简介:<textarea v-model="desc"></textarea> </div> <div> <input type="submit" value="提交" @click.prevent='login'> </div> </form> </div> <script> Vue.config.productionTip = false; var app = new Vue({ el: "#app", data: { username: '', /* 设置单选框默认值 */ gender: '男', /* 设置复选框默认值 */ hobby: ['抽烟'], /* 设置下拉列表默认值 */ address: 0, desc: '' }, methods: { login() { console.log(this.username); console.log(this.gender); console.log(this.hobby); console.log(this.address); console.log(this.desc); } } }); </script>
2. 表单修饰符
-
.number 转换为数值。
-
.trim 自动过滤用户输入的首尾空白字符。
-
.lazy 将input事件切换成change事件,在失去焦点 或者 按下回车键时才更新。
六、Vue自定义指令
-
全局自定义指令。
-
1. 全局自定义指令
自定义全局指令:
<div id="app"> <input type="text" v-myfocus> </div> <script> Vue.config.productionTip = false; Vue.directive('myfocus', { inserted: function (val) { console.log(val); /* 元素获得焦点 */ val.focus(); } }); var app = new Vue({ el: "#app" }); </script> </body>
<div id="app"> <button v-mycolor="color">按钮</button> </div> <script> Vue.config.productionTip = false; Vue.directive('mycolor', { bind: function (val, binding) { console.log(val); console.log(binding); /* 修改背景颜色, binding对象中的value属性为v-mycolor的属性值 */ val.style.backgroundColor = binding.value; } }); var app = new Vue({ el: "#app", data:{ color: 'green' } }); </script>
注意:使用时要在前面加上 v-
2. 局部自定义指令
-
-
局部指令只能在当前组件里面使用。
-
<body> <div id="app"> <button v-mycolor="color">按钮</button> </div> </body> <script> Vue.config.productionTip = false; var vm = new Vue({ el: '#app', data:{ color: 'red' }, directives:{ mycolor:{ bind: function(el,binding){ el.style.backgroundColor = binding.value; } } } }) </script>
七、Vue计算属性 监听器 过滤器
1. 计算属性 computed
<div id="app"> <!-- 插值表达时中允许直接调用方法。--> <!-- 调用methods中的方法时必须为方法名(),()不能省略) --> <p>{{fun1()}}</p> <hr> <!-- 调用computed中的方法时必须为方法名,不能添加() --> <p>{{fun2}}</p> </div> <script> Vue.config.productionTip = false; var app = new Vue({ el: "#app", methods: { fun1(){ return Math.random(); } }, computed: { fun2(){ return Math.random(); } } }); </script>
2. 监听器 watch
<div id="app"> 用户名:<input type="text" v-model="name"> <p> <span>{{name}}</span> </p> </div> <script> Vue.config.productionTip = false; var app = new Vue({ el: "#app", data: { name: 'zs' }, watch: { name: function (val) { console.log(val); } } }); </script>
3. 过滤器 filter/filters
-
-
过滤器可以用在两个地方:双花括号插值和v-bind表达式。
-
过滤器应该被添加在JavaScript表达式的尾部,由“管道”符号指示。
-
过滤器不是真的修改
data
,而只是改变渲染的结果,并返回过滤后的版本。 -
<div id="app"> <p> {{name | myfilter1}} </p> <p> {{msg | myfilter2}} </p> </div> <script> <!-- 全局过滤器--> Vue.filter('myfilter1', function (val) { console.log(val); return val.toUpperCase(); }); var app = new Vue({ el: "#app", data: { name: 'zs', msg: 'Hello Vue' }, <!-- 局部过滤器--> filters: { myfilter2: function (val) { return val.toLowerCase(); } } }); </script>
过滤器传递参数:

<div id="app"> <p> {{name | myfilter1(1)}} </p> <p> {{msg | myfilter2(2)}} </p> </div> <script> <!-- val是过滤的data,len是传入的参数--> Vue.filter('myfilter1', function (val, len) { console.log(val); return val.substr(0, len); }); var app = new Vue({ el: "#app", data: { name: 'zs', msg: 'Hello Vue' }, filters: { myfilter2: function (val, len) { return val.substr(0, len); } } }); </script>
八、Vue生命周期
2. 钩子函数
在Vue.js中,钩子函数是一种特殊函数,它们在组件的生命周期中被调用。
这些函数在组件被创建、更新和销毁时执行,可以在这些关键时刻执行特定的任务。
-
-
created:在创建实例之后进行调用。
-
beforeMount:页面加载完成,没有渲染。如:此时页面还是{{name}}
-
mounted:我们可以将他理解为原生 js 中的 window.onload=function({.,.}),或许大家也在用 jquery,所以也可以理解为 jquery 中的$(document).ready(function(){….}),它的功能就是: 在 dom 文档渲染完毕之后将要执行的函数, 该函数在 Vue1.0 版本中名字为compiled。 此时页面中的{{name}}已被渲染成张三
-
beforeDestroy: 在实例销毁之前调用,包括解绑事件和清理所有计时器。
-
destroyed: 在实例销毁后调用,此时可以进行一些清理工作。
- beforeUpdate: 在实例更新之前调用,包括重新计算属性、观察属性和调用子组件的beforeUpdate。
- updated: 在实例更新完成后调用,此时实例已经重新渲染。
九、Vue 数组内容渲染
描述 | |
---|---|
push() |
往数组最后面添加一个元素,成功返回当前数组的长度 |
pop() |
删除数组的最后一个元素,成功返回删除元素的值 |
shift() |
删除数组的第一个元素,成功返回删除元素的值 |
unshift() |
往数组最前面添加一个元素,成功返回当前数组的长度 |
splice() |
参数1:想要删除的元素的下标 参数2:删除的元素个数 参数3:删除位置添加的新元素 |
sort() |
sort() 使数组按照字符编码默认从小到大排序,成功返回排序后的数组 |
reverse() |
<div id="app"> <p>{{strs}}</p> <p> <button @click="fun1">按钮1</button> </p> </div> <script> let app = new Vue({ el: "#app", data: { strs: [ "bb", "aa", 'cc' ] }, methods:{ fun1(){ var number = this.strs.push("dd"); console.log(number); } } }); </script>
2. 操作数组
方法 | 描述 |
---|---|
forEach() | 数组遍历 |
filter() | 过滤数组中元素 |
some() | 当有一个元素满足条件时,some方法返回true,否则返回false |
concat() | |
slice() | 数组中元素截取 |
<div id="app"> <p>{{strs}}</p> <p> <button @click="fun1">按钮1</button> <button @click="fun2">按钮2</button> </p> </div> <script> var app = new Vue({ el: "#app", data: { strs: [ "bb", "aa", 'cc' ] }, methods:{ fun1(){ var a = this.strs.filter(function (v) { console.log(v); if (v == 'bb' || v == 'cc') return v; }); console.log(a); }, fun2() { var b = this.strs.filter(v => { if (v == 'bb' || v == 'cc') return v; }); console.log(b); } } }); </script>
十、组件
1. 非单文件组件
组件的开发步骤:
1. 定义组件(创建组件)
2. 注册组件(局部组件组要手动注册)
3. 使用组件(写组件标签)- 组件分为全局组件和局部组件
1.1 全局组件
①创建组件
全局组件创建后会自动注册。
语法格式:
Vue.component('自定义组件名', { 组件内容 })
Vue.component("my-component", { //不可以写el,最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器 //组件中的html代码及数据 template: '<button @click="fun1">{{name}}点击了{{count}}</button>', //避免组件被复用时,数据存在引用关系 data() { return { count: 0, name: '按钮' } }
命名规范:
-
-
第一种写法(首字母小写):school
-
第二种写法(首字母大写):School
-
-
多个单词组成:
-
第一种写法(kebab-case命名):my-school
-
第二种写法(CamelCase命名):MySchool (需要Vue脚手架支持)
-
-
注意事项:
-
组件名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行。
-
当使用 kebab-case (短横线分隔命名) 定义一个组件时,必须在引用时使用 kebab-case,例如
<my-component-name>
。 -
当使用 PascalCase (首字母大写命名) 定义一个组件时,你在引用这个自定义元素时两种命名法都可以使用。也就是说
<my-component-name>
和<MyComponentName>
-
1.2 局部组件
-
-
局部组件注册后,只用引用了局部组件的vue实例
语法格式:
const 组件名 = { 组件内容 }
vue对象中使用components属性注册局部组件
// 方式一: /* 创建局部组件 */ const MyComponent1 = { data () { return { name: '按钮1' } }, template: '<button>{{name}}</button>' }; // 方式二: /* 创建局部组件 */ const MyComponent2 = Vue.extend({ data() { return { name: '按钮2' } }, template: '<button>{{name}}</button>' });
②注册组件
const app = new Vue ({ el: '#app', /* 注册局部组件 */ components: { MyComponent1, MyComponent2 } });
③使用
只有注册了局部组件的vue实例才能使用该局部组件
1.3 组件的嵌套
//定义student组件 const student = Vue.extend({ template: ` <div> <h2>学生名称:{{name}}</h2> <h2>学生年龄:{{age}}</h2> </div> `, }); //定义school组件 const school = Vue.extend({ template: ` <div> <h2>学校名称:{{name}}</h2> <h2>学校地址:{{address}}</h2> <student></student> </div> `, /* 注册student组件 */ components: { student },
2. 单文件组件
2.1 .vue格式文件
一个典型的.vue文件包含三个部分:模板(template)、样式(style)和脚本(script)。
2.2 mian.js
以vue2语法为例
import Vue from 'vue' import App from './App.vue' Vue.config.productionTip = false new Vue({ el:'#app', // 简写形式 render: h => h(App), // 完整形式 // render(createElement){ // return createElement(App) // } })
vue.js 是完整版的 Vue,包含:核心功能+模板解析器。
vue.runtime.xxx.js 是运行版的 Vue,只包含核心功能,没有模板解析器。
-
-
scoped
样式一般不会在App.vue
-
组件的 DOM 结构、Style 样式要尽量复用。
-
组件中要展示的数据,尽量由组件的使用者提供。
为了方便使用者为组件提供要展示的数据,vue 组件提供了 props 的概念。
props: ["mymsg", "mylist"], /* 接收的同时对数据进行类型限制 */ props:{ mymsg: String, mylist: Object }, /* 接收的同时对数据进行类型限制 + 指定默认值 + 限制必要性 */ props:{ mymsg:{ type: String, default: "默认值" }, mylist:{ type: Array, equired: true } },
父组件:
<组件名 :mymsg="父组件中的数据" />
3. 自定义事件
要想通过子组件向父组件传递数据,可以自定义事件
3.1 介绍
-
一种组件间通信的方式,适用于:子组件 与 父组件。
-
使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调在A中)。
-
触发自定义事件:
<template> <div class='Demo'> <h2>学校名称:{{name}}</h2> <h2>学校地址:{{address}}</h2> <button @click="send">点击按钮向父组件传递数据</button> </div> </template> <script> /* 创建并导出组件 */ export default { name: 'MySchool', data() { return { name: '北大', address: '北京' } }, methods: { send() { /* 参数1:驱动自定义事件 getSchoolName 执行 参数2:传递的参数 */ this.$emit("getSchoolName", this.name); } } } </script>
父组件:
<template> <!-- 使用组件 --> <div> <!-- 子组件给父组件传值:借助于自定义事件 getSchoolName --> <my-school @getSchoolName="showName"/> </div> </template> <script> /* 导入组件 */ import MySchool from './components/MySchool.vue' /* 创建并导出组件 */ export default { name: 'App', /* 父组件中的数据 */ data() { return { msg: 'app父组件中的数据', } }, methods: { showName(name){ console.log("父组件中数据:", name); } }, /* 注册组件 */ components: { MySchool } } </script>
4. 全局事件总线
它必须满足以下条件:
- 所有的组件对象都必须能使用它。
- 这个对象必须能够使用
$on
、$emit
和$off
import Vue from 'vue' import App from './App.vue' Vue.config.productionTip = false new Vue({ el:'#app', render: h => h(App), beforeCreate() { Vue.prototype.$bus = this //安装全局事件总线 } })
②子组件1(提供数据的组件)
<template> <div class='Demo'> <h2>学校名称:{{name}}</h2> <h2>学校地址:{{address}}</h2> <button @click="send1">点击按钮向兄弟组件传递数据</button> </div> </template> <script> /* 创建并导出组件 */ export default { name: 'MySchool', data() { return { name: '北大', address: '北京' } }, methods: { send1() { console.log("MySchool组件中数据:", this.address); this.$bus.$emit("getSchoolAddress", this.address); } } } </script>
③子组件2(获取数据的组件)
<template> <div class="Demo"> </div> </template> <script> /* 创建并导出组件 */ export default { name:'MyStudent', methods: { getSchoolAddress(addr){ console.log("MyStudent中接收的数据:", addr); } }, mounted() { this.$bus.$on('getSchoolAddress',this.getSchoolAddress) } } </script>
5. mixin混入
作用:
将组件的公共逻辑或者配置提取出来,哪个组件需要用到时,直接将提取的这部分混入到组件内部即可。这样既可以减少代码冗余度,也可以让后期维护起来更加容易。
5.1 创建js文件
export const mixin = { methods: { //自定义的方法 show() { console.log("哪个组件调用了该方法this为哪个组件对象", this); } }, data() { return { msg: '混入对象中的数据' } }, created() { console.log("我是mixin中的created生命周期函数", "mixin被创建了"); }, mounted() { console.log("我是mixin中的mounted生命周期函数", "dom中元素完成了渲染"); } };
5.2 局部混入
<template> <div id='Demo'> <!-- 局部混入第3步:获取混入中数据 --> <h2>混入中的数据:{{msg}}</h2> <!-- 调用混入对象中方法 --> <button @click="show">按钮</button> </div> </template> <script> /* 局部混入第1步:导入混入对象 */ import {mixin} from '../index.js' /* 创建并导出导出组件 */ export default { name:'MySchool', /* 局部混入第2步:注册混入对象 */ mixins: [mixin] } </script>
5.3 全局混入
在main.js导入并注册混入,所有组件就可以使用混入
import Vue from 'vue' import App from './App.vue' /* 引入index.js */ import {mixin} from './index' Vue.config.productionTip = false; /* 设置混入对象 */ Vue.mixin(mixin); new Vue({ el:"#app", render: h => h(App) });
6. WebStorage
6.1 介绍
浏览器端通过window.sessionStorage
和window.localStorage
<script> export default { name: "WebStorageComponent", methods: { //保存数据 saveData() { sessionStorage.setItem("uname", "zs"); sessionStorage.setItem("pwd", "123"); }, //读取数据 readData() { var uname = sessionStorage.getItem("uname"); var pwd = sessionStorage.getItem("pwd"); console.log(uname, pwd); }, //删除数据 deleteData() { sessionStorage.removeItem("uname"); }, //清空数据 deleteAllData() { sessionStorage.clear(); } } } </script>
十二、前后端交互
1. axios
axios是一个基于promise的HTTP客户端,可以用在浏览器和Node.js环境中。它提供了一个简单的API,可以轻松地发送HTTP请求和处理响应。
它支持浏览器和Node.js中的一系列HTTP方法,包括GET、POST、PUT、DELETE等,并且可以在请求中添加自定义的headers和参数
在服务端axios使用原生的nodejs的http模块,在客户端浏览器中使用XmlHttpRequest,本质是对XHR的封装。
-
从浏览器创建
-
自动转换 JSON 数据
-
转换请求和响应数据
-
拦截请求和响应
-
取消请求
-
cnpm install --save axios
3. 传统请求
前后端分离项目,后端要注意允许跨越访问
前端要导入axios
//导入axios对象 import axios from 'axios'
3.1 Get请求
fun1() { //发送get请求 axios.get("http://127.0.0.1:8888/queryById?id=1") //成功回调的函数,参数为响应对象 .then(res => { console.log(res.data); }) //失败回调的函数,参数为异常对象 .catch(ex => { console.log(ex); }) }, fun2() { //发送get请求 axios.get("http://127.0.0.1:8888/queryById", { params: { id: 1 } }) //成功回调的函数,参数为响应对象 .then(res => { console.log(res.data); }) //失败回调的函数,参数为异常对象 .catch(ex => { console.log(ex); }) }
3.2 Post请求
fun1() { //发送post请求,请求内容类型 Content-Type: application/json axios.post("http://127.0.0.1:8888/add", { id: 3, sname: 'ww', age: 25 }).then(res => { console.log(res.data); }) .catch(ex => { console.log(ex); }) }
这里要注意由于axios发送请求默认的ContentType为 application/json,
所以后端接收数据需要使用@RequestBody注解,而且必须为引用类型(包装类不可以)
@RequestBody是spring提供的注解,用于将接收到的json格式数据转换为List、javaBean、List、Map等
4. Restful请求
methods: { fun1() { axios.get("http://127.0.0.1:8888/clazz/1") .then(res => { console.log(res.data); }) }, fun2() { axios.delete("http://127.0.0.1:8888/clazz/1") .then(res => { console.log(res.data); }) }, fun3(){ axios.post("http://127.0.0.1:8888/clazz", { id: 1, cname: "Vue 班" }).then(res => { console.log(res.data); }) }, fun4(){ axios.put("http://127.0.0.1:8888/clazz", { id: 2, cname: "Ajax 班" }).then(res => { console.log(res.data); }) } }
5. axios全局配置
main.js
import Vue from 'vue' import App from './App.vue' import axios from 'axios' // 配置公共的请求基础路径 axios.defaults.baseURL = 'http://127.0.0.1:8888'; // 配置 超时时间 axios.defaults.timeout = 2500; // 配置公共的请求头 axios.defaults.headers['uname'] = 'zs'; // 配置公共的 post 的 Content-Type //axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'; Vue.config.productionTip = false; new Vue({ render: h => h(App), }).$mount('#app');
十三、slot插槽
1. 默认插槽
也叫匿名插槽
<slot>插槽1</slot>
使用:
<CategoryComponent>
插入的内容
</CategoryComponent>
注意:当没有插入内容时,会显示<slot>标签的内容
2. 具名插槽
<slot name="body">插槽2</slot>
比默认插槽多了个name属性
可以根据name插入到指定的插槽中
<CategoryComponent > <h5 slot="footer">插入内容</h5> </CategoryComponent>
3. 作用域组件
作用域组件可以将子组件中的数据传递给调用者
<slot :games="suiyi">我是一些默认值,当使用者没有传递具体结构时,我会出现</slot> //...省略 data() { return { games:[ '植物大战僵尸','红色警戒','LOL','吃鸡' ], } }
使用
<CategoryComponent>
<!-- 获取属性名及属性绑定的值存储在data作用域中 -->
<template scope="suiyi">
{{suiyi.games}}
</template>
</CategoryComponent>
十四、Vue路由
1. vue-router介绍
vue路由为vue 的一个插件库,专门用来实现SPA 应用。
-
什么是路由?
-
一个路由就是一组映射关系(key - value)。
-
key 为路径,value 为 componen。
-
-
执行原理
-
当浏览器的请求路径改变时,对应的组件就会显示。
-
-
2. 安装
vue2对应的vue-router版本是 vue-router3.x
cnpm install vue-router@3.6.5 --save
vue3对应的vue-router版本是 vue-router4.x
<template> <h5>First 组件</h2> </template> <script> export default { name: "FirstComponent" } </script> </script>
组件2:
<template> <h5>Second 组件</h2> </template> <script> export default { name: "SecondComponent" } </script>
//导入Vue import Vue from 'vue' //导入路由 import VueRouter from 'vue-router' //导入组件 import FirstComponent from "@/pages/FirstComponent"; import SecondComponent from "@/pages/SecondComponent"; //使用路由 Vue.use(VueRouter); //创建并导出一个路由 export default new VueRouter({ routes: [ { path: '/first', component: FirstComponent }, { path: '/second', component: SecondComponent } ] });
修改main.js(全局的配置)
import Vue from 'vue' import App from './App.vue' //导入路由对象 import router from './router' Vue.config.productionTip = false; new Vue({ //注册路由对象 router, render: h => h(App), }).$mount('#app');
<template> <div id="app"> <h2>主页面</h2> <!-- Vue中借助router-link标签实现路由的切换 --> <p> <router-link to="/first">First</router-link> <router-link to="/second">Second</router-link> </p> <hr> <!-- 被路由的组件展示位置 --> <router-view></router-view> </div> </template> <script> export default { name: 'App' } </script>
<template> <div> <h5>Second 组件</h5> <!-- 子路由中使用的路径必须 /父路由路径/子路由路径 --> <ul type="none"> <li> <router-link to="/second/news">News</router-link> </li> <li> <router-link to="/second/message">Message</router-link> </li> </ul> <p> <!-- 被路由的组件展示位置 --> <router-view></router-view> </p> </div> </template> <script> export default { name: "SecondComponent" } </script>
修改index.js
routes: [ { path: '/first', component: FirstComponent }, { path: '/second', component: SecondComponent, //配置子路由。子路由中的路径不能以/开头 children: [ { path:'news', //不能以/开头 component: NewsComponent }, { path:'message', //不能以/开头 component: MessageComponent } ] } ]
5. url中的#
什么是hash值?—— #及其后面的内容就是hash值
hash值不会包含在 HTTP 请求中,即:hash值不会带给服务器
-
hash模式(默认):
-
地址中永远带着#号,不美观。
-
若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法。
-
兼容性较好。
-
-
history模式:
-
new VueRouter({})中,通过mode='history' 可以切换为history模式。
-
地址干净,美观。
-
兼容性和hash模式相比略差。
-
-
routes: [ { path: '/second', component: SecondComponent, //配置子路由。子路由中的路径不能以/开头 children: [ { name: "new", //即使指定了路由名,也必须指定path path:'news', //不能以/开头 component: NewsComponent }, ] } ]
使用路由:
<!-- 使用属性绑定,根据路由名进行路由 --> <router-link :to="{name: 'new'}">News</router-link>
7. 路由传递参数
两种传参方式:query、params
7.1 query参数
①传递参数
<router-link
:to="{ path: '/xxx' 或者 name: 'xxx', query: { 参数名: 值 } }">xxx</router-link>
②接收参数
$route.query.参数名
注意是$route 而不是$router
在 Vue-router 中,有两个常用的实例变量:$router 和 $route。
- $router 是一个指向 Vue-router 实例的引用。它允许在 Vue 实例中访问路由器配置和路由对象。可以使用 $router 来访问当前路由对象,以及获取路由器配置对象中的路由参数和锚点。
- $route 是一个指向当前路由对象的引用。它是通过使用 router.currentRoute() 方法获取的。您可以使用 $route 来访问当前路由对象的属性,例如 path、name、params、anchor 等。
总的来说,$router 是一个指向 Vue-router 实例的引用,而 $route 是指向当前路由对象的引用。它们都用于访问与路由相关的信息,但用途略有不同。
7.2 params参数
①传递参数
<router-link :to="{ path: '/xxx' 或 name:'xxx', params:{ 参数名: 值 } }" >xxx</router-link>
②接收参数
$route.params.参数名
③动态路由(可选)
{ name: 'mse', path:'message/:msgs', //使用占位符声明接收params参数名(动态路由,解决刷新页面不能获取数据的问题),不能以/开头 component: MessageComponent }
动态路由可以解决使用params传递参数时,刷新页面就获取不到数据的问题,使用这种方式时其实就是将参数拼接到url中了。
7.2.1 props配置
params可以配合props使用
①index.js配置props
routes: [ { name:'xxx', path:'/xxx', component: xxx, //props的第一种写法,值为对象,该对象中的所有key-value都会以props的形式传递 // props:{a:1,b:'hello'} //props的第二种写法,值为布尔值,若布尔值为真,就会把该路由组件收到的所有params参数,以props的形式传递,属性名为params中的参数名 // props:true //props的第三种写法,值为函数,以props的形式传递 props($route){ return { 自定义属性名: $route.params.参数名, } } }
]
②接收数据
<script> export default { name:'xxx', props:['属性名'] } </script>
以第三种props的写法为例
routes: [ { path: '/second', component: SecondComponent, //配置子路由。子路由中的路径不能以/开头 children: [ { name: 'mse', path:'message', //不能以/开头 props($route){ return { mymsgs: $route.params.msgs, } }, component: MessageComponent } ] } ]
mymsgs: 自定义的参数名,接收时 自定义属性要使用该参数名进行接收。
$.route.params.msgs 组件中的参数,其值就是组件中 data属性中的msgs的参数的值。
7.3 总结
路由传参:
query:
1.将参数在url中拼接进行传递(类似于get请求处理请求参数)
2.刷新页面也可以获取到数据
3.根据path | name进行组件的切换时,都能传递数据
params:
1.默认不会在地址栏拼接参数进行传递
2.刷新后获取不到数据
3.只有通过name进行组件的切换时,才能传递数据
动态路由:
解决params刷新页面获取不到数据的问题。
index.js中的path配置: '/first/:uname' -> 访问first资源时,路径会变为 /first/(uname对应的属性值)(类似于Resultful处理请求参数)
注意:
传递对象类型,数组类型:
1.传递时:将对象类型,数组类型转换为 JSON格式的字符串 JSON.stringify(对象|数组)
2.接收时:将JSON格式字符串的对象类型,数组类型转转换为对象,数组 JSON.parse(JSON格式字符串)
8. 编程式导航
8.1 路由跳转
控制路由跳转时操作浏览器历史记录的模式。
浏览器的历史记录有两种写入方式:push和replace,其中push是追加历史记录(保留历史记录),replace是替换当前记录。
路由跳转时候默认为push方式。
开启replace模式:<router-link replace ...>xxx</router-link>
例:
<router-link replace to="/second">Second</router-link>
8.2 前进、回退历史
//后退 this.$router.back() //前进 this.$router.forward() //前进或回退 this.$router.go(1)
十五、vuex
1. 介绍
vuex在 Vue 中实现集中式数据管理的一个 Vue 插件,对 vue 应用中多个组件的共享数据进行集中式的管理,也是一种组件间通信的方式,且适用于任意组件间通信。
2. 使用场景
3. 安装vuex
下载vuex`插件: vue2版本:cnpm i vuex@3
vue3版本:cnpm i vuex
4. vuex执行流程
Mutations:修改state中的数据
State对象:存储共享的数据
操作共享数据:
组件中使用 $store.dispatch('Actions中的方法名',数据)
若没有网络请求或其它业务逻辑,组件中也可以越过调用
dispatch
,直接调用commit
获取共享数据:
5. 使用vuex实现计数器
①安装vux
②创建vuex配置文件
src/store/index.js
//引入Vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//应用Vuex插件
Vue.use(Vuex);
//准备actions对象 -》响应组件中用户的动作(处理业务逻辑)
const actions = {
add(context, value) {
console.log(context, value);
context.commit("ADD", value);
}
};
//准备mutations对象 -》修改state中的数据
const mutations = {
ADD(state, value) {
console.log(state, value);
state.count += value;
}
};
//准备state对象 -》保存具体的数据
const state = {
count: 0
};
//创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state
})
③修改main.js
import Vue from 'vue' import App from './App.vue' //导入store import store from './store' Vue.config.productionTip = false new Vue({ //注册store store, render: h => h(App), }).$mount('#app');
④创建组件测试
src/components/FirstComponent.vue
<template> <div> <h3>组件一</h3> <button @click="fadd">+1</button> <p>{{$store.state.count}}</p> </div> </template> <script> export default { name: "FirstComponent", methods: { fadd() { //调用dispatch方法,驱动actions中add方法执行 this.$store.dispatch('add',1); } } } </script>
src/components/SecondComponent.vue
<template> <div> <h3>组件二</h3> <button @click="sadd">+1</button> <p>{{$store.state.count}}</p> </div> </template> <script> export default { name: "SecondComponent", methods: { sadd() { //调用dispatch方法,驱动actions中add方法执行 this.$store.dispatch('add',1); } } } </script>
6. getter配置项
6.1 介绍
当 state中的数据需要加工后在使用时,可以使用getter加工
6.2 使用
①修改vuex配置文件
//... //创建getters配置项对象 -》对数据相关操作 const getters = { big() { return state.count * 10; } }; //创建并暴露store export default new Vuex.Store({ actions, mutations, state, //注册getter getters })
②修改组件
<template> <div> <h3>组件一</h3> <button @click="fadd">+1</button> <p>{{$store.state.count}}</p> <!-- 调用方式时只能使用方法名,不能添加方法的() --> <p>放大十倍:{{$store.getters.big}}</p> </div> </template> <script> export default { name: "FirstComponent", methods: { fadd() { this.$store.dispatch('add',1); } } } </script>
<template> <div> <h3>组件二</h3> <button @click="sadd">+1</button> <p>{{$store.state.count}}</p> <!-- 调用方式时只能使用方法名,不能添加方法的() --> <p>放大十倍:{{$store.getters.big}}</p> </div> </template> <script> export default { name: "SecondComponent", methods: { sadd() { this.$store.dispatch('add',1); } } } </script> <style scoped> </style>
7. 四个map方法的使用
7.1 mapState | mapGetter
<template> <div> <p>{{count}}</p> <p>放大十倍:{{big}}</p> </div> </template> <script> //导入 mapState,mapGetters import {mapState,mapGetters} from 'vuex' //...省略 computed: { //参数:state中的属性名 ...mapState(['count']), //参数:getters中的方法名 ...mapGetters(['big']) }
//...省略
7.2 mapAction | mapMutations
-
mapActions:简化调用dispatch方法。既:简化了
this.$store.dispatch(xxx);
-
mapMutations:简化调用commit方法。既:简化了
this.$store.commit(xxx);
-
若没有网络请求或其它业务逻辑,组件中也可以越过调用
dispatch
,直接调用commit
-
<template> <div> <!-- 指定传递的参数 --> <button @click="fadd(1)">+1</button> </div> </template> <script> //导入 mapState,mapGetters,mapMutations,mapActions //import {mapState,mapGetters,mapMutations,mapActions} from 'vuex' import {mapActions} from 'vuex' export default { name: "FirstComponent", methods: { fadd() {/*this.$store.dispatch('add',1);*/ }, //mapActions与mapMutations使用时,若需要传递参数,则需要在模板中绑定事件时传递好参数,否则参数是事件对象 //调用actions中的add()方法。{事件中的方法名:'actions中的方法名' ...mapActions({fadd: 'add'}) }, } </script>
-
mapState:简化获取state中的共享数据。
-
没有简化:$store.state.属性名
-
简化后:配置
...mapState(['属性名'])
获取数据直接使用 属性名 获取
-
-
mapGetters:简化获取数据加工后的结果
-
没有简化:$store.getters.方法名
-
简化后:配置
...mapGetters(['方法名'])
获取加工后结果直接使用 方法名 获取
-
-
mapActions:简化调用actions中的自定义方法 =》处理用户的数据变化的业务逻辑
-
没有简化:$store.dispatch('方法名')
-
简化后:直接使用
...mapActions({事件中的方法名:方法名})
调用-
注意事项:需要传递参数,必须在事件的方法中添加传递的参数
-
-
-
mapMutations:简化调用mutaions中的自定义方法 =》改变数据
-
没有简化:$store.commit('方法名')
-
简化后:直接使用
...mapMutations({事件中的方法名:方法名})
调用 -
-
十七、Element UI
1. 介绍
npm i element-ui -S --legacy-peer-deps
3. 修改main.js
import Vue from 'vue' import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; import App from './App.vue'; Vue.use(ElementUI); Vue.config.productionTip = false new Vue({ render: h => h(App), }).$mount('#app')
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异