Vue.js学习

1、概念和特点

  • 概念:Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式JavaScript框架。 与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。发布时间为2014年2月。
  • 特点
    • 更加轻量20kb min + gzip
    • 渐进式框架
    • 响应式的更新机制
    • 学习成本低

2、MVVM模式的实现者

  • Model:模型层,在这里表示avaScript对象

  • View:视图层,在这里表示DOM(HTML操作的元素)

  • ViewModel:连接视图和数据的中间件,Vue.js就是MVVM中ViewModel的实现者
    在MVVM架构中,是不允许数据和视图直接通信的,只能通过ViewModel来通信,而ViewModel就是定义了一个Observer观察者

  • ViewModel能够视察到数据的变化,并对视图对应的内容进行更新

  • ViewModel能够监听到视图的变化,并能够通知数据发生改变

3、Vue基本语法

带有前缀v-的被称为指令,以表示它们是Vue提供的体术属性,它们会在渲染的DOM上应用特殊的响应式行为,该指令的意思是“将这个元素节点的title特性和Vue实例的message属性保持一致”
如果再次打开浏览器的JavaScript控制台,输入app.message="新消息",就会再一次看到这个绑定了title特性的HTML已经进行了更新。

  • v-bind
<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    {{message}}<br/>
    <span v-bind:title="message">消息</span>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
    var vm = new Vue({
        el:"#app",
        data:{
            message:"Hello Vue!!!"
        }
    });
</script>
</body>
</html>
  • v-if和v-else
  <!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <span v-if="status">成功</span>
    <span v-else>失败</span>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
    var vm = new Vue({
        el:"#app",
        data:{
            status:true
        }
    });
</script>
</body>
</html>
  • v-for
<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <div v-for="arr in arrs">
        {{arr.message}}
    </div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
    var vm = new Vue({
        el:"#app",
        data:{
            arrs:[
                {message:"啦啦啦"},
                {message:"哈哈哈"}
            ]
        }
    });
</script>
</body>
</html>

4、Vue绑定事件(v-on)

<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>绑定事件</title>
</head>
<body>
<div id="app">
    <button v-on:click="alertMsg">点我</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
    var vm = new Vue({
        el:"#app",
        data:{
            message:"hahaha"
        },
        methods:{
            alertMsg:function (event) {
                alert(this.message);
            }
        }
    });
</script>
</body>
</html>

5、Vue双向绑定(v-model)

<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>双向绑定</title>
</head>
<body>
<div id="app">
    请输入内容:
    <input type="text" v-model="message"/><br/>
    输入的内容为:{{message}}
    <br/><br/>

    性别:<input type="radio" name="sex" value="男" v-model="checked"/>男
    <input type="radio" name="sex" value="女" v-model="checked"/>女
    <br/>
    选择的性别为:{{checked}}
    <br/><br/>

    兴趣爱好:
    <select v-model="selected">
        <option value="" disabled>--请选择--</option>
        <option>羽毛球</option>
        <option>钢琴</option>
    </select>
   <br/>
    选择的兴趣爱好为:{{selected}}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
    var vm = new Vue({
        el:"#app",
        data:{
            message:"121",
            checked:"男",
            selected:""
        },
        methods:{

        }
    });
</script>
</body>
</html>

注意:v-model会忽略所有表单元素的value、checked、selected特性的初始值,而总是将Vue实例的数据作为数据来源。你应该通过JavaScript在组件的data选项中声明初始值

6、Vue组件

  <!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>组件</title>
</head>
<body>
<div id="app">
    <my-component v-for="hobby in hobbys"></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>

    Vue.component("my-component",{
        template:"<li>{{hobby}}</li>"
    });

    var vm = new Vue({
        el:"#app",
        data:{
            hobbys:["钢琴","篮球","羽毛球"]
        }

    });
</script>
</body>
</html>

说明:

  • Vue.component():注册组件
  • my-component:自定义组件的名字
  • template:组件的模板
  • 使用props属性传递参数
    向上面那样用组件没有任何意义,所以我们是需要传递参数到组件的,此时就需要使用props属性了。
  <!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>组件</title>
</head>
<body>
<div id="app">
    <my-component v-for="hobby in hobbys" v-bind:test="hobby"></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>

    Vue.component("my-component",{
        props:["test"],
        template:"<li>{{test}}</li>"
    });

    var vm = new Vue({
        el:"#app",
        data:{
            hobbys:["钢琴","篮球","羽毛球"],
            test:""
        }

    });
</script>
</body>
</html><!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>组件</title>
</head>
<body>
<div id="app">
<!--通过v-bind绑定一个变量,把hobyy变量对应的数据传递到自定义的组件,自定一的组件通过props来接收传过来的数据-->
    <my-component v-for="hobby in hobbys" v-bind:test="hobby"></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>

    Vue.component("my-component",{
        props:["test"],
        template:"<li>{{test}}</li>"
    });

    var vm = new Vue({
        el:"#app",
        data:{
            hobbys:["钢琴","篮球","羽毛球"],
            test:""
        }

    });
</script>
</body>
</html>

7、Axios异步通信

Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中,是基于ajax的异步通信。
特性:

  • 从浏览器中创建 XMLHttpRequests
  • 从 node.js 创建 http 请求
  • 支持 Promise API
  • 拦截请求和响应
  • 转换请求数据和响应数据
  • 取消请求
  • 自动转换 JSON 数据
  • 客户端支持防御 XSRF
<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>组件</title>
</head>
<body>
<div id="app">
    <div>{{info.name}}</div>
    <div>{{info.address.street}}</div>
    <a v-bind:href="info.link">点我</a>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>


    var vm = new Vue({
        el:"#app",
       data(){
            //返回的只是数据的格式
            return{
                info:{
                    name:null
                }
            }
       },

       mounted(){//使用钩子函数
            axios.get("../data.json").then(response=>(this.info=response.data))
       }

    });
</script>
</body>
</html>

8、计算属性

  • 计算出来的结果,保存在属性中
<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>组件</title>
</head>
<body>
<div id="app">
    currentTime1:{{currentTime1()}}<br/>
    currentTime2:{{currentTime2}}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>


    var vm = new Vue({
        el:"#app",
       data:{
            message:""
       },
        methods:{
            currentTime1:function (event) {
                return Date.now();
            }
        },
        computed:{
            currentTime2:function (event) {
                return Date.now();
            }
        }

    });
</script>
</body>
</html>

说明:

  • methods:定义方法,调用方法使用currentTime1(),需要带括号
  • computed:定义计算属性,调用属性使用currentTime2,不需要带括号;this.message是为了能够让currentTime2观察到数据变化而变化
  • 如果在方法中的值发生了变化,则缓存就会刷新。可以在控制台使用vm.message="zixin",改变下数据的值,再次测试观察效果

结论:
调用方法时,每次都需要进行计算,既然有计算过程则必定产生系统开销,那如果这个结果是不经常变化的,此时就可以考虑将这个结果缓存起来,采用计算属性可以很方便的做到这一点,计算属性的主要特性就是为了将不经常变化的计算结果进行缓存,以节约我们的系统开销。

9、插槽slot

在Vue.js中我们使用<slot>元素作为分发内容的出口,称为插槽,可以用用在组合组件的场景中。

<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>slot插槽</title>
</head>
<body>
<!--将在父模板中定义的值通过插槽插入子模版中-->
<div id="app">
    <father>
        <son-title slot="son-title" v-bind:title="title"></son-title>
        <son-item slot="son-item" v-for="it in items" v-bind:item="it"></son-item>
    </father>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
    //定义父模板
    Vue.component("father",{
        template:'<div>'+
            '<slot name="son-title"></slot>' +
            '<ul>'+
            '<slot name="son-item"></slot>'+
            '</ul>' +
        '</div>'
    });
    //子模版:标题
    Vue.component("son-title",{
        props:["title"],
        template:"<p>{{title}}</p>"
    });
    //子模版:列表
    Vue.component("son-item",{
        props:["item"],
        template: "<li>{{item}}</li>"
    });

    var vm = new Vue({
        el:"#app",
       data:{
           message:"",
           title:"兴趣爱好",//标题
           item:"",
           items:["羽毛球","篮球","钢琴"]//列表数据
       }

    });
</script>
</body>
</html>

10、自定义事件内容分发

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>事件分发</title>
</head>
<body>
<div id="app">
    <father>
        <son-title slot="son-title" v-bind:title="title"></son-title>
        <son-item slot="son-item" v-for="(it,index) in items" :item="it" :key="index" :index="index"></son-item>
    </father>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>

    Vue.component("father",{
        template:'<div>'+
            '<slot name="son-title"></slot>' +
            '<ul>'+
            '<slot name="son-item"></slot>'+
            '</ul>' +
            '</div>'
    });

    Vue.component("son-title",{
        props:["title"],
        template:"<p>{{title}}</p>"
    });
    Vue.component("son-item",{
        props:["item","index"],
        template: "<li>{{item}}<button v-on:click='removeItem(index)'>删除</button></li>"
    });

    var vm = new Vue({
        el:"#app",
        data:{
            message:"",
            title:"兴趣爱好",
            item:"",
            items:["羽毛球","篮球","钢琴"]
        },
        methods:{
            removeItem:function (index) {
                console.log("要删除的为"+this.items[index]);
            }
        }

    });
</script>
</body>
</html>

通过上面的代码不难发现,数据项在Vue的实例中,但删除操作要在组件中完成,那么组件如何才能删除Vue实例中的数据呢?此时就涉及到参数传递与事件分发了,Vue为我们提供了自定义事件的功能 ,很好地帮助了我们解决了这个问题:使用this.$emit('自定义事件名',参数),操作过程如下:

  1. 在Vue的实例中,增加了methods对象并定义了一个名为removeItem的方法
removeItem:function (index) {
                console.log("要删除的为"+this.items[index]);
                this.items.splice(index, 1);
            }
  1. 修改son-item代办内容组件的代码,增加一个删除按钮,并绑定事件
 template: "<li>{{item}}<button type='button' v-on:click='butClick(index)'>删除</button></li>",
  1. 修改son-item代办内容组件的HTML代码,增加一个自定义事件,比如叫butClick,可以和组件的方法绑定,然后绑定到Vue的方法中
methods:{
            butClick:function (index) {
                this.$emit('remove', index);
            }
        }


<son-item slot="son-item" v-for="(it,index) in items" v-bind:item="it" v-bind:key="index" v-bind:index="index" v-on:remove="removeItem(index)"></son-item>

全部代码:

   <!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>事件分发</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">
    <father>
        <son-title slot="son-title" v-bind:title="title"></son-title>
        <son-item slot="son-item" v-for="(it,index) in items" v-bind:item="it" v-bind:key="index" v-bind:index="index" v-on:remove="removeItem(index)"></son-item>
    </father>
</div>
<script>

    Vue.component("father",{
        template:'<div>'+
            '<slot name="son-title"></slot>' +
            '<ul>'+
            '<slot name="son-item"></slot>'+
            '</ul>' +
            '</div>'
    });

    Vue.component("son-title",{
        props:["title"],
        template:"<p>{{title}}</p>"
    });
    Vue.component("son-item",{
        props:["item","index"],
        template: "<li>{{item}}<button type='button' v-on:click='butClick(index)'>删除</button></li>",
        methods:{
            butClick:function (index) {
                this.$emit('remove', index);
            }
        }
    });

    var vm = new Vue({
        el:"#app",
        data:{
            message:"",
            title:"兴趣爱好",
            item:"",
            items:["羽毛球","篮球","钢琴"]
        },
        methods:{
            removeItem:function (index) {
                console.log("要删除的为"+this.items[index]);
                this.items.splice(index, 1);
            }
        }

    });
</script>
</body>
</html>

11、第一个vue-cli程序

准备工作

  1. 下载和安装Node.js
    官网下载后打开文件,然后无脑下一步,即可安装完成。

  2. 检查Node.js是否安装成功
    在控制台输入node -v与npm -v,若输出版本号表示安装成功

  3. 安装Node.js淘宝镜像加速器(cnpm)
    Node.js有时候下载会很慢,下载淘宝加速器,下载会快很多

  # -g 全局安装,在全局环境下都能使用
  npm install cnpm -g

  # 或每次需要用到淘宝加速器的时候手动添加如下语句解决npm速度慢的问题
  npm install --registry=https://registry.npm.taobao.org

建议npm下载失败再用cnpm下载,因为cnpm下载的文件有时候会出问题

  1. 安装vue-cli
  cnpm install vue-cli -g
  
  #测试是否安装成功
  #查看可以基于那些模块创建vue应用程序,通常我们选择webpack
  vue list

创建项目步骤

  1. 创建一个Vue项目,我们随便建立一个空的文件夹在电脑上,我这里在F盘下新建一个目录
    F:\ideaworkplace\vuestudy

  2. 创建一个基于webpack模板的vue应用程序

  #这里的myvue时项目名称,可以根据自己的需求起名
  vue init webpack myvue

一路都选择no即可

说明:

  • Project name:项目名称,默认回车即可
  • Project description:项目描述,默认回车即可
  • Author:作者
  • Vue build:vue构建方式
  • Install vue-router:是否安装路由
  • Use ESLint to lint your code:使用ESLint对代码进行规范
  • Set up unit tests:是否设置单元测试
  • Setup e2e tests with Nightwatch:是否使用Nightwatch设置e2e
  • Should we run npm install for you after the project has been created? (recommended):是否在工程创建后就去跑 npm 安装依赖

创建好的项目目录

  1. 初始化项目并运行
  cd myvue
  npm install
  npm run dev
  • 先执行前面两个命令,下载依赖

  • 执行完成后,目录多了很多依赖

  • 再执行npm run dev运行项目

  • 运行成功页面如下

12、webpack学习使用

  1. 安装
  npm install webpack -g
  npm install webpack-cli -g
  1. 测试是否安装成功
  • webpack -v
  • webpack-cli -v
  1. 配置
    创建webpack.config.js配置文件
  • entry:入口文件,指定WebPack用那个文件作为项目的入口
  • output:输出,指定WebPack把处理完成的文件防止到指定路径
  • module:模块,用于处理各种类型的文件
  • plugins:插件,如:热更新、代码重用等
  • resovle:设置路径指向
  • watch:监听,用于设置文件改动后直接打包
  modules.exports = {
    entry:"",
    output:{
      path:"",
      filename:""
    },
    modules:{
      loaders:{
        {test:/\.js$/,loader:""}
      }
    },
    plugins:{},
    resolve:{},
    watch:true
  }

  1. 使用webpack
  • 创建一个项目(空文件夹,用idea打开)
  • 创建一个名为modules的目录,用于放置JS模块等资源文件
  • 在modules下创建模块文件,如hello.js,用于编写JS模块相关代码
  //暴露一个方法
  exports.sayHi = function(){
    document.write("<div>Hello WebPack!</div>")
  }
  • 在modules下创建一个名为main.js的入口文件,用于打包时设置entry属性
  //require导入一个模块,就可以调用这个模块中的方法了
  var hello = require("./hello");
  hello.sayHi();
  • 在项目目录下创建webpack.config.js配置文件
  module.exports = {
    entry:"./modules/main.js",
    output:{
      filename:"./js/bundle.js"
    }
  };
  • 直接运行webpack命令打包

  • 项目中多个一个dist文件夹,里面存放刚刚打包的js文件

  • 编写一个index.html页面,同时引入刚刚打包好的js文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>测试引入打包后的js文件</title>
    <script src="dist/js/bundle.js"></script>
</head>
<body>

</body>
</html>
  • 运行index.html文件,看效果

13、vue-router路由

  1. 概念
    Vue Router是Vue.js官方的路由管理器。它和Vue.js的核心深度集成,让构建单页面应用变得易如反掌,包含的功能有:
  • 嵌套的路由/视图表
  • 模块化的、基于组件的路由配置
  • 路由参数、查询、通配符
  • 基于Vue.js过渡系统的视图过度效果
  • 细粒度的导航控制
  • 带有自动激活的CSS class的链接
  • HTML5历史模式或hash模式,在IE9中自动降级
  • 自定义的滚动行为
  1. 安装
    基于第一个vue-cli进行测试学习,先查看node_modules中是否存在vue-router
    vue-router是一个插件包,所以需要用npm/cnpm来进行安装的。打开命令行工具,进入项目目录,输入下面命令。
  npm install vue-router --save

此时遇到安装失败如下

原因是npm版本过高,此时需要降低npm的版本,执行执行下面命令

  #安装低版本的npm
  npm install npm@6.14.10 -g

注意:如果在一个模块化工程中使用它,必须要通过Vue.use()明确地安装路由功能

  import Vue from 'vue'
  import VueRouter from 'vue-router'

  Vue.use(VueRouter);
  1. 测试
  • 先删除没有用的东西
  • components目录下存放我们自己编写的组件
  • 定义一个Content.vue组件
  <template>
    <div>
      <h1>内容页</h1>
    </div>
  </template>

  <script>
    export default {
      name:'Content'
    }
  </script>
  <style scoped>

  </style>
  • 定义一个Main.vue组件
  <template>
    <div>
      <h1>首页</h1>
    </div>
  </template>

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

  <style scoped>

  </style>
  • 安装路由,在src目录下,新建一个文件夹:router,专门存放路由,在下面创建一个index.js文件
  import Vue from 'vue'
  import VueRouter from 'vue-router'
  //导入组件
  import Content from "../components/Content";
  import Main from "../components/Main";


  //安装路由
  Vue.use(VueRouter);

  //配置导出路由
  export default new VueRouter({
    routes:[
      {
        //路由路径
        path:'/content',
        name:'content',
        //跳转的组件
        component:Content
      },
      {
        path: '/main',
        name:'main',
        component: Main
      },

    ]
  });
  • 在main.js中配置路由
  import Vue from 'vue'
  import App from './App'

  //自动扫描里面的路由配置
  import router from './router'

  Vue.use(router);

  new Vue({
    el: '#app',
    //配置路由
    router,
    render:h=>h(App)
  });
  • 在App.vue中使用路由
  <template>
    <div id="app">
      <h1>路由首页</h1>
      <router-link to="/main">首页</router-link>
      <router-link to="/content">内容页</router-link>
      <router-view></router-view>
    </div>
  </template>

  <script>

  export default {
    name: 'App',
    components: {
    }
  }
  </script>

  <style>

  </style>
  • 测试,发现了下面的错误

问题原因:安装了最新的vue-router,版本大概是4.0.12,我最开始安装vuecli没有指定版本
解决方法:降低vue-router的版本,这里我换成了3.0.1

  #卸载新版本的vue-router
  npm uninstall vue-router
  #安装指定版本的vue-router
  npm i vue-router@3.0.1
  • 重新运行,得到如下运行成功的页面

14、vue+elementUI

创建工程(命令行都要使用管理员模式运行)

  1. 创建一个名为hellovue的工程vue init webpack hellovue

  2. 安装依赖,我们需要安装vue-router、element-ui、sass-loader和node-sass四个插件

  #进入工程目录
  cd hellovue

  #安装vue-router
  npm install vue-router --save

  #安装element-ui
  npm i element-ui -S
  
  #安装依赖
  npm install

  #安装sass加载器
  cnpm install sass-loader node-sass --save-dev

  #启动测试
  npm run dev
  1. npm命令解释
  • npm install moduleName:安装模块到项目目录下
  • npm installl -g moduleName:-g的意思是将模块安装到全局,具体安装到磁盘那个位置,要看npm config prefix的位置
  • npm install -save moduleName:--save的意思是将模块安装到项目目录下,并在package文件的dependencies节点写入依赖,-S为该命令的缩写
  • npm install --save-dev moduleName:--save-dev的意思是将模块安装到项目目录下,并在package文件的devDependencies节点写入依赖,-D为该命令的缩写
  1. 用idea打开项目,并删除多余的东西,重新使用npm run dev运行项目,运行结果如下

  2. 测试

  • Login.vue
  <template>
    <div>
      <el-form ref="loginForm" :model="form" :rules="rules" label-width="80px" class="login-box">
        <h3 class="login-title">欢迎登录</h3>
        <el-form-item label="账号" prop="username">
          <el-input type="text" placeholder="请输入账号" v-model="form.username"/>
        </el-form-item>
        <el-form-item label="密码" prop="password">
          <el-input type="password" placeholder="请输入密码" v-model="form.password"/>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" v-on:click="onSubmit('loginForm')">登录</el-button>
        </el-form-item>
      </el-form>

      <el-dialog
        title="温馨提示"
        :visible.sync="dialogVisible"
        width="30%"
        :before-close="handleClose">
        <span>请输入账号和密码</span>
        <span slot="footer" class="dialog-footer">
          <el-button type="primary" @click="dialogVisible = false">确 定</el-button>
        </span>
      </el-dialog>
    </div>
  </template>

  <script>
    export default {
      name: "Login",
      data() {
        return {
          form: {
            username: '',
            password: ''
          },
          //表单验证,需要在el-form-item 元素中增加prop 属性
          rules: {
            username: [
              {required: true, message: " 账号不可为空", trigger: 'blur'}
            ],
            password: [
              {required: true, message: " 密码不可为空 ", trigger: 'blur'}
            ]
          },
          //对话框显示和隐藏
          dialogVisible: false
        }
      },methods: {
        onSubmit(formName) {
          //为表单绑定验证功能
          this.$refs[formName].validate((valid) => {
            if (valid) {
            //使用vue-router路由到指定页面,该方式称之为编程式导航
              this.$router.push("/main");
            } else {
              this.dialogVisible = true;
              return false;
            }
          });
        }
      }
    }
  </script>

  <style lang="scss" scoped>
    .login-box {
      border: 1px solid #DCDFE6;
      width: 350px;
      margin: 180px auto;
      padding: 35px 35px 15px 35px;
      border-radius: 5px;
      -webkit-border-radius: 5px;
      -moz-border-radius: 5px;
      box-shadow: 0 0 25px #909399;
    }

    .login-title {
      text-align: center;
      margin: 0 auto 40px auto;
      color: #303133;
    }
  </style>
  • Main.vue
  <template>
    <div>
      <el-container>
        <el-aside width="200px">
          <el-menu :default-openeds="['1']">
            <el-submenu index="1">
              <template slot="title"><i class="el-icon-caret-right"></i>用户管理</template>
              <el-menu-item-group>
                <el-menu-item index="1-1">
                  <router-link to="/user/profile">个人信息</router-link>
                </el-menu-item>
                <el-menu-item index="1-2">
                  <router-link to="/user/list">用户列表</router-link>
                </el-menu-item>
              </el-menu-item-group>
            </el-submenu>
            <el-submenu index="2">
              <template slot="title"><i class="el-icon-caret-right"></i>内容管理</template>
              <e1-menu-item-group>
                <el-menu-item index="2-1">分类管理</el-menu-item>
                <el-menu-item index="2-2">内容列表</el-menu-item>
              </e1-menu-item-group>
            </el-submenu>
          </el-menu>
        </el-aside>
        <el-container>
          <el-header style="text-align: right; font-size: 12px">
            <el-dropdown>
              <i class="el-icon-setting" style="margin-right:15px"></i>
              <el-dropdown-menu slot="dropdown">
                <el-dropdown-item>个人信息</el-dropdown-item>
                <el-dropdown-item>退出登录</el-dropdown-item>
              </el-dropdown-menu>
            </el-dropdown>
          </el-header>

          <el-main>
            <router-view/>
          </el-main>

        </el-container>
      </el-container>
    </div>
  </template>

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

  <style scoped lang="scss">
    .el-header {
      background-color: #048bd1;
      color: #333;
      line-height: 60px;
    }

    .el-aside {
      color: #333;
    }
  </style>
  • Profile.vue
  <template>
      <div>
        <h1>个人信息</h1>
      </div>
  </template>

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

  <style scoped>

  </style>
  • UserList.vue
  <template>
    <div>
      <h1>用户列表</h1>
    </div>
  </template>

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

  <style scoped>

  </style>
  • index.js
  import Vue from 'vue'
  import Router from 'vue-router'

  //引入组件
  import Main from "../components/Main";
  import Login from "../components/Login";
  import Profile from "../components/user/Profile";
  import UserList from "../components/user/UserList";

  //安装路由
  Vue.use(Router);

  let router = new Router({
    routes:[
      {
          path:'/main',
          name:'Main',
          component:Main,
          children:[
            {
              path:'/user/profile',
              name:'Profile',
              component:Profile,
            },
            {
              path:'/user/list',
              name:'UserList',
              component:UserList,
            }
          ]
      },
      {
          path: '/login',
          name:'Login',
          component: Login
      }
    ]
  });
  export default router
  • main.js
  import Vue from 'vue'
  // import {createApp} from 'vue'
  import App from './App'
  //引入element-ui
  import ElementUI from 'element-ui';
  import 'element-ui/lib/theme-chalk/index.css';

  //引入路由
  import router from './router';
  //
  Vue.use(ElementUI);
  Vue.use(router);

  new Vue({
    el: '#app',
    router,
    render: h => h(App)
  });
  • App.vue
  <template>
    <div id="app">
      <router-view/>
    </div>
  </template>

  <script>

  export default {
    name: 'App'
  }
  </script>

  <style>

  </style>

运行时遇到问题

原因:因为node-loader版本过高导致的问题,我们尝试将版本降低到@4.14.1
解决方法:直接使用命令:npm install sass-loader@4.14.1 --save-dev 降低版本号,再进行npm run dev即可运行

15、路由嵌套

  1. 如上面的Main.vue页面中代码,点击这些链接,右边显示对应的页面
    <!--导航栏:用于在右边显示不同的页面->
    <el-menu-item-group>
      <el-menu-item index="1-1">
        <router-link to="/user/profile">个人信息</router-link>
      </el-menu-item>
      <el-menu-item index="1-2">
        <router-link to="/user/list">用户列表</router-link>
      </el-menu-item>
    </el-menu-item-group>


   <!--点击链接后跳转的页面显示的地方-->
    <el-main>
       <router-view/>
    </el-main>
  1. 在router目录下的index.js中的routes数组,在component为Main中添加如下代码
   children:[
      {
        path:'/user/profile',
        name:'Profile',
        component:Profile,
      },
      {
        path:'/user/list',
        name:'UserList',
        component:UserList,
      }
    ]

注意:必须要引入对应的组件

16、参数传递及重定向

  1. 参数传递

方式一

  • 将Main.vue中的个人信息链接改成下面代码:
  <!--有参数时,必须使用对象,同时to必须绑定-->
  <router-link :to="{name:'Profile',params:{id:1}}">个人信息</router-link>
  • index.js中Profile组件的代码修改为如下:
    {
      path:'/user/profile/:id',
      name:'Profile',
      component:Profile,
    },

注意:参数名必须与传过来的一致

  • 重新运行,运行结果与预期一致

方式二

  • 在Login.vue中的onSubmit方法跳转到main页面时添加参数:
      onSubmit(formName) {
        //为表单绑定验证功能
        this.$refs[formName].validate((valid) => {
          if (valid) {
          //使用vue-router路由到指定页面,该方式称之为编程式导航
            this.$router.push("/main/"+this.form.username);
          } else {
            this.dialogVisible = true;
            return false;
          }
        });
      },
  • 在路由主文件中的Main路由对象中,开启props,同时在path的后面添加/:name
    {
        path:'/main/:name',
        name:'Main',
        component:Main,
        props:true,
        children:[
          {
            path:'/user/profile/:id',
            name:'Profile',
            component:Profile,
          },
          {
            path:'/user/list',
            name:'UserList',
            component:UserList,
          },
          {
            path:'/goTop',
            redirect:'/main'
          }
        ]
    },
    {
        path: '/login',
        name:'Login',
        component: Login
    },
    {
      path: '*',
      name:'NotFound',
      component: NotFound
    }
  • 在Main.vue页面中接收参数
<script>
    export default {
        name: "Main",
        props:["name"]
    }
</script>
  • 显示在页面中
  <span>{{name}}</span>
  • 重新运行,运行结果与预期一致
  1. 重定向
  • 在Main.vue中添加一个子菜单栏
    <el-submenu index="3">
      <template slot="title"><i class="el-icon-caret-right"></i>系统管理</template>
      <e1-menu-item-group>
        <el-menu-item index="3-1">
          <router-link to="/goTop">回到首页</router-link>
        </el-menu-item>
      </e1-menu-item-group>
    </el-submenu>
  • 在index.js中的children中添加如下代码
  {
    path:'/goTop',
    redirect:'/main'
  }
  • 重新运行,点击回到首页链接,成功跳转

17、404和路由钩子

路由模式有两种

修改路由配置,代码如下:

  export default new VueRouter({
    mode:'history',
    routes:[
    ]
  })

处理404

  • 在component文件夹下创建一个名为NotFound.vue的视图组件,代码如下:
  <template>
    <div>
      页面不存在,请重试
    </div>
  </template>

  <script>
    export default {
      name:'NotFound'
    }
  </script>
  <style scoped>

  </style>
  • 在路由的主文件index.js中添加如入代码
  {
      path: '*',
      name:'404',
      component: NotFound
  }

18.路由钩子与异步请求

  1. 路由钩子
    beforeRouteEnter:在渲染该组件的第一营路由被confirm前调用,不能获取组件实例this,因为当守卫执行前,组件实例还没被创建
    beforeRouteLeave:导航离开该组件的对应路由时调用,可以访问组件实例this
  • to: Route: 即将要进入的目标路由对象

  • from: Route: 当前导航正要离开的路由

  • next:理由的控制参数

    • next():跳入下一个页面
    • next('/path'):改变路由的跳转方向,使其跳到另一个路由
    • next(false):返回原来的页面
    • next((vm)=>{})仅在beforeRouteEnter中可用,vm使组件实例

测试:

  • 在Profile组件中添加两个钩子函数
  <template>
      <div>
        <h1>个人信息</h1>
        {{$route.params.id}}
      </div>
  </template>

  <script>
      export default {
          name: "Profile",
          beforeRouteEnter(to, from, next){
            console.log("进入组件时路由调用");
            next();
          },
          beforeRouteLeave(to, from, next){
            console.log("离开组件时路由调用");
            next();
          }
      }
  </script>
  • 运行测试
    点击个人信息链接时执行beforeRouteEnter,点击其他链接时执行beforeRouteLeave
  1. 在钩子函数中使用异步请求
  • 安装Axios cnpm install axios --save
  • 在main.js中引用Axios
  import axios from 'axios'
  // axios需要使用prototype将axios挂载到原型上 ,$后面是自己另起的名称,以后就可以使用该名称
  Vue.prototype.axios = axios;
  1. 准备数据:只有我们的static目录下的文件是可以被访问到的,所以我们把静态文件放入该目录下
  //静态数据存放的位置
  static/jsondata/data.json
  {
      "name":"狂神说java",
      "url": "http://baidu.com",
      "page": "1",
      "isNonProfit":"true",
      "address": {
      "street": "含光门",
      "city":"陕西西安",
      "country": "中国"
      },
      "links": [
      {
        "name": "B站",
        "url": "https://www.bilibili.com/"
      },
      {
        "name": "4399",
        "url": "https://www.4399.com/"
      },
      {
        "name": "百度",
        "url": "https://www.baidu.com/"
      }
    ]
  }
  1. 在Profile.vue页面中的methods{}中添加一个getData方法
   methods:{
    getData(){
      this.axios({
        method:'get',
        url:'http://localhost:8080/static/jsondata/data.json'
      }).then(response=>{
          console.log(response);
      })
    }
}
  1. 在beforeRouteEnter中进行异步请求
   beforeRouteEnter(to, from, next){
      console.log("进入组件时路由调用");
      next((vm)=>{
        vm.getData();
      });

    },
  1. 运行测试,遇到下面的问题


原因是:将this.axios写成了this.$axios

修改后成功获取到数据

posted @ 2022-02-14 10:51  RBAZX  阅读(34)  评论(0编辑  收藏  举报