Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式的js框架,发布于 2014 年 2 月。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库(如:vue-router,vue-resource,vuex)或既有项目整合。
Model:模型层,在这里表示 JavaScript 对象
View:视图层,在这里表示 DOM(HTML 操作的元素)
ViewModel:连接视图和数据的中间件,Vue.js 就是 MVVM 中的 ViewModel 层的实现者

这里 核心就是 ViewModel 里面有DOM监听以及数据绑定,View是页面数据展示 Model也就是前面data里定义的,通过Vue来实现各种快捷功能,我们用普通js写的话 得写一大串Js代码;
mvvm设计模式 这里的
第一个m是 model 也就是vm的data属性
第二个v是 view 视图 网页模版
最后vm就是中间vue的 viewmodel 代码体现就是vm对象或者vm实例;
AngularJS
简单介绍一下,AngularJS诞生于2009年,由Misko Hevery 等人创建,后为Google所收购。是一款优秀的前端JS框架,已经被用于Google的多款产品当中。AngularJS有着诸多特性,最为核心的是:MVVM、模块化、自动化双向数据绑定、语义化标签、依赖注入等等。
ReactJS
React引入了虚拟DOM(Virtual DOM)的机制:在浏览器端用Javascript实现了一套DOM API。基于React进行开发时所有的DOM构造都是通过虚拟DOM进行,每当数据变化时,React都会重新构建整个DOM树,然后React将当前整个DOM树和上一次的DOM树进行对比,得到DOM结构的区别,然后仅仅将需要变化的部分进行实际的浏览器DOM更新。
微信小程序
微信小程序的视图层和数据层就是通过MVVM进行绑定的。
轻量级,体积小是一个重要指标。Vue.js 压缩后有只有 20多kb (Angular 压缩后 56kb+,React 压缩后 44kb+)
移动优先。更适合移动端,比如移动端的 Touch 事件
易上手,学习曲线平稳,文档齐全
吸取了 Angular(模块化)和 React(虚拟 DOM)的长处,并拥有自己独特的功能,如:计算属性
开源,社区活跃度高

当你把一个普通的 JavaScript 对象传给 Vue 实例的 data 选项,Vue 将遍历此对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。Object.defineProperty 是 ES5 中一个无法 shim 的特性,这也就是为什么 Vue 不支持 IE8 以及更低版本浏览器。
这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。这里需要注意的问题是浏览器控制台在打印数据对象时 getter/setter 的格式化并不同,所以你可能需要安装 vue-devtools 来获取更加友好的检查接口。
每个组件实例都有相应的 watcher 实例对象,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新。
页面上每个独立的可交互的区域视为一个组件
每个组件对应一个工程目录,组件所需的各种资源在这个目录下就近维护
页面不过是组件的容器,组件可以嵌套自由组合(复用)形成完整的页面
注意:cdn是一种加速策略,能够快速的提供js文件
创建一个div,id是app
<div id="app">div>
2.3 创建vue对象,设计对象的内容
其中该vue对象,绑定了页面中id是app的那个div
- new Vue({
- el:"#app",
- data:{
- title:"hello vue!",
- args1:"hi!",
- age:18,
- flag:true
- }
- });
- # el: element的简称,也就是Vue实例挂载的元素节点,值可以是 CSS 选择符,或实际 HTML 元素,或返回 HTML 元素的函数。
- # data: 用于提供数据的对象,里面存放键值对数据。
说明:
这里有几点重要说明:
new Vue 我们创建了Vue对象;
el 指定了绑定DOM,接管DOM操作;
data:用于提供数据的对象,里面存放键值对数据
v-model 重点 可以实现数据双向绑定,改变了这里的值,其他地方也根据改变;
{{xxxxx}} 显示数据;
- <div id="app">
- {{ title }}
- div>
插值表达式的作用是在View中获得Model中的内容
Model中的内容如下:
- new Vue({
- el:"#app",
- data:{
- title:"hello world!"
- },
- methods:{
- sayHello:function(){
- return "hello vue";
- }
- }
- });
- <div id="app">
- {{title}}
- div>
此时,页面上将会显示"Hello world!"
- "app">
- {{[1,2,3,4][2]}}
此时,页面上会显示“3”,也就是数组中的第三个元素被获取。
- <div id="app">
- {{ {"name":"xiaoyu","age":20}.age }}
- div>
此时,页面上会显示“20”,也就是对象中age属性的值。
- <div id="app">
- {{ sayHello()}}
- div>
此时,页面上会显示“hello vue”,也就是调用了vue对象中的sayHello方法,并展示了方法的返回值。
Vue.js通过加载js,实现对页面的快速渲染。vue封装的js该如何使用? 就必须了解MVVM双向数据绑定模式。Vue将视图层和数据层分离,通过MVVM建立视图层和数据层的连接。其中,插值表达式是一种连接方式,可以通过插值表达式以多种方式,快速的从数据层获取数据并展示在视图层上。数据层Vue对象,也是由很多部分组成,比如之前介绍的el,data,methods等,以及之后要介绍的mount,computed等。
Vue中的分支语句v-if非常好理解,逻辑跟Java中的if-else相同。v-if语句块包含以下内容:
v-if
v-else
v-else-if
接下来以一个简单例子即可理解:
- <html>
- <head>
- <meta charset="utf-8">
- <title>title>
- head>
- <body>
- <div id="app">
- <p v-if="flag">
- 今天天气很舒服!
- p>
- <p v-else-if="rich">
- 今天天气很燥热!晚上要去放松一下!
- p>
- <p v-else="rich">
- 晚上只能自嗨!
- p>
- div>
-
- body>
- <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.js">script>
- <script>
- new Vue({
- el:'#app',
- data:{
- flag:false,
- rich:false
- },
- methods:{
- }
- });
- script>
- html>
从这个例子可以看出,vue对象中的data提供了分支的条件。根据条件,如果是true,则v-if的内容就会显示,反之不显示。
v-if和v-show之间有着看似相同的效果,但优化上却有区别。先看下面这个例子:
- <html>
- <head>
- <meta charset="utf-8">
- <title>title>
- head>
- <body>
- <p v-show="rich">
- 有钱!
- p>
- <p v-if="rich">
- 有钱!
- p>
- <button type="button" @click="rich=!rich">今晚彩票开奖button>
- div>
-
- body>
- <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.js">script>
- <script>
- new Vue({
- el:'#app',
- data:{
- flag:false,
- rich:false
- },
- methods:{
-
- }
- });
- script>
- html>
通过点击“今晚彩票开奖”按钮,能切换rich的值,此时发现,v-if和v-show的显示状态都会来回切换。看起来是一样的,但通过查看控制台代码发现,v-show实际会将p标签的css样式的display属性设为none来达到隐藏的效果。

而v-if是直接在页面上添加和删除p标签来达到效果,因此v-show在反复切换的应用场景下,效率比v-if更高。
Vue中的循环关键字并没有Java的那么多,只有v-for,但用法上有多种。接下来我们来逐一介绍。
我们需要定义数据源,然后通过v-for来遍历数据源,再使用差值表达式输出数据。
- <body>
- <div id="app">
- <ul>
- <li v-for="item in items">{{item.date}}li>
- ul>
- div>
- body>
- <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.js">script>
- <script>
- new Vue({
- el:'#app',
- data:{
- items:[1,2,3,4,5,6]
- }
- });
- script>
在这个例子中,数据源提供了一个数组。视图层通过v-for来循环输出多个li标签,非常简单。
- <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>
此时的i就是每次循环的循环变量 ,从0开始一直到元素个数-1
- <body>
- <div id="app">
- <ul>
- <li v-for="(value,name,index) in student">{{name}}--{{value}}--{{index}}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>
value、name、index 这几个字符可以自己定义,分别表示每次循环内容的值、键、序号。
value: 循环中每条数据的值 小鱼、20、如花
name: 循环中每天数据的键 username、age、girl
index: 循环的序号,从0开始
| 页面效果如下: |
|---|
- <div id="app">
- <table style="border: 1px solid black">
- <tr>
- <th>姓名th>
- <th>年龄th>
- <th>联系方式th>
- tr>
- <tr v-for="(stu,index) in students" v-bind:key="index">
- <td>{{stu.name}}td>
- <td>{{stu.age}}td>
- <td>{{stu.phone}}td>
- tr>
- table>
- div>
- <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.js">script>
- <script>
- new Vue({
- el:'#app',
- data:{
- students:[
- {
- name:'zs',
- age:18,
- phone:'111'
- },
- {
- name:'ls',
- age:18,
- phone:'222'
- },{
- name:'ww',
- age:18,
- phone:'333'
- }
- ]
- }
- });
- script>
可以清楚的看到,此时数据源是一个student数组,通过两层v-for循环,外层遍历数组中的每个student对象,内层v-for遍历每个对象的v、k、i。
Vue提供了多个关键字,能快速的将数据对象中的值绑定在视图层中。
通过v-model将标签的value值与vue对象中的data属性值进行绑定。
- <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@2.6.12/dist/vue.js">script>
- new Vue({
- el:'#app',
- data:{
- title:"hello vue"
- }
-
- })
- script>
- html>
此时input标签中加入了“v-model='title'”,表示input的value值与vue对象中的title属性绑定,当在input输入框中输入内容会实时修改title的值。于是{{title}}插值表达式能实时输出input输入框内的值。
| 页面效果如下: |
|---|
![]() |
我们知道插值表达式是不能写在html的标签的属性内的,那如果一定要用vue中的属性作为html标签的属性的内容,就可以通过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@2.6.12/dist/vue.js">script>
- new Vue({
- el:'#app',
- data:{
- link:'http://www.baidu.com'
- }
- })
- script>
- html>
这样,a标签内的href属性就可以使用vue对象中的属性值。
注意: v-bind也可以简写,使用冒号“:”来代替。
bind:href='link'> 等价于 'link'>
关于事件,要把握好三个步骤:设参、传参和接参。
- <html>
- <head>
- <meta charset="utf-8" />
- <title>title>
- head>
- <body>
- <div id="app">
- sum={{sum}}<br/>
- {{sum>10?'总数大于10':'总数不大于10'}}<br/>
- <button type="button" @click="increase(2)">增加button>
- div>
- body>
- <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
- <script type="text/javascript">
- new Vue({
- el:'#app',
- data:{
- sum:0
- },
- methods:{
- increase:function(s){
- this.sum+=s
- }
- }
- })
- script>
- html>
从这里例子中:
设参:
<button type="button" @click="increase(2)">增加button>
传参:
increase:function(s)
接参:
this.sum+=s
注意:increase:function(s){ }函数可以写成increase(s){ }
接下来我们来看一下VUE中如何进行事件绑定。
通过配合具体的事件名,来绑定vue中定义的函数
- <html>
- <head>
- <meta charset="utf-8" />
- <title>title>
- head>
- <body>
- <div id="app">
- <input type="text" v-on:click="changeMajor" />
- div>
- body>
- <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
- <script type="text/javascript">
- new Vue({
- el:'#app',
- data:{
- major:'java'
- },
- methods:{
- sayHi(){
- alert("HELLO VUE!");
- },
- changeMajor(){
- console.log("change Title")
- }
- }
- script>
- html>
此时,该按钮,在点击时将会调用Vue对象中定义的changeMajor方法。
注意: v-on也可以简写,使用"@"替代。
<input type="text" @click="changeMajor" />
可以使用Vue中定义好的事件修饰符,快速达到效果。查看以下例子:
- <head>
- <meta charset="utf-8" />
- <title>title>
- head>
- <body>
- <div id="app">
- <p @mousemove="mm">
- x:{{x}}
- y:{{y}}
- <span @mousemove.stop>鼠标移动到此即停止span>
- p>
- <div @click = "doDivClick" style="width: 100px;height: 100px;border: 1px solid black">
- <a @click.stop="doThis" href="https://www.baidu.com">
- 百度
- a>
- div>
- div>
- body>
- <script <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.js">script>
- new Vue({
- el:'#app',
- data:{
- x:0,
- y:0
- },
- methods:{
- mm(event){
- this.x = event.clientX;
- this.y = event.clientY;
- },
- stopm(event){
- event.stopPropagation();
- },
- doThis(){
- alert("执行到了a的click");
- },
- doDivClick(){
- alert("执行到了div的click");
- }
- }
- })
- script>
当鼠标经过P标签区域内时,区域内就会显示X和Y轴的坐标,如果经过P标签内的Span标签内时,此时会调用事件属性mousemove.stop预定的效果,鼠标移动的效果将会被取消,X和Y不再显示信息。
计算属性的重点突出在 属性 两个字上(属性是名词),首先它是个 属性 其次这个属性有 计算 的能力(计算是动词),这里的 计算 就是个函数;简单点说,它就是一个能够将计算结果缓存起来的属性(将行为转化成了静态的属性),仅此而已;
- 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>
methods:定义方法,调用方法使用 currentTime1(),需要带括号
computed:定义计算属性,调用属性使用 currentTime2,不需要带括号;this.message 是为了能够让 currentTime2 观察到数据变化而变化
注意:methods 和 computed 里不能重名
仔细看图中说明,观察其中的差异

调用方法时,每次都需要进行计算,既然有计算过程则必定产生系统开销,那如果这个结果是不经常变化的呢?此时就可以考虑将这个结果缓存起来,采用计算属性可以很方便的做到这一点;计算属性的主要特性就是为了将不经常变化的计算结果进行缓存,以节约我们的系统开销
Vue的组件化设计思想借鉴了Java的面向对象思想。Java认为万物皆对象,在Vue中,万物皆组件。
也就是说,在实际的vue项目中,以及使用了Vue框架的项目中,Vue的对象都会以组件的形式出现,能被反复使用。
要想实现组件化,需要在页面中注册组件:关于注册的方式有两种,分别是全局注册和本地注册。
- 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.jsdelivr.net/npm/vue@2.6.12/dist/vue.js">script>
- <script>
- //通过Vue.component实现组件的全局注册,全局注册后的组件可以被重复使用。
- Vue.component("model1",{
-
- template:"
{{title}}
", - data:function(){
- return {
- title:"hello vue"
- }
- },
- methods:{
- btnfn:function(){
- alert("hello !!!");
- }
- }
- });
- new Vue({
- el:'#app'
- })
- new Vue({
- el:'#app1'
- })
- script>
-
- html>
vue的全局注册,也就意味着在页面的任意一个被vue绑定过的div中,都可以使用全局注册了的vue组件。
但是,如果是对vue组件进行本地注册,那么在其他被vue绑定的div中,不能使用该组件。
- html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>vue组件的本地(局部)注册title>
- head>
- <body>
- <div id="app">
- <model11>model11>
- div>
- <hr/>
-
- <div id="app1">
- <model11>model11>
- div>
- body>
- <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.js">script>
- <script>
- new Vue({
- el:'#app',
- components:{
- "model11":{
-
- template:"
{{title}}
", - data:function(){
- return {
- title:"hello vue"
- }
- },
- methods:{
- btnfn:function(){
- alert("hello !!!");
- }
- }
- }
- }
- })
- new Vue({
- el:'#app1'
- })
- script>
这是一个完整的Vue组件。该组件包含了三个部分:template(html视图层内容)、script(Model层)、style(CSS样式)。这样封装好的组件可以被复用,也可以作为其他组件的组成部分而被封装——Java的面向对象再次体现。
特点1: template标签内,必须有且只能有一个根标签。
特点2: componet中注册的组件中的data,必须是已函数的形式。
如下:
- data:function(){
- return {
- title:"hello vue"
- }
- }
Vue中的组件也是有生命周期的。一个Vue组件会经历:初始化、创建、绑定、更新、销毁等阶段,不同的阶段,都会有相应的生命周期钩子函数被调用。
| 组件的生命周期钩子 |
|---|
![]() |
生命周期主要有三个阶段:
- 一,初始化显示;(重要勾子 mounted 网页加载完毕触发)
- 二,更新显示;(重要勾子beforeUpdate 数据属性更新前)
- 三,死亡;(重要勾子beforeDestroy vm死亡前)
每个生命周期都会有对应的生命周期的函数,或者叫做勾子函数;
- <html>
- <head>
- <meta charset="UTF-8">
- <title>Titletitle>
- <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.js">script>
- head>
- <body>
- <pre>每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、
- 将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,
- 这给了用户在不同阶段添加自己的代码的机会。pre>
- <div id="app">
- <p>{{name}}p>
- <button @click="update">updatebutton>
- <button @click="destroy">destroybutton>
- div>
- <script type="text/javascript">
- new Vue({
- el:"#app",
- data:{
- a:1,
- name:"zs"
- },
- methods:{
- update(){
- this.name = Math.random() +"---";
- },
- destroy(){
- this.$destroy();
- }
- },
- beforeCreate(){
- console.log("创建vue实例之前");
- },
- created(){
- //
- console.log("vue实例创建成功");
- console.log(this.a);
- }
- /* created: () => console.log(this.a)*/
- ,
- beforeMount(){
- console.log("vue对象挂载之前");
- },
- mounted(){
- // 只执行一次 页面加载完之后执行 比如 咱们在 页面加载完毕 发送ajax请求 获取数据
- console.log(" mounted 挂载完毕")
- },
- beforeUpdate(){
- // 可执行多次
- console.log("data更新之前执行");
- },
- updated(){
- // 可执行多次
- console.log("data更新之后执行");
- },
- beforeDestroy(){
- // 只执行一次
- console.log("vue实例销毁之前执行");
- },
- destroyed(){
- // 只执行一次
- console.log("vue实例销毁之后执行");
- }
-
- });
- script>
- body>
- html>
-
cli: Command Line 命令行工具,vue-cli就是vue的命令行工具,也称之为脚手架,使用vue-cli提供的各种命令可以拉取、创建、运行我们需要使用到的框架,比如webpack、Element UI、Element Admin等等。那么要想使用vue-cli命令,需要先安装node.js。
node.js的介绍
node.js提供了前端程序的运行环境,可以把node.js理解成是运行前端程序的服务器。
node.js的安装
从官网下载安装即可: 下载 | Node.js 中文网
| 测试node.js是否安装成功: 在DOS窗口中输入“node -v” 查看版本,如果看到版本,就表示安装成功。 |
|---|
![]() |
使用如下命令安装vue-cli
- npm install -g vue-cli 安装的是2.9.6 版本 ------- 不装这个
- npm install -g @vue/cli 安装的是新版本 新版本 支持 vue ui
npm: 使用node.js的命令
install: 安装
vue-cli: 要安装的vue-cli
-g: 全局安装
注意 这里的安装可能需要管理员权限
安装完了之后 可能被windows的安全策略限制 参考
VSCode报错:vue : 无法加载文件 D:\nodejs\node_global\vue.ps1,因为在此系统上禁止运行脚本。_没有咸鱼的梦想的博客-CSDN博客
| 当出现以下界面,表示正在安装: |
|---|
![]() |
如果使用npm官方镜像速度比较慢,可以使用淘宝镜像来安装:
npm install -g cnpm --registry=https://registry.npm.taobao.org
之后使用npm命令时就可以替换成cnpm
- cnpm install vue-cli -g
- cnpm install
- cnpm run dev
dos命令输入vue ui会进入如下图:





创建项目 不保存预设 然后 后台就开始下载文件

创建好之后 页面跳转到仪表盘

可以在这里 安装一些插件 比如 axios element-ui 等等

这是已经安装的插件
点 添加插件

安装 ajax 插件 axios
然后 可以关掉仪表盘,使用vscode 打开 刚才创建的工程 使用 vue run serve 启动工程,

打开VSCode,文件—>首选项—>配置用户代码片段


输入一下代码:配置完成后新建.vue文件输入vue回车就会生成以下代码。
- {
- "Print to console": {
- "prefix": "vue",
- "body": [
- "",
- "",
- " $5",
- "",
- "",
- "",
- ""
- ],
- "description": "生成vue模板"
- }
- }
就像maven一样,vue为我们提供了一些官方项目骨架。使用vue list命令可以列出当前官方提供的骨架,可以使用这些骨架来快速搭建出项目。
vue list
完事 用vscode 打开项目文件夹



父组件

消息订阅与发布组件PubSub
我们前面讲了父子组件之间通过prop来实现消息传递;但是再其他情况,比如兄弟组件,爷孙组件消息传递时候,就要用到高级的消息订阅与发布;
1.首先我们安装下消息订阅与发布pubsub组件;
npm install --save pubsub-js
2.把 pubsub 配置成全局组件 在 main.js 中配置

3.在 父组件中 订阅消息 可以在 mounted 钩子函数中 监听消息

在这里 使用了 箭头函数 => ,在箭头函数中 的 this 代表 当前 vue 对象,如果 使用一般函数 ,那么在这个函数内 this 就代表PubSub对象,所以 在这里 咱们使用 =>箭头函数
在别的组件中 发布消息

注意: 执行上面的案例 会发现 订阅消息的回调函数 执行了两次 , 我们需要在我们每次接受数据pubsub.subscribe的时候,先执行pubsub.unsubscribe操作就好了,就完美解决了,这样你接收以后的callback只执行一次
- PubSub.unsubscribe();
- PubSub.subscribe(eventName, callback); //这样 回调就只执行一次
父组件向子组件传递标签,通过slot 插槽实现
主要作用:
某一个区块,先占位,然后可以动态的搞个标签进去,方便切换该位置的内容,无需再搞多个页面。
父组件 直接定义标签p 注意 slot 属性

子组件 使用 slot 标签 占位置 注意 slot 标签的name 属性,当父组件没有传对应的插槽(属性值对应)内容时,会显示插槽默认内容

常用命令:
npm install
在运行和调试项目前,一般都需要先执行该命令,目的是安装项目运行所需要的环境。
npm run dev
以调试的方式运行项目
npm run build
生成用于项目部署所需的最小资源,生成的内容存放在build文件夹内。
Webpack是一个前端资源的打包工具,它可以将js、image、css等资源当成一个模块进行打包。

从图中我们可以看出,Webpack可以将js、css、png等多种静态资源进行打包,使用webpack有什么好处呢?
1、模块化开发程序员在开发时可以分模块创建不同的js、css等小文件方便开发,最后使用webpack将这些小文件打包成一个文件,减少了http的请求次数。webpack可以实现按需打包,为了避免出现打包文件过大可以打包成多个文件。
2、编译typescript、ES6等高级js语法随着前端技术的强大,开发中可以使用javascript的很多高级版本,比如:typescript、ES6等,方便开发,webpack可以将打包文件转换成浏览器可识别的js语法。
3、CSS预编译webpack允许在开发中使用Sass和Less等原生CSS的扩展技术,通过sass-loader、less-loader将Sass和Less的语法编译成浏览器可识别的css语法
4.使用vue.js开发大型应用需要使用webpack打包工具
vue init webpack my-project1
webpack: 骨架名称
my-project1: 项目名称
| 过程中会出现如下界面,需要手动操作。 |
|---|
![]() |
| 出现如下界面,表示安装成功。 |
|---|
![]() |
进入到my-project1文件夹内后,使用以下命令来运行项目。
npm run dev

| 访问http://localhost:8081,页面效果如下: |
|---|
![]() |
npm install vue-router --save
创建views 文件夹 其下面创建Index.vue 和 Menu1.vue
在main.js中引入路由模块并使用
- import Vue from 'vue'
- import App from './App'
- import router from './router' //引入路由模块
-
- Vue.config.productionTip = false
-
- /* eslint-disable no-new */
- new Vue({
- el: '#app',
- router, //使用路由模块
- components: { App },
- template: '
' - })
在 router文件夹下 的index.js 是 路由的配置文件
index.js中:
- import Vue from 'vue'
- import Router from 'vue-router'
- import HelloWorld from '@/components/HelloWorld'
- import Index from '@/views/Index'
- import Menu1 from '@/views/Menu1'
- Vue.use(Router)
-
- export default new Router({
- routes: [
- {
- path: '/',
- name: 'HelloWorld',
- component: HelloWorld
- },
- {
- path: '/index',
- name: 'Index',
- component: Index
- },
- {
- path: '/menu1',
- name: 'Menu1',
- component: Menu1
- }
- ]
- })
-
在App.vue 中的路由写法
- <div class="menu">
- <ul>
- <li>
-
- <router-link to="/index">首页router-link>
- li>
- <li>
-
- <router-link to="/menu1">菜单1router-link>
- li>
- ul>
- div>
- <div class="content">
- <router-view>router-view>
- div>
通过 router-link 向路由配置发送请求 ,结果会在 router-view 显示
Menu1.vue是在前面创建的views文件夹下 继续嵌套 下级页面 配置嵌套路由,其他代码有vue片段生成
Menu1.vue
- <div>
- {{msg}}
- <ul>
- <li>
- <router-link to="/menu1/submenu1">子菜单1router-link>
- li>
- <li>
- <router-link to="/menu1/submenu2">子菜单2router-link>
- li>
- ul>
-
- <div class="content">
- <router-view>router-view>
- div>
-
- div>
在路由配置文件src文件夹下router文件夹下的index.js中
- {
- path: '/menu1',
- name: 'Menu1',
- component: Menu1,
- children:[ // 子路由
- {
- path:'/menu1/submenu1', // 当然 对应的 子组件 得创建好
- component: () => import('@/views/SubMenu1.vue') // 这样就不用在文件上面配置了
- },
- {
- path:'/menu1/submenu2',
- component: () => import('@/views/SubMenu2.vue')
- },
- {
- path:'',
- redirect:'/menu1/submenu1' // 默认显示submenu1
- }
- ]
- },
在views文件夹下创建SubMenu1.vue,其他代码vue片段生成
- <div>子菜单1
- <input type="text" name="sub1input">
- div>
- template>
SubMenu2.vue,其他代码vue片段生成
- <div>子菜单2
- <input type="text" name="sub2input">
- div>
- template>
当我们 在 子菜单1 和 子菜单2 的 文本输入框输入内容时,发现 跳转之后内容没有了,这种情况也经常遇到

我们切换不同的组件时,希望 组件内输入的内容不要丢失 ,怎么解决?只需要 使用keep-alive 标签



app.vue显示页面的配置:
- <template>
- <div id="app">
- <div class="menu">
- <ul>
- <li>
- <router-link to="/">首页router-link>
- li>
- <li>
- <router-link to="/menu1">菜单1router-link>
- li>
- <li>
- <router-link to="/admin">账户信息router-link>
- li>
- ul>
- div>
- <div class="content">
- <router-view>router-view>
- div>
- div>
- template>
- <script>
- export default {
- mounted(){
- this.axios.defaults.headers.common['token'] = 6666;
- }
- }
- script>
- <style>
- ul li{
- float: left;
- margin-right: 20px;
- list-style: none;
- }
- .content{
- clear: both;
- }
- style>
注意:上述路由需要再定义个div并在里面写
标签
router文件下index.js中路由配置,这里只设置了账户信息路由
- {
- //path对应app.vue文件中账户信息标签to="/admin"
- path: '/admin',
- name: 'index',
- component: () => import ('@/views/Admin.vue'),
- children: [ // 子路由,点击姓名显示详细信息
- {
- path:'/admin/adminDetail/:id',
- component: () => import ('@/views/AdminDetail.vue')
- }
- ]
- },
用户信息组件views文件夹下创建Admin.vue
- <template>
- <div class="">
- <table>
- <tr>
- <th>编号th>
- <th>账号th>
- <th>密码th>
- tr>
- <tr v-for="(admin, index) in admins" v-bind:key="index">
- <td>{{ admin.id }}td>
- <router-link :to='`/admin/adminDetail/${admin.id}`'><td>{{ admin.username }}td>router-link>
- <td>{{ admin.password }}td>
- tr>
- table>
- <hr>
- <div class="content">
- <router-view>router-view>
- div>
- div>
- template>
-
- <script>
-
- export default {
- //这里存放数据
- data() {
- return {
- admins: [],
- };
- },
-
- //方法集合
- methods: {
- getAdmins() {
- this.axios({
- url: "http://localhost:8081/admin/list",
- params: {
- page: 1,
- limit: 10,
- },
- })
- .then((res) => {
- this.admins = res.data.data;
- })
- .catch(function (error) {
- //处理错误情况
- console.log(error);
- })
- .then(function () {
- //总是会执行
- });
- },
- },
-
- //生命周期 - 挂载完成(可以访问DOM元素)
- mounted() {
- this.axios.defaults.headers.common['token'] = 6666;
- this.getAdmins(); // 页面加载完成后调用这个函数
- },
- };
- script>
- <style>
- table {
- border: 1px solid black;
- }
- th,
- td,
- tr {
- border: 1px solid black;
- text-align: center;
- width: 150px;
- }
- /* @import url(); 引入公共css类 */
- style>
当点击名字时会显示该用户信息,用到嵌套路由,在views下创建AdminDetail.vue文件,代码如下:
- <template>
- <div class="">
- Id:{{ $route.params.id }}<br />
- {{ admin.username }}<br />
- {{ admin.password }}<br />
- {{ admin.type }}<br />
- {{ admin.create_time }}<br />
- div>
- template>
-
- <script>
- export default {
- data() {
- //这里存放数据
- return {
- admin: {},
- };
- },
- //监控data中的数据变化
- watch: {
- $route(value) {
- let id = value.params.id;
- this.getAdminById(id); // 每次点击姓名都会调用该方法
- },
- },
- //方法集合
- methods: {
- getAdminById(id) {
- console.log(id);
- this.axios({
- url: `http://localhost:8081/admin/adminDetail/${id}`,
- })
- .then((res) => {
- console.log("响应的id详情");
- console.log(res.data.data.admin);
- this.admin = res.data.data.admin;
- })
- .catch((error) => {
- console.log(error);
- });
- },
- },
- //生命周期 - 挂载完成(可以访问DOM元素)
- mounted() {
- let id = this.$route.params.id;
- this.getAdminById(id);
- },
- };
- script>

只需要在上面的Admin.vue文件中添加一些代码就行。
- <template>
- <div class="">
- <table>
- <tr>
- <th>编号th>
- <th>账号th>
- <th>密码th>
- <th>测试编程式路由th>
- tr>
- <tr v-for="(admin, index) in admins" v-bind:key="index">
- <td>{{ admin.id }}td>
- <router-link :to="`/admin/adminDetail/${admin.id}`"
- ><td>{{ admin.username }}td>
- >
- <td>{{ admin.password }}td>
- <td>
- <button @click="pushShow(admin.id)">pushbutton>
- <button @click="replaceShow(admin.id)">replacebutton>
- td>
- tr>
- table>
- <button @click="$router.back()">回退button>
- <hr />
- <div class="content">
- <router-view>router-view>
- div>
- div>
- template>
-
- <script>
- export default {
- //这里存放数据
- data() {
- return {
- admins: [],
- };
- },
-
- //方法集合
- methods: {
- getAdmins() {
- this.axios({
- url: "http://localhost:8081/admin/list",
- params: {
- page: 1,
- limit: 10,
- },
- })
- .then((res) => {
- this.admins = res.data.data;
- })
- .catch(function (error) {
- //处理错误情况
- console.log(error);
- })
- .then(function () {
- //总是会执行
- });
- },
- pushShow(id) {
- console.log(id);
- // 点击时路由带id,通过$router获得id
- this.$router.push(`/admin/adminDetail/${id}`);
- },
- replaceShow(id) {
- this.$router.replace(`/admin/adminDetail/${id}`);
- },
- },
-
- //生命周期 - 挂载完成(可以访问DOM元素)
- mounted() {
- this.axios.defaults.headers.common["token"] = 6666;
- this.getAdmins(); // 页面加载完成后调用这个函数
- },
- };
- script>
- <style>
- table {
- border: 1px solid black;
- }
- th,
- td,
- tr {
- border: 1px solid black;
- text-align: center;
- width: 150px;
- }
- /* @import url(); 引入公共css类 */
- style>
十一、使用Axios发送请求
11.1 什么是 Axios
Axios 是一个开源的可以用在浏览器端和 NodeJS 的异步通信框架,她的主要作用就是实现 AJAX 异步通信,其功能特点如下:
-
从浏览器中创建 XMLHttpRequests
-
从 node.js 创建 http 请求
-
支持 Promise API
-
拦截请求和响应
-
转换请求数据和响应数据
-
取消请求
-
自动转换 JSON 数据
-
客户端支持防御 XSRF(跨站请求伪造)
GitHub:GitHub - axios/axios: Promise based HTTP client for the browser and node.js
11.2 为什么要使用 Axios
由于 Vue.js 是一个 视图层框架 并且作者(尤雨溪)严格准守 SoC (关注度分离原则),所以 Vue.js 并不包含 AJAX 的通信功能,为了解决通信问题,作者单独开发了一个名为 vue-resource 的插件,不过在进入 2.0 版本以后停止了对该插件的维护并推荐了 Axios 框架
11.3 Axios的使用
11.3.1 安装vue axios
npm install --save axios vue-axios
11.3.2 在main.js中引入
在项目中使用axios模块
- import Vue from 'vue'
- import axios from 'axios'
- import VueAxios from 'vue-axios'
-
- Vue.use(VueAxios, axios)
11.4 发送axios请求
在使用axios时,要注意到配置选项中包含params和data两者
1.params是添加到url的请求字符串中的,用于get请求;
2.而data是添加到请求体(body)中的, 用于post请求;
11.4.1axios使用方法-post
- this.$axios({ //这种格式,是需要每个参数都弄成对象的
- methods: 'POST',
- url: '#',
- data: {
- key1: val1,
- key2: val2
- },
- timeout: 1000,
- baseURL:'xxxx'
- ...//其他相关配置
- })
11.4.2axios使用方法-get
- this.$axios({
- methods: 'get',
- url: '#',
- params: { //注意是params,get请求必须写上params,不能写data
- key1: val1,
- key2: val2
- },
- timeout: 1000,
- baseURL:'xxxx'
- ...//其他相关配置
- })
注意:
在get请求下,参数需要使用【params】来设置,
而post请求中,是使用data来传递的
11.4.3axios的简化写法
- this.$axios.get('url')
- this.$axios.post('url')
注意:这种直接没有参数的,就写个url就行了
get请求直接写参数是错误写法,会导致请求无法携带参数
如果get请求有参数,必须使用params:{}括起来
11.4.4axios请求案例
如果带token的话可以在app.vue中的mounted里面设置全局的
- mounted(){
- this.axios.defaults.headers.common['token'] = 6666;
- }
创建一个.vue文件书写一下代码:
- <template>
- <div class="">
- <table>
- <tr>
- <th>编号th>
- <th>账号th>
- <th>密码th>
- tr>
- <tr v-for="(admin, index) in admins" v-bind:key="index">
- <td>{{ admin.id }}td>
- <td>{{ admin.username }}td>
- <td>{{ admin.password }}td>
- tr>
- table>
- div>
- template>
-
- <script>
- export default {
- data(){
- data() {
- //这里存放数据
- return {
- admins: [],
- };
- },
-
- },
- methods:{
- getAdmins() {
- this.axios({
- methods:"get",
- url: "http://localhost:8081/admin/list",
- params: {
- page: 1,
- limit: 10,
- },
- })
- .then((res) => {
- this.admins = res.data.data;
- })
- .catch(function (error) {
- //处理错误情况
- console.log(error);
- })
- .then(function () {
- //总是会执行
- });
- }
- },
- mounted() {
- this.axios.defaults.headers.common['token'] = 6666;
- this.getAdmins(); // 页面加载完成后调用这个函数
- },
- }
- }
- script>
11.4.5 服务端解决跨域问题
- <mvc:cors>
- <mvc:mapping path="/"
- allowed-origins="*"
- allowed-methods="POST, GET, OPTIONS, DELETE, PUT,PATCH"
- allowed-headers="Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With"
- allow-credentials="true" />
- mvc:cors>
在spring-mvc.xml中加入上述这一段。其中,allowed-origins指的是允许的访问源的域名,"*"表示任何人都可以访问,也可以指明具体的域名
11.4.6解决axios无法传递data中的参数问题
原因:默认情况下发送axios时请求头中的内容类型为: (后端没有使用@RequestBody)
Content-Type:application/json;charset=UTF-8
而实际服务端需要的是:
Content-Type:application/x-www-form-urlencoded
因此,使用axios的qs内置库中的方法进行内容类型的转换。
- import Qs from 'qs'
-
- this.axios({
- method:'post',
- url:'http://localhost:8081/regist',
- transformRequest: [function (data) {
- return Qs.stringify(data)
- }],
- data:{
- email:this.email
- }
- })
- .then(function (response) {
- alert(response.data.message)
- });
十二、 Vuex状态集中式管理
12.1 什么是Vuex
Vuex 是一个专为 Vue.js 应用程序开发的 状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
12.2步骤
1.先在创建一个没有使用 vuex的组件 MyVuex.vue
- <div class=''>
- vuex
- <p>当前数字: {{number}} is {{evenOrOdd}}p>
- <button v-on:click="jia()">加button>
- <button @click="jian()">减button>
- div>
- <script>
- export default {
- data() {
- //这里存放数据
- return {
- number:0
- }
- },
- //监听属性 类似于data概念
- computed: {
- evenOrOdd(){
- return this.number%2==0?'偶数':'奇数'
- }
- },
- //方法集合
- methods: {
- jia(){
- this.number++;
- },
- jian(){
- this.number--;
- }
- },
- }
- script>

12.3 安装
1.如果不想安装可以在构建项目时勾选此选项:

2.也可以在项目根目录执行如下命令来安装 Vuex
若失败,可使用cnpm
npm install vuex --save
修改 main.js 文件,导入 Vuex,关键代码如下:
- import Vuex from 'vuex'
- Vue.use(Vuex);
npm install vuex --save
但是 如果项目里 需要多个组件 共享这个 number 的值 ,也就是 number 的变化 很多组件都能感知到 怎么实现,vuex 状态集中式管理 就是解决这个问题的。
首先 安装
修改 main.js 文件,导入 Vuex,关键代码如下:
- import Vuex from 'vuex'
- Vue.use(Vuex);
创建vuex配置文件 在 src 目录下创建一个名为 store 的目录并新建一个名为 index.js 文件用来配置 Vuex,代码如下:
- import Vue from 'vue'
- import Vuex from 'vuex'
- Vue.use(Vuex);
-
- export default new Vuex.Store({
- // 全局 state 对象,用于保存所有组件的公共数据
- state: {
- //在组件中是通过 this.$store.state.number 来获取
- number: 0
- },
- // 实时监听 state 值的最新状态,注意这里的 getters 可以理解为计算属性
- getters: {
- // 在组件中是通过 this.$store.getters.evenOrOdd 来获取
- evenOrOdd(state) {
- return state.number % 2 == 0 ? '偶数' : '奇数'
- }
- },
- // 定义改变 state 初始值的方法,这里是唯一可以改变 state 的地方,缺点是只能同步执行
- mutations: {
- // 在组件中是通过 this.$store.commit('jia'); 方法来调用 mutations
- jia(state) {
- state.number++
- },
- jian(state) {
- state.number--
- }
- },
- // 定义触发 mutations 里函数的方法,可以异步执行 mutations 里的函数
- actions: {
-
- // 在组件中是通过 this.$store.dispatch('jia'); 来调用 actions
- jia(context) {
- context.commit('jia')
- },
- // 在组件中是通过 this.$store.dispatch('jian'); 来调用 actions
- jian({ commit, state }) { //解构 context 对象 可以拿到对象属性 commit 和 state
- if (state.number > 0) {
- commit('jian')
- }
- }
- },
- modules: {
-
- }
- })
修改 main.js 增加刚才配置的 store/index.js,关键代码如下:
- import Vue from 'vue'
- import Vuex from 'vuex'
- import store from './store'
-
- Vue.use(Vuex);
-
- new Vue({
- el: '#app',
- store
- });
修改MyVuex.vue
当前数字: {{$store.state.number}} is {{$store.getters.evenOrOdd}}
- <button v-on:click="jia()">加button>
- <button @click="jian()">减button>
- methods: {
- jia(){
- // this.$store.commit('jia'); // 同步调用
- this.$store.dispatch('jia'); // 异步调用
- },
- jian(){
- // this.$store.commit('jian'); // 同步调用
- this.$store.dispatch('jian'); // 异步调用
- }
- },
依然 可以实现之前的效果
但是感觉 每次 都写 $.store.xxx.xxx 太长了 ,怎么办?
- // 不想每次都写 $store.state.xxx 就导入组件然后计算属性
- // 第一步:在MyVuex.vue中的