Vue

2023-05-16

在这里插入图片描述

Author: Thor

Version: 9.0.1

文章目录

      • 一、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 初体验
        • 2.2 基本指令
        • 2.3 跑马灯案例
        • 2.4 设置全名
        • 2.5 名字过滤以及年龄排序案例
        • 2.6 事件修饰符
        • 2.7 按键修饰符
        • 2.8 生命周期
      • 三、使用Vue-Cli搭建Vue项目
        • 3.1 vue-cli 介绍
        • 3.2 node.js 介绍及安装
        • 3.3 axios.js 介绍
        • 3.4 Element-Ul 介绍
        • 3.5 moment.js 介绍
        • 3.6 项目搭建流程
        • 3.7 在 main.js 中添加如下配置
        • 3.8 修改 App.vue
        • 3.9 moment.js 格式 Date 类型
        • 3.10 分页
        • 3.11 删除
        • 3.12 添加
        • 3.12 修改
      • 四、Vue组件间的参数传递
        • 4.1 在项目中创建子组件
        • 4.2 注册子组件
        • 4.3 在App.vue中使用组件并传递参数
      • 五、Vue-router 路由
        • 5.1 介绍
        • 5.2 准备工作
        • 5.3 Router 入门
        • 5.4 子路由
        • 5.5 路由传参
        • 5.6 Element-ui 中的使用
      • 六、 Vuex的应用
        • 6.1 Vuex介绍
        • 6.2 准备工作
        • 6.3 配置 vuex
          • 15.3.2 解决浏览器刷新后 Vuex 数据消失问题
        • 6.2 准备工作
        • 6.3 配置 vuex
          • 15.3.2 解决浏览器刷新后 Vuex 数据消失问题

一、Vue简介


1.1 简介

Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式的js框架,发布于 2014 年 2 月。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库(如:vue-router,vue-resource,vuex)或既有项目整合。

1.2 MVVM 模式的实现者——双向数据绑定模式

  • Model:模型层,在这里表示 JavaScript 对象
  • View:视图层,在这里表示 DOM(HTML 操作的元素)
  • ViewModel:连接视图和数据的中间件,Vue.js 就是 MVVM 中的 ViewModel 层的实现者

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nVYFAYLp-1598408904696)(pictures/1.png)]

在 MVVM 架构中,是不允许 数据 和 视图 直接通信的,只能通过 ViewModel 来通信,而 ViewModel 就是定义了一个Observer` 观察者

  • ViewModel 能够观察到数据的变化,并对视图下对应的内容进行更新
  • ViewModel 能够监听到视图的变化,并能够通知数据发生改变

Vue.js 是目前最火的一个前端框架,和Angular.js、React.js 一起,并成为前端三大主流框架,框架的好处就是提高开发效率,原生JS -> Jquery之类的类库 -> 前端模板引擎 -> Angular.js / Vue.js,能够帮助我们减少不必要的DOM操作,提高渲染效率,双向数据绑定的概念一个核心的概念,就是让用户不再操作DOM元素,解放了用户的双手,让程序员可以更多的时间去关注业务逻辑。

Vue.js 是一个 MVVM 的实现者,核心就是实现了 DOM 监听 与 数据绑定

1.3 其它 MVVM 实现者

  • 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进行绑定的。

1.4 为什么要使用 Vue.js

  • 轻量级,体积小是一个重要指标。Vue.js 压缩后有只有 20多kb (Angular 压缩后 56kb+,React 压缩后 44kb+)
  • 移动优先。更适合移动端,比如移动端的 Touch 事件
  • 易上手,学习曲线平稳,文档齐全
  • 吸取了 Angular(模块化)和 React(虚拟 DOM)的长处,并拥有自己独特的功能,如:计算属性
  • 开源,社区活跃度高

1.5 Vue.js 的两大核心要素

1.5.1 数据驱动

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j0Ojthdn-1598408904699)(pictures/2.png)]

当你把一个普通的 JavaScript 对象传给 Vue 实例的 data 选项,Vue 将遍历此对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。Object.defineProperty 是 ES5 中一个无法 shim 的特性,这也就是为什么 Vue 不支持 IE8 以及更低版本浏览器。

这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。这里需要注意的问题是浏览器控制台在打印数据对象时 getter/setter 的格式化并不同,所以你可能需要安装 vue-devtools 来获取更加友好的检查接口。

每个组件实例都有相应的 watcher 实例对象,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新。

1.5.2 组件化
  • 页面上每个独立的可交互的区域视为一个组件
  • 每个组件对应一个工程目录,组件所需的各种资源在这个目录下就近维护
  • 页面不过是组件的容器,组件可以嵌套自由组合(复用)形成完整的页面

二、Vue入门


2.1 vue 初体验

在webStorm中安装插件,安装成功后直接在页面输入:div#app>form>input*2 然后按 Tap 键即可

在这里插入图片描述

  1. vue 初体验
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<!-- 导入vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<body>
    <div id="app">
        <!-- 插值表达式 -->
        {{ name }}
        <hr>
        <!-- v-model表示双向绑定 -->
        <input type="text" v-model="name">
    </div>
</body>
<script>
    new Vue({
        el: '#app',
        //组件化编程支持的data写法
        data(){
            return{
                name: 'jack'
            }
        }
    });
</script>
</html>

2.2 基本指令

v-text: v-text是用于操作纯文本,它会替代显示对应的数据对象上的值,可以简写为{{}}, 即插值表达式。

v-html: 将内容以html的形式呈现在页面

v-bind: 将值绑定到标签的自定义属性上,形式为 v-bind:title=“mytitle”,可以简写为 :属性名

v-model: 双向数据绑定

v-if: 值如果为true的情况下,显示标签,如果为false会移除标签

v-else-if: 与v-if配合使用

v-else: 与v-if配合使用

v-show: 如果为true,显示信息,如果为false则隐藏标签

v-for: 循环遍历。语法形式为 v-for=“item in list”

v-on:click: 点击事件,可以简写为@click

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<!-- 导入vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<body>
<div id="app">
    <p v-text="name"></p>

    <p v-text="htmlText"></p>

    <p v-html="htmlText"></p>

    <!--<a v-bind:href="url">v-bind百度</a>-->
    <a :href="url">v-bind百度</a>

    <p v-if="score > 90">优秀</p>
    <p v-else-if="score > 60">及格</p>
    <p v-else>不及格</p>

    <ul>
        <li v-for="user in users">
            {{user.id}} -- {{user.username}}
        </li>
    </ul>
    <hr color="red">
    <!-- dom树中有该标签 -->
    <div v-show="score > 100">
        v-show成绩大于100
    </div>
    <!-- dom树中无该标签 -->
    <div v-if="score > 100">
        v-if成绩大于100
    </div>

    <button @click="show">点击</button>
</div>
</body>

<script>

    new Vue({
        el: '#app',

        data(){
            return{
                name:'张三',
                score:100,
                htmlText:'<a href="http://www.baidu.com">百度</a>',
                url:"http://www.baidu.com",
                users:[
                    {id:1001,username:'jack'},
                    {id:1002,username:'tom'},
                    {id:1003,username:'lucy'}
                ]
            }
        },
        methods:{
            show(){
                // 如果method中要使用 vue data中的数据,都需要带上this
                alert(this.name);
            }
        }
    })
</script>
</html>

2.3 跑马灯案例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<!--引入官方js文件 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<body>

<div id="app">

    <input type="button" value="move" @click="move">
    <input type="button" value="stop" @click="stop">

    <h1><font color="blue">{{ msg }}</font></h1>
</div>


</body>
<script>

    //var arr = [11,22,33,44,55];

    // arr.forEach(function (item) {
    //         if(item>20){
    //             alert(item+"--")
    //         }
    // })

    // arr.forEach(item => {
    //     if(item>20){
    //         alert(item+"++")
    //     }
    // })

    // var item = arr.filter(item => item>20)
    // alert(item)

    new Vue({

        el:"#app",

        data(){
            return{
                msg:"中国移动通信",
                id:null
            }
        },

        methods:{

            move(){

               if(this.id!=null){
                   return;
               }

               this.id = setInterval( () => {
                    var start = this.msg.substring(0,1);//中
                    var end = this.msg.substring(1);//国移动通信

                    this.msg = end + start;
                },300)
            },

            stop(){
                clearInterval(this.id);
                this.id=null;
            }
        }
    })


</script>
</html>

2.4 设置全名

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<!--引入官方js文件 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<body>

<div id="app">

    FirstName:<input type="text" v-model="firstName"><br>
    LastName:<input type="text" v-model="lastName"><br>
    FullName1(单向数据绑定):<input type="text" v-model="fullName1"><br>
    FullName2(单向数据绑定):<input type="text" v-model="fullName2"><br>
    FullName3(双向数据绑定):<input type="text" v-model="fullName3"><br>

</div>

</body>

<script>

    new Vue({

        el: "#app",

        data() {
            return {
                firstName: '',
                lastName: '',
                fullName2: '',
            }
        },
        //计算属性
        computed: {
            //定义了回调方法,没有显示调用,会触发
            //1.计算属性的值,不用再data中定义,直接用
            //2.计算属性对应一个回调方法
            //3.触发时机:只要牵扯到属性发生变化,该方法就会触发
            //4.在使用时,首先需要用到属性局部赋值

            // fullName1:function () {
            //
            //     let firstName = this.firstName;
            //     let lastName = this.lastName;
            //
            //     return firstName + "  " + lastName;
            // },

            fullName1: {
                get() {
                    let firstName = this.firstName;
                    let lastName = this.lastName;

                    return firstName + "  " + lastName;
                }
            },

            fullName3: {
                get() {
                    let firstName = this.firstName;
                    let lastName = this.lastName;

                    return firstName + "  " + lastName;
                },

                set(val) {
                    //alert(val);//拿到fullName3的值
                    let arr = val.split(/\s+/);//通过空格分离
                    var first = arr[0];
                    var last = arr[1];

                    this.firstName = first;
                    this.lastName = last;
                }

            }
        },

        watch: {
            firstName: function (newVal, oldVal) {
                this.fullName2 = newVal + " " + this.lastName;
            },
            lastName: function (newVal, oldVal) {
                this.fullName2 = this.firstName + " " + newVal;
            }
        }

    })

</script>
</html>

2.5 名字过滤以及年龄排序案例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <style>

        #app {
            width: 400px;
            margin: 100px auto 0;
        }
    </style>
</head>

<body>

<div id="app">
    <input v-model="searchText">

    <table border="1" style="text-align: center;" cellspacing="0"
           cellpadding="0" width="100%">
        <tr>
            <th>ID</th>
            <th>姓名</th>
            <th>年龄</th>
        </tr>
        <tr v-for="user in filterUsers">
            <td>{{user.id}}</td>
            <td>{{user.name}}</td>
            <td>{{user.age}}</td>
        </tr>
    </table>

    <button @click="orderByAge(1)">升序</button>
    <button @click="orderByAge(2)">降序</button>
    <button @click="orderByAge(3)">不排序</button>

</div>

</body>

<script>
    new Vue({
        el: '#app',

        data() {

            return {

                users: [
                    {id: 1, name: 'zhangsan', age: 22},
                    {id: 2, name: 'lisi', age: 12},
                    {id: 3, name: 'wangwu', age: 42},
                    {id: 4, name: 'zhaoliu', age: 32},
                    {id: 5, name: 'tianqi', age: 28},
                ],

                searchText: '',
                order: 3

            }
        },
        computed: {

            filterUsers: function() {

                let searchText = this.searchText;
                let order = this.order;
                // 根据名字过滤
                let newUsers = this.users.filter(user => user.name.indexOf(searchText) > -1);

                // 排序
                if(order != 3) {

                    newUsers.sort((u1, u2) => {
                        if(order == 1) {
                            return u1.age - u2.age;
                        }else {
                            return u2.age - u1.age;
                        }
                    });
                }

                return newUsers;

                // String s = "helloworld";
                // s.indexOf('worlx'); // -1
            }
        },

        methods: {
            orderByAge(value) {

                this.order = value;

            }
        }
    })

</script>

</html>

2.6 事件修饰符

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <style>
        .box1 {
            background-color: red;
            height: 200px;
            width: 200px;
        }

        .box2 {
            background-color: #e3e3e3;
            height: 100px;
            width: 100px;
        }
    </style>

</head>
<body>
<div id="app">

    <!--@click.prevent 阻止事件传播 -->
    <a href="http://www.baidu.com" @click.prevent="show">百度</a>

    <hr>

    <div class="box1" @click="alertOutterBox">
        <!-- click.stop阻止冒泡事件 -->
        <div class="box2" @click.stop="alertInnerBox"></div>
    </div>

</div>
</body>
<script>
    new Vue({

        el: '#app',

        methods: {

            show() {
                alert("show")
            },
            alertOutterBox(){
                alert("alertOutterBox")
            },
            alertInnerBox(){
                alert("alertInnerBox")

            }
        }
    })
</script>

</html>

2.7 按键修饰符

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>

<div id="app">

    <!-- keyup.enter 表示enter键弹起的时候,事件被触发 -->
    keyup:<input type="text" v-model="name" @keyup.enter="keyupTest()">
    <!-- keydown 表示按下某个键时触发 -->
    keydown:<input type="text" v-model="code" @keydown="keydownTest($event)">

</div>

</body>

<script>
    new Vue({
        el: '#app',

        data() {
            return {
                name: '',
                code: ''
            }
        },
        methods: {

            keyupTest() {
                alert(this.name)
            },

            keydownTest: function (event) {
                var keyCode = event.keyCode;
                alert(keyCode)
                // if (keyCode != 49) {
                //     event.preventDefault();//阻止按键输入
                // }
            }
        }

    })

</script>
</html>

2.8 生命周期

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>

<div id="app">
    {{message}}
</div>

</body>

<script>
    var vm= new Vue({
        el: "#app",
        data(){
            return{
                message:"hello vue"
            }
        },
        methods:{
        },
        beforeCreate:function () {
            console.log("beforeCreate创建vue之前:",this.message);
            console.log("$el:"+this.$el);
            console.log("$data:"+this.$data);
            console.log("-------------")
        },
        created:function () {
            console.log("created创建vue:",this.message);
            console.log("$el:"+this.$el);
            console.log("$data:"+this.$data);
            console.log("-------------")
        },
        beforeMount:function () {
            console.log("beforeMount挂载之前:",this.message);
            console.log("$el:"+this.$el);
            console.log("$data:"+this.$data);
            console.log("-------------")
        },
        mounted:function () {
            console.log("mounted挂载:",this.message);
            console.log("$el:"+this.$el);
            console.log("$data:"+this.$data);
            console.log("-------------")
        },
        beforeUpdate:function () {
            console.log("beforeUpdate修改之前:",this.message);
            console.log("$el:"+this.$el);
            console.log("$data:"+this.$data);
            console.log("-------------")
        },
        updated:function () {
            console.log("updated修改:",this.message);
            console.log("$el:"+this.$el);
            console.log("$data:"+this.$data);
            console.log("-------------")
        },
        beforeDestroy:function () {
            console.log("beforeDestroy销毁之前:",this.message);
            console.log("$el:"+this.$el);
            console.log("$data:"+this.$data);
            console.log("-------------")
        },
        destroyed:function () {
            console.log("destroyed销毁:",this.message);
            console.log("$el:"+this.$el);
            console.log("$data:"+this.$data);
            console.log("-------------")
        }

    });
    vm.message="bye vue";
    vm.$destroy();
</script>
</html>

在这里插入图片描述

三、使用Vue-Cli搭建Vue项目


3.1 vue-cli 介绍

cli: Command Line 命令行工具,vue-cli就是vue的命令行工具,也称之为脚手架,使用vue-cli提供的各种命令可以拉取、创建、运行我们需要使用到的框架,比如webpack、Element UI、Element Admin等等。那么要想使用vue-cli命令,需要先安装node.js。

3.2 node.js 介绍及安装

node.js提供了前端程序的运行环境,可以把node.js理解成是运行前端程序的服务器。

从官网下载安装即可:http://nodejs.cn/download/

3.3 axios.js 介绍

Axios 是一个开源的可以用在浏览器端和 NodeJS 的异步通信框架,她的主要作用就是实现 AJAX 异步通信,其功能特点如下:

  • 从浏览器中创建 XMLHttpRequests
  • 从 node.js 创建 http 请求
  • 支持 Promise API
  • 拦截请求和响应
  • 转换请求数据和响应数据
  • 取消请求
  • 自动转换 JSON 数据
  • 客户端支持防御 XSRF(跨站请求伪造)

由于 Vue.js 是一个 视图层框架 并且作者(尤雨溪)严格准守 SoC (关注度分离原则),所以 Vue.js 并不包含 AJAX 的通信功能,为了解决通信问题,作者单独开发了一个名为 vue-resource 的插件,不过在进入 2.0 版本以后停止了对该插件的维护并推荐了 Axios 框架

3.4 Element-Ul 介绍

Element-Ul是饿了么前端团队推出的一款基于Vue.js 2.0 的桌面端UI框架,手机端有对应框架是Mint UI

3.5 moment.js 介绍

moment.js是一个JavaScript的日期和时间处理工具类,提供了非常全面且强悍的日期处理功能

3.6 项目搭建流程

1.在 Terminal 下使用npm构建项目

1.首先安装Node.js

2.npm install -g @vue/cli        #安装vue-cli,该步骤需要等一段时间

3.vue -V                              #查看vue-cli的版本

4.vue create my-app                   #创建名为my-app的项目

5.my-app>npm install axios vue-axios element-ui --save #安装axios,vue-axios和 element-ui

6.my-app>npm install moment --save #安装格式化时间日期的moment.js

7.my-app>npm run serve  #启动项目

2.访问http://localhost:8080/ 会显示 HelloWorld.vue 该组件的页面

在这里插入图片描述

3.7 在 main.js 中添加如下配置

main.js 是该程序的入口

// 如下两个是网络的请求组件
import VueAxios from "vue-axios";
import axios from 'axios'

// ElmentUI的组件
import ElementUI from 'element-ui'
// ElementUI的样式
import 'element-ui/lib/theme-chalk/index.css'

Vue.use(VueAxios, axios)
Vue.use(ElementUI)

// 设置基础的url地址
axios.defaults.baseURL = 'http://localhost:8081'

3.8 修改 App.vue

注意:el-table-column 标签中的 prop属性 对应的是实体类的属性名

<template>
  <el-container>
    <el-header>管理系统</el-header>
    <el-container>
      <el-aside>系统列表</el-aside>
      <el-main>
        <el-table
                :data="musics"
                border
                style="width: 100%">
          <el-table-column
                  align="center"
                  prop="musicId"
                  label="编号">
          </el-table-column>
          <el-table-column
                  align="center"
                  prop="musicName"
                  label="歌曲名称"
                  width="180">
          </el-table-column>
          <el-table-column
                  align="center"
                  prop="musicAlbumName"
                  label="专辑名称"
                  width="180">
          </el-table-column>
          <el-table-column
                  align="center"
                  prop="musicArtistName"
                  label="歌手名称"
                  width="180">
          </el-table-column>
        </el-table>
      </el-main>
    </el-container>

  </el-container>
</template>

<script>

export default {
  name: 'App',
  components: {
    //HelloWorld
  },

  data(){
    return{
      musics:[]
    }
  },

  mounted() {

    // 第一种方式
    // let that = this;
    // this.axios.get('/music/findAll')
    //         .then(function (response) {
    //           that.musics = response.data;
    //         })
    //         .catch(function (error) {
    //           console.log(error);
    //         });

    // 第二种方式
    // this.axios.get('/music/findAll')
    //         .then(resp => {
    //           // resp.data才是实际的数据本身
    //           this.musics = resp.data;
    //           alert(this.musics)
    //         })

    // 第三种方式
    this.$http.get('/music/findAll').then((response) => {
      this.musics = response.data;
    })
  },
}
</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>

<!-- 设置容器样式 -->
<style>
  .el-header {
    background-color: #409EFF;
    color: #ffffff;
    line-height: 60px;
    font-size: 28px;
  }

  .el-aside {
    background-color: #e3e3e3;
    width: 180px !important;
  }

  .el-pagination {
    text-align: center;
    margin-top: 10px;
  }

  .el-table {
    margin-top: 10px;
  }
</style>

分别启动前后端项目进行测试(注:设置后端项目与前端项目端口号对应,在后端Controller层配置跨域:@CrossOrigin(origins = “*”)

3.9 moment.js 格式 Date 类型

1.在 main.js 引入 moment.js

import moment from 'moment'

2.在日期列添加属性

<el-table-column
    align="center"
    prop="createTime"
    label="时间"
    :formatter="formatDate"
    width="180">
</el-table-column>

3.在methods中添加对应的的方法

methods:{
    formatDate(row, column, currValue) {
      return moment(currValue).format('YYYY-MM-DD HH:mm:ss');
    }
}

3.10 分页

1.修改 data

data(){
    return{
      musics:[],
      total:0,
      pageSize:0
    }
  },

2.添加分页标签

<el-pagination
    background
    layout="prev, pager, next"
    :total="total"
    :page-size="pageSize"
    @current-change="toPage">
</el-pagination>

3.修改 methods

methods:{
    formatDate(row,column,currVal){
      return moment(currVal).format("YYYY-MM-DD")
    },
    toPage(currPage){
      this.axios.get('/music/findByPage?pageNum='+currPage)
              .then(resp => {
                // resp.data才是实际的数据本身
                this.musics = resp.data.list;
                //alert(this.musics)
                this.total = resp.data.total
                this.pageSize = resp.data.pageSize
              })
    }
  },

4.修改 mounted

mounted() {

    this.axios.get('/music/findByPage')
            .then(resp => {
              // resp.data才是实际的数据本身
              this.musics = resp.data.list;
              //alert(this.musics)
              this.total = resp.data.total
              this.pageSize = resp.data.pageSize
            })
  },

3.11 删除

1.添加标签

<el-table-column label="操作">
  <template slot-scope="scope">
   <el-button
    size="mini" type="primary" icon="el-icon-edit"
    @click="updateById(scope.row.musicId)">编辑</el-button>
   <el-button
    size="mini" type="danger" icon="el-icon-delete"
    @click="deleteById(scope.row.musicId)">删除</el-button>
 </template>
</el-table-column>

2.修改 data 以及 methods

  data(){
    return{
      musics:[],
      total:0,
      pageSize:0,
      currentPage:1
    }
  },

  methods:{
    formatDate(row,column,currVal){
      return moment(currVal).format("YYYY-MM-DD")
    },
    toPage(currPage){
      this.axios.get('/music/findByPage?pageNum='+currPage)
              .then(resp => {
                // resp.data才是实际的数据本身
                this.musics = resp.data.list;
                //alert(this.musics)
                this.total = resp.data.total
                this.pageSize = resp.data.pageSize
                this.currentPage = resp.data.pageNum
              })
    },
    deleteById(musicId){

      this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {

        this.axios.get('/music/deleteById?musicId='+musicId)
                .then(resp => {
                  if(resp.data == 'success'){
                    this.toPage(this.currentPage);
                  }
                })

        this.$message({
          type: 'success',
          message: '删除成功!'
        });
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消删除'
        });
      });
    }
  },

3.如果删除成功,页面没有跳转,需要去后端配置 pagehelper

pagehelper.helper-dialect=mysql
pagehelper.reasonable=true
pagehelper.support-methods-arguments=true

3.12 添加

1.在 el-main 标签中增加添加按钮

<el-button size="mini" type="success" @click="dialogVisible = true">添加</el-button>

2.添加 add 的对话框

      <el-dialog
              title="提示"
              :visible.sync="dialogVisible"
              width="30%"
              :before-close="handleClose">

        <el-form :model="musicModel" :rules="musicRules" ref="musicForm">
          <el-form-item label="id" prop="musicId">
            <el-input v-model="musicModel.musicId"></el-input>
          </el-form-item>
          <el-form-item label="歌曲" prop="musicName">
            <el-input v-model="musicModel.musicName"></el-input>
          </el-form-item>
          <el-form-item label="专辑" prop="musicAlbumName">
            <el-input v-model="musicModel.musicAlbumName"></el-input>
          </el-form-item>
          <el-form-item label="歌手" prop="musicArtistName">
            <el-input v-model="musicModel.musicArtistName"></el-input>
          </el-form-item>
          <el-form-item label="时间" prop="createTime">
            <el-date-picker type="date" placeholder="选择日期" v-model="musicModel.createTime" style="width: 100%;"></el-date-picker>
          </el-form-item>

          <el-form-item>
            <el-button type="primary" @click="submitForm('musicForm')">立即创建</el-button>
            <el-button @click="resetForm('musicForm')">重置</el-button>
          </el-form-item>
        </el-form>

      </el-dialog>

3.修改 data

  data(){
    return{

      musics:[],
      total:0,
      pageSize:0,
      currentPage:1,
      dialogVisible: false,

      musicModel: {
        musicId: '',
        musicName: '',
        musicAlbumName: '',
        musicArtistName: '',
        createTime: ""
      },
      musicRules: {
        musicId: [
          {required: true, message: '请输入id', trigger: 'blur'}
        ]
      }
    }
  },

4.在 method 中添加方法

    submitForm(formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          this.axios.post('/music/save',this.musicModel)
                  .then(resp => {
                    if(resp.data == "success"){
                      this.$refs[formName].resetFields();//清空下一次添加表单中的数据
                      this.dialogVisible = false //关闭添加的对话框
                      this.toPage(this.currentPage);
                    }
                  })
        } else {
          console.log('error submit!!');
          return false;
        }
      });
    },
    resetForm(formName) {
      this.$refs[formName].resetFields();
    },

5.后端Controller方法实现

//添加
    @RequestMapping("save")
    public String add(@RequestBody TbMusic tbMusic){
    
        tbMusicService.add(tbMusic);

        return "success";
    }

3.12 修改

1.在 data 中添加属性

updatedialogVisible:false

2.创建对话框

      <el-dialog
              title="提示"
              :visible.sync="updatedialogVisible"
              width="30%"
              :before-close="handleClose">

        <el-form :model="musicModel" :rules="musicRules" ref="updateForm">
          <el-form-item label="id" prop="musicId">
            <el-input v-model="musicModel.musicId" readonly="readonly"></el-input>
          </el-form-item>
          <el-form-item label="歌曲" prop="musicName">
            <el-input v-model="musicModel.musicName"></el-input>
          </el-form-item>
          <el-form-item label="专辑" prop="musicAlbumName">
            <el-input v-model="musicModel.musicAlbumName"></el-input>
          </el-form-item>
          <el-form-item label="歌手" prop="musicArtistName">
            <el-input v-model="musicModel.musicArtistName"></el-input>
          </el-form-item>
          <el-form-item label="时间" prop="createTime">
            <el-date-picker type="date" placeholder="选择日期" v-model="musicModel.createTime" style="width: 100%;"></el-date-picker>
          </el-form-item>

          <el-form-item>
            <el-button type="primary" @click="updateMusic('updateForm')">修改</el-button>
            <el-button @click="resetForm('updateForm')">重置</el-button>
          </el-form-item>
        </el-form>

      </el-dialog>

3.在 methods 中添加方法

updateById(musicId){

      this.updatedialogVisible =true;

      this.axios.get('/music/findById?musicId='+musicId)
              .then(resp => {
                  this.musicModel = resp.data;
              })
    },

    updateMusic(){
      this.axios.post('/music/updateMusic',this.musicModel)
              .then(resp => {
                if(resp.data == "success"){
                  this.updatedialogVisible = false //关闭添加的对话框
                  this.toPage(this.currentPage);
                }
              })
    }

4.编写 Controller 中的方法

@RequestMapping("updateMusic")
public String updateMusic(@RequestBody TbMusic tbMusic){

    tbMusicService.updateMusic(tbMusic);
    return "success";
}

四、Vue组件间的参数传递


4.1 在项目中创建子组件

1.在 Components 目录下创建 MyComponent 子组件,并编写

<template>
    <div>
        MyComponent...
        {{ MyTitle }}
        
        <button @click="MyMethod('bye vue')">修改内容</button>
    </div>
</template>

<script>
    export default {
        name: "MyComponent",

        //props:["MyTitle"],

        props:{
            MyTitle:{
                type:String,
                required:true,
                default:'defaultMyTitle'
            },

            MyMethod:{
                type: Function
            }
        }
    }
</script>

<style scoped>

</style>

4.2 注册子组件

在main.js中注册子组件

//导入子组件
import MyComponent from "./components/MyComponent";
//全局注册
Vue.component("MyComponent",MyComponent)

4.3 在App.vue中使用组件并传递参数

<div id="app">
      <MyComponent :MyTitle="msg" :MyMethod="changeMsg"></MyComponent>
</div>

export default {
 	data(){
    	return {
      		msg:'hello vue!!'
    	}
 	},
  
	methods:{
    	changeMsg(massage){
      		this.msg = massage;
    }
}

父传子:通过子组件的props部分,来指明可以接收的参数,父组件通过在标签中写明参数的键值对来传递参数。

props是表示一个组件的参数部分,那么props的写法有两种:

​ 1)props:[参数列表]

​ 比如: props:[‘MyProp1’,‘MyProp2’,…]

​ 2)props:{参数名1:{type:String,required:true,default:‘XX’},参数名2:{…}})

子传父:通过方法来传,子传给父,父还可以传给子

五、Vue-router 路由


5.1 介绍

Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌

5.2 准备工作

创建工程,并安装路由模块

vue create router-app 
router-app> npm install vue-router -s

5.3 Router 入门

1.在src下创建views文件夹,然后创建Home和About两个组件

<template>
    <div>
        <h1>Home</h1>
    </div>
</template>

<script>
    export default {
        name: "Home"
    }
</script>

<style scoped>

</style>
<template>
    <div>
        <h1>About</h1>
    </div>
</template>

<script>
    export default {
        name: "About"
    }
</script>

<style scoped>

</style>

2.在src下创建router文件夹,然后在里面定义一个index.js文件,在index.js文件中配置路由信息:

import Vue from 'vue'
import Router from 'vue-router'

import Home from "../views/Home";
import About from "../views/About";

Vue.use(Router)   //使用插件

export default new Router({

    routes: [
        {
            path: '/home',
            component: Home,
        },
        {
            path: '/about',
            component: About
        },
    ]

})

3.修改main.js

import Vue from 'vue'
import App from './App.vue'

//默认指向router目录下的index.js
import router from './router'

Vue.config.productionTip = false

new Vue({
  router,//配置router
  render: h => h(App),
}).$mount('#app')

4.修改App.vue

<template>

  <div id="app">
    <ul>
      <li>
        <router-link to="/home">Home</router-link>
      </li>
      <li>
        <router-link to="/about">About</router-link>
      </li>
    </ul>

    <hr>

    <!-- 设置路由显示 -->
    <div>
      <router-view></router-view>
    </div>
  </div>

</template>

<script>
//import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'App',
  components: {
    //HelloWorld
  }
}
</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>

5.访问浏览器进行测试即可

6.设置默认访问Home页面,修改index.js

import Vue from 'vue'
import Router from 'vue-router'

import Home from "../views/Home";
import About from "../views/About";

Vue.use(Router)   //使用插件

export default new Router({

    routes: [
        {
            path: '/home',
            component: Home,
        },
        {
            path: '/about',
            component: About
        },
        {
            path: '/',
            redirect: '/home'
        },
    ]

})

7.浏览器访问:localhost:8080,会显示Home页面,显示后路径会跳转为:localhost:8080/#/home,有#号

我们向router实例中添加mode属性:

  • 值"hash": url带# 适用于调试模式
  • 值"history" url不带#
import Vue from 'vue'
import Router from 'vue-router'

import Home from "../views/Home";
import About from "../views/About";

Vue.use(Router)   //使用插件

export default new Router({
    mode:'history',
    routes: [
        {
            path: '/home',
            component: Home,
        },
        {
            path: '/about',
            component: About
        },
        {
            path: '/',
            redirect: '/home'
        },
    ]

})

8.再次访问浏览器进行测试即可

5.4 子路由

1.在src/views目录下创建about目录,然后再创建Info.vue组件

<template>
    <div>
        <h1>Info</h1>
    </div>
</template>

<script>
    export default {
        name: "Info"
    }
</script>

<style scoped>

</style>

2.在index.js导入Info.vue组件并配置children子路由

import Vue from 'vue'
import Router from 'vue-router'

//导入组件,一次性全部加载
// import Home from "../views/Home";
// import About from "../views/About";
// import Info from "../views/about/Info";

//实际开发中,一般使用按需加载的方式
const Home = () => import('../views/Home');
const About = () => import('../views/About');
const Info = () => import('../views/about/Info');


Vue.use(Router)   //使用插件

export default new Router({
    mode:'history',
    routes: [
        {
            path: '/home',
            component: Home,
        },
        {
            path: '/about',
            component: About,
            children:[
                {
                    path:'/about/info',
                    component:Info
                }
            ]
        },
        {
            path: '/',
            redirect: '/home'
        },
    ]

})

3.修改About.vue组件

<template>
<!--    <div>-->
<!--        <h1>About</h1>-->
<!--    </div>-->

    <div>
        <center>
        <table border="1" cellpadding="0" cellspacing="0" width="200">
            <tr>
                <th>id</th>
                <th>name</th>
            </tr>
            <tr>
                <td>1</td>
                <td>
                    <router-link to="/about/info">jack</router-link>
                </td>
            </tr>
            <tr>
                <td>2</td>
                <td>
                    rose
                </td>
            </tr>
        </table>

        <router-view></router-view>
        </center>
    </div>

</template>

<script>
    export default {
        name: "About"
    }
</script>

<style scoped>

</style>

访问浏览测试即可

5.5 路由传参

1.修改index.js,在路径上配置 id和name 以及props

import Vue from 'vue'
import Router from 'vue-router'

//导入组件,一次性全部加载
// import Home from "../views/Home";
// import About from "../views/About";
// import Info from "../views/about/Info";

//实际开发中,一般使用按需加载的方式
const Home = () => import('../views/Home');
const About = () => import('../views/About');
const Info = () => import('../views/about/Info');


Vue.use(Router)   //使用插件

export default new Router({
    mode:'history',
    routes: [
        {
            path: '/home',
            component: Home,
        },
        {
            path: '/about',
            component: About,
            children:[
                {
                    path:'/about/info/:id/:name',
                    component:Info,
                    props:true
                }
            ]
        },
        {
            path: '/',
            redirect: '/home'
        },
    ]

})

2.修改Info.vue组件,设置id和name类型

<template>
    <div>
        <h1>Info</h1>
        <h1>{{ id }} -- {{ name }}</h1>
    </div>
</template>

<script>
    export default {
        name: "Info",
        props:{
            id:Number,
            name:String
        }
    }
</script>

<style scoped>

</style>

3.修改About.vue组件,设置参数值

<template>
<!--    <div>-->
<!--        <h1>About</h1>-->
<!--    </div>-->

    <div>
        <center>
        <table border="1" cellpadding="0" cellspacing="0" width="200">
            <tr>
                <th>id</th>
                <th>name</th>
            </tr>
            <tr v-for="(user,index) in users" :key="index">
                <td>{{ user.id }}</td>
                <td>
                    <router-link :to="'/about/info/' + user.id +'/' + user.name">{{ user.name }}</router-link>
                </td>
            </tr>
            <tr>
                <td>2</td>
                <td>
                    rose
                </td>
            </tr>
        </table>

        <router-view></router-view>
        </center>
    </div>

</template>

<script>
    export default {
        name: "About",
        data(){
            return{
                users:[
                    {id:1,name:'张三'},
                    {id:2,name:'李四'},
                    {id:3,name:'王五'},
                ]
            }
        }
    }
</script>

<style scoped>

</style>

4.访问浏览器测试即可

5.6 Element-ui 中的使用

1.切换到工程路径下,安装router

music-app> npm install --save router

2.在src下创建views文件夹,然后创建Music和Sheet两个组件

<template>
    <div>

        <el-dialog title="添加用户" :visible.sync="add">
            <el-form :model="musicModel" :rules="musicRules" ref="addForm">
                <!-- prop:指定具体规则,命名要和musicModel对应的属性名一致,否则验证会异常显示-->
                <el-form-item label="musicId" prop="musicId">
                    <el-input v-model="musicModel.musicId"></el-input>
                </el-form-item>
                <el-form-item label="musicName" prop="musicName">
                    <el-input v-model="musicModel.musicName"></el-input>
                </el-form-item>
                <el-form-item label="musicAlbumName" prop="musicAlbumName">
                    <el-input v-model="musicModel.musicAlbumName"></el-input>
                </el-form-item>
                <el-form-item label="musicArtistName" prop="musicArtistName">
                    <el-input v-model="musicModel.musicArtistName"></el-input>
                </el-form-item>
                <el-form-item label="createTime" prop="createTime">
                    <el-date-picker type="date" placeholder="选择日期" v-model="musicModel.createTime"></el-date-picker>
                </el-form-item>

            </el-form>

            <div slot="footer" class="dialog-footer">
                <el-button @click="add = false">取 消</el-button>
                <el-button type="primary" @click="addMusic">确 定</el-button>
            </div>
        </el-dialog>

            <el-button type="primary" size="mini" @click="add = true">添加</el-button>

            <el-table
                    :data="musics"
                    border
                    style="width: 100%">
                <el-table-column
                        align="center"
                        prop="musicId"
                        label="编号">
                </el-table-column>
                <el-table-column
                        align="center"
                        prop="musicName"
                        label="歌曲名称"
                        width="180">
                </el-table-column>
                <el-table-column
                        align="center"
                        prop="musicAlbumName"
                        label="专辑名称"
                        width="180">
                </el-table-column>
                <el-table-column
                        align="center"
                        prop="musicArtistName"
                        label="歌手名称"
                        width="180">
                </el-table-column>
                <el-table-column
                        align="center"
                        prop="createTime"
                        :formatter="formatDate"
                        label="时间"
                        width="180">
                </el-table-column>

                <el-table-column label="操作">
                    <template slot-scope="scope">
                        <el-button
                                size="mini" type="primary" icon="el-icon-edit"
                                @click="updateById(scope.row.musicId)">编辑</el-button>
                        <el-button
                                size="mini" type="danger" icon="el-icon-delete"
                                @click="deleteById(scope.row.musicId)">删除</el-button>
                    </template>
                </el-table-column>

            </el-table>

            <el-pagination
                    background
                    layout="prev, pager, next"
                    :total="total"
                    :page-size="pageSize"
                    @current-change="toPage">
            </el-pagination>

    </div>
</template>

<script>
    import moment from "moment";

    export default {
        name: "Music",

        data(){
            return{
                //msg:"hello vue",
                musics:[],
                total:0,
                pageSize:0,
                currentPage:1,
                add: false,
                musicModel: {
                    musicId:"",
                    musicName:"",
                    musicAlbumName:"",
                    musicArtistName:"",
                    createTime:"",
                },
                musicRules: {
                    musicId: [{required: true, message: 'musicId不能为空', trigger: 'blur'}]
                }
            }
        },

        methods:{
            // changeMsg(massage){
            //   this.msg = massage;
            // },

            formatDate(row,column,currVal){
                return moment(currVal).format("YYYY-MM-DD")
            },
            toPage(currPage){
                this.axios.get('/music/findByPage?pageNum='+currPage)
                    .then(resp => {
                        // resp.data才是实际的数据本身
                        this.musics = resp.data.list;
                        //alert(this.musics)
                        this.total = resp.data.total
                        this.pageSize = resp.data.pageSize
                        this.currentPage = resp.data.pageNum
                    })
            },
            deleteById(musicId){

                this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    type: 'warning'
                }).then(() => {

                    this.axios.get('/music/deleteById?musicId='+musicId)
                        .then(resp => {
                            if(resp.data == 'success'){
                                this.toPage(this.currentPage);
                            }
                        })

                    this.$message({
                        type: 'success',
                        message: '删除成功!'
                    });
                }).catch(() => {
                    this.$message({
                        type: 'info',
                        message: '已取消删除'
                    });
                });
            },

            addMusic() {
                this.$refs.addForm.validate((valid) => {
                    if (valid) {
                        this.axios.post('/music/save', this.musicModel)
                            .then(resp => {
                                if (resp.data == 'success') {
                                    this.add = false;
                                    this.toPage(this.currentPage); //重新加载当前页的数据
                                }
                            })
                    } else {
                        alert('error submit!!');
                        return false;
                    }
                });
            }


        },

        mounted() {

            this.axios.get('/music/findByPage')
                .then(resp => {
                    // resp.data才是实际的数据本身
                    this.musics = resp.data.list;
                    //alert(this.musics)
                    this.total = resp.data.total
                    this.pageSize = resp.data.pageSize
                })
        },

    }
</script>

<style scoped>

    .el-aside {
        background-color: #e3e3e3;
        width: 180px !important;
    }

    .el-pagination {
        text-align: center;
        margin-top: 10px;
    }

    .el-table {
        margin-top: 10px;
    }
</style>
<template>
    <h1>歌单管理</h1>
</template>

<script>
    export default {
        name: "Sheet"
    }
</script>

<style scoped>

</style>

3.在src下创建router目录,在router目录下创建index.js并编写index.js

import Vue from 'vue'
import Router from 'vue-router'

const Music = () => import("../views/Music")
const Sheet = () => import("../views/Sheet")

Vue.use(Router)   //使用插件

export default new Router({
    mode:'history',
    routes: [
        {
            path: '/music',
            component: Music,
        },
        {
            path: '/sheet',
            component: Sheet
        },
    ]

})

4.在main.js中导入router

import Vue from 'vue'
import App from './App.vue'

//导入子组件
//import MyComponent from "./components/MyComponent";
//全局注册
//Vue.component("MyComponent",MyComponent)

// 如下两个是网络的请求组件
import VueAxios from "vue-axios";
import axios from 'axios'

// ElmentUI的组件
import ElementUI from 'element-ui'
// ElementUI的样式
import 'element-ui/lib/theme-chalk/index.css'

Vue.use(VueAxios, axios)
Vue.use(ElementUI)

// 基础的url地址
axios.defaults.baseURL = 'http://localhost:8081'


Vue.config.productionTip = false

//默认指向router目录下的index.js
import router from './router'

new Vue({
  router,//配置router
  render: h => h(App),
}).$mount('#app')

5.修改App.vue

<template>
  <el-container>

<!--    <div id="app">-->
<!--      <MyComponent :MyTitle="msg" :MyMethod="changeMsg"></MyComponent>-->
<!--    </div>-->

    <el-header>管理系统</el-header>
    <el-container>
      <el-aside>
          <!-- 添加 router -->
          <el-menu router>
            <!-- element-ui将vue中的router的to属性,使用index来替代了 -->
            <el-menu-item index="/music">
              <i class="el-icon-setting"></i>歌曲管理
            </el-menu-item>
            <el-menu-item index="/sheet">
              <i class="el-icon-menu"></i>歌单管理
            </el-menu-item>
          </el-menu>
      </el-aside>
      <el-main>
      <!-- 编写 router-view -->
      <router-view></router-view>
      </el-main>
    </el-container>

  </el-container>
</template>

<script>

export default {
  name: 'App',
  components: {
    //HelloWorld
  },

}
</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>

<!-- 设置容器样式 -->
<style>
  .el-header {
    background-color: #409EFF;
    color: #ffffff;
    line-height: 60px;
    font-size: 28px;
  }

</style>

6.访问浏览器测试即可

六、 Vuex的应用


6.1 Vuex介绍

Vuex 是一个专为 Vue.js 应用程序开发的 状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

6.2 准备工作

1.在项目根目录执行如下命令来安装 Vuex

router-app> npm install vuex --save

2.在main.js 中导入 Vuex

import Vuex from 'vuex'
Vue.use(Vuex);

6.3 配置 vuex

1.在 src 目录下创建一个名为 store 的目录并新建一个名为 index.js 文件用来配置 Vuex

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);

// 全局 state 对象,用于保存所有组件的公共数据
const state = {
  // 定义一个 user 对象
  // 在组件中是通过 this.$store.state.user 来获取
  user: {
    name: ''
  }
};

// 实时监听 state 值的最新状态,注意这里的 getters 可以理解为计算属性
const getters = {
  // 在组件中是通过 this.$store.getters.getUser 来获取
  getUser(state) {
    return state.user;
  }
};

// 定义改变 state 初始值的方法,这里是唯一可以改变 state 的地方,缺点是只能同步执行
const mutations = {
  // 在组件中是通过 this.$store.commit('updateUser', user); 方法来调用 mutations
  updateUser(state, user) {
    state.user = user;
  }
};

// 定义触发 mutations 里函数的方法,可以异步执行 mutations 里的函数
const actions = {
  // 在组件中是通过 this.$store.dispatch('asyncUpdateUser', user); 来调用 actions
  asyncUpdateUser(context, user) {
    context.commit('updateUser', user);
  }
};

export default new Vuex.Store({
  state,
  getters,
  mutations,
  actions
});

2.修改 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
});
15.3.2 解决浏览器刷新后 Vuex 数据消失问题
  • 问题描述

Vuex 的状态存储是响应式的,当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。但是有一个问题就是:vuex 的存储的数据只是在页面的中,相当于我们定义的全局变量,刷新之后,里边的数据就会恢复到初始化状态。但是这个情况有时候并不是我们所希望的。

  • 解决方案

监听页面是否刷新,如果页面刷新了,将 state 对象存入到 sessionStorage 中。页面打开之后,判断 sessionStorage 中是否存在 state 对象,如果存在,则说明页面是被刷新过的,将 sessionStorage 中存的数据取出来给 vuex 中的 state 赋值。如果不存在,说明是第一次打开,则取 vuex 中定义的 state 初始值。

  • 修改代码

在 App.vue 中增加监听刷新事件

  export default {
    name: 'App',
    mounted() {
      window.addEventListener('unload', this.saveState);
    },
    methods: {
      saveState() {
        sessionStorage.setItem('state', JSON.stringify(this.$store.state));
      }
    }
  }

修改 store/index.js 中的 state

const state = sessionStorage.getItem('state') ? JSON.parse(sessionStorage.getItem('state')) : {
  user: {
    name: ''
  }
};

应用程序开发的 状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

6.2 准备工作

1.在项目根目录执行如下命令来安装 Vuex

router-app> npm install vuex --save

2.在main.js 中导入 Vuex

import Vuex from 'vuex'
Vue.use(Vuex);

6.3 配置 vuex

1.在 src 目录下创建一个名为 store 的目录并新建一个名为 index.js 文件用来配置 Vuex

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);

// 全局 state 对象,用于保存所有组件的公共数据
const state = {
  // 定义一个 user 对象
  // 在组件中是通过 this.$store.state.user 来获取
  user: {
    name: ''
  }
};

// 实时监听 state 值的最新状态,注意这里的 getters 可以理解为计算属性
const getters = {
  // 在组件中是通过 this.$store.getters.getUser 来获取
  getUser(state) {
    return state.user;
  }
};

// 定义改变 state 初始值的方法,这里是唯一可以改变 state 的地方,缺点是只能同步执行
const mutations = {
  // 在组件中是通过 this.$store.commit('updateUser', user); 方法来调用 mutations
  updateUser(state, user) {
    state.user = user;
  }
};

// 定义触发 mutations 里函数的方法,可以异步执行 mutations 里的函数
const actions = {
  // 在组件中是通过 this.$store.dispatch('asyncUpdateUser', user); 来调用 actions
  asyncUpdateUser(context, user) {
    context.commit('updateUser', user);
  }
};

export default new Vuex.Store({
  state,
  getters,
  mutations,
  actions
});

2.修改 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
});
15.3.2 解决浏览器刷新后 Vuex 数据消失问题
  • 问题描述

Vuex 的状态存储是响应式的,当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。但是有一个问题就是:vuex 的存储的数据只是在页面的中,相当于我们定义的全局变量,刷新之后,里边的数据就会恢复到初始化状态。但是这个情况有时候并不是我们所希望的。

  • 解决方案

监听页面是否刷新,如果页面刷新了,将 state 对象存入到 sessionStorage 中。页面打开之后,判断 sessionStorage 中是否存在 state 对象,如果存在,则说明页面是被刷新过的,将 sessionStorage 中存的数据取出来给 vuex 中的 state 赋值。如果不存在,说明是第一次打开,则取 vuex 中定义的 state 初始值。

  • 修改代码

在 App.vue 中增加监听刷新事件

  export default {
    name: 'App',
    mounted() {
      window.addEventListener('unload', this.saveState);
    },
    methods: {
      saveState() {
        sessionStorage.setItem('state', JSON.stringify(this.$store.state));
      }
    }
  }

修改 store/index.js 中的 state

const state = sessionStorage.getItem('state') ? JSON.parse(sessionStorage.getItem('state')) : {
  user: {
    name: ''
  }
};
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Vue 的相关文章

随机推荐

  • C++循环依赖的一些解决方法

    若存在两个类A B使得A类中含有B类的对象且B类中包含A类的对象 xff0c 则称A B之间存在循环依赖 如 class B class A public B b class B public A a 若两个类之间存在循环依赖则在编译时会报
  • Read-only file system怎么解决?

    Read only file system怎么解决 xff1f 我的思路是先查看 proc mounts文件里面的目录的权限 xff0c 确定是否缺少w权限 如果确定缺少的话 xff1a 解决方法 xff1a mount o remount
  • php 上传文件 出现413 Request Entity Too Large问题的解决方法

    配置 xff1a php 43 nginx 需求 xff1a 上传小文件正常 xff0c 上传大于2M 的PDF文件就提示 出现413 Request Entity Too Large问题的解决方法 经过排查 xff0c 这是nginx 拦
  • C语言中,通过指针得到相应数组的长度

    通过指针得到相应数组的长度 xff0c 1 通过指针得到浮点型数组的长度 2 通过指针得到字符串型数组的长度 得到浮点型数组长度 int arrayVlenth float p int len 61 0 while p p 43 43 le
  • Python监控目录文件夹,并使用SFTP上传目录及文件到linux服务器

    Python 扫描监控本地文件夹并进行超大文件上传 方案1 WebUploader大文件分块多线程并发上传 方案2 watchdog目录文件夹监控 paramiko STFP上传服务器 方案3 优化2 压缩后上传 服务器解压 1 监控本地文
  • 本地组策略编辑器关闭windows10的自动更新

    具体操作 xff1a win 43 R输入 gpedit msc 打开组策略 xff0c 在 计算机配置 管理模板 windows组件 Windows更新 里找到 指定Intranet microsoft 更新服务位置 xff0c 双击打开
  • PVE虚拟机篇-PVE虚拟机安装

    安装包下载 前往Proxmox Virtual Environment下载ISO镜像文件 xff0c 可以直接选择最新版本 但是如果没有海外线路一般下载十分缓慢 xff0c 甚至下不动 xff0c 所以可以去中科大镜像源 xff1a 中科大
  • PVE虚拟机篇-pve软件换源

    起因 由于安装pve的第二天突然发现后台显示执行错误 xff0c 更新软件源失败 xff1a 更新软件源方法 注释企业源 echo 34 deb https enterprise proxmox com debian pve bullsey
  • 解决android opengl glReadPixels 慢的问题 二

    解决android opengl glReadPixels 慢的问题 二 上篇讲到使用pbo解决glreadpix慢的问题 xff0c 但是效果不太理想 xff0c 后来参考链接 xff1a OpenGL Pixel Buffer Obje
  • Tesseract 3.02中文字库训练

    下载chi sim traindata字库 下载tesseract ocr setup 3 02 02 exe 下载地址 xff1a http code google com p tesseract ocr downloads list 下
  • Windows下使用pip安装包 出错 TLS/SSL

    Windows下使用pip安装包的时候出现如下问题 xff1a WARNING pip is configured with locations that require TLS SSL however the ssl module in
  • C++进阶(七)-模板与群体数据8

    选择排序 选择排序的基本思想 每次从待排序序列中选择一个关键字最小的元素 xff0c xff08 当需要按关键字升序排列时 xff09 xff0c 顺序排在已排序序列的最后 xff0c 直至全部排完 例9 12 简单选择排序函数模板 tem
  • Ubuntu 20.04 WARNING笔记(长期更新,欢迎交流)

    记录使用Ubuntu 20 04过程的报错 以及解决 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
  • 循环嵌套例题

    循环嵌套例题 1 例题1 span class token comment 代码 span span class token keyword for span span class token punctuation span span c
  • java实现学生信息管理(对象数组实现)

    java实现学生信息管理 xff08 对象数组实现 xff09 1 例题 实体类 学生类 id 姓名 xff0c 年龄 xff0c 性别 xff0c 成绩 需要使用数组保存学生信息 Student allStu 需要完成的方法 1 根据学生
  • java基础语法思维导图

    java从入门到放弃 简单总结之前的
  • 学生管理系统2.0 (可对学生数组扩容)

    学生管理系统2 0 可对学生数组扩容 1 用户可初始化数组长度 xff0c 不够用时可以扩充数组容量 尝试完成以下功能 实体类 学生类 id 姓名 xff0c 年龄 xff0c 性别 xff0c 成绩 需要使用数组保存学生信息 Studen
  • LinkedList和Set

    LinkedList和Set 1 LinkedList 1 1 LinkedList概述 底层存储数据是一个双向链表结构 自行车链子 就是一个生活中链表结构 xff0c 环环相扣 xff0c 替换 xff0c 拆除非常方便 1 2 Link
  • shiro与springboot整合

    Shiro 与 SpringBoot 的整合 1 创建SpringBoot工程 xff0c 导入依赖 span class token generics function span class token punctuation lt sp
  • Vue

    Author Thor Version 9 0 1 文章目录 一 Vue简介1 1 简介1 2 MVVM 模式的实现者 双向数据绑定模式1 3 其它 MVVM 实现者1 4 为什么要使用 Vue js1 5 Vue js 的两大核心要素1