Vue基础入门

一、入门概述

Vue是一套用于构建用户界面的渐进式JavaScript框架

特点:
轻量级:体积小
渐进式:不需要学完全部功能,用到什么学什么
响应式:数据更新之后,视图不需要刷新,会自动更新
学习成本低:基于HTML和js,官方文档都是中文
官方教程文档:https://cn.vuejs.org/v2/guide/

安装引入
Vue有两年环境版本
开发版本:
包含完整的警告和调试模式
本地下载:https://cn.vuejs.org/js/vue.js

生产版本:
删除了警告,33.30KB min+gzip
本地下载:https://cn.vuejs.org/js/vue.min.js

CDN引入:

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

二、基础语法

1、声明式渲染

示例:

<div id="app">{{message}}</div>
<script type="text/javascript">
    var vm =new Vue({
        el:"#app",
        data:{
            message:"hello Vue!"
        }
    })
</script>

页面显示结果:

hello Vue!

el叫做挂载点,对应的值是html元素的id。一个Vue应用会将其挂载到一个DOM元素上,即这个id对应的元素。挂载点支持css选择器,推荐使用id选择器。挂载点的DOM只支持双标签(和标签除外),不支持单标签。
data是渲染的时候动态的数据,当这些数据改变时,视图会进行重渲染(不需要手动刷新),也就是响应式。
在Vue中使用{{属性名}} (插值)来获取data中的值,如上面代码中的{{message}}对应的就是data中的message

2、条件渲染

指令:v-if
控制一个元素是否显示,使用指令。在Vue中,元素中V-前缀的特殊属性叫做指令。指令的职责是,当表达式的值改变时,将其产生的连带影响。

<div id="app">
    <p v-if="seen">直接显示的内容</p>
    <p v-else >默认隐藏</p>
</div>
    var vm =new Vue({
        el:"#app",
        data:{
            seen:true
        }
    })

浏览器显示:

直接显示的内容

指令:v-show
也是控制一个元素是否显示,不过改变的是样式(适合频繁切换的元素),而v-if改变的是DOM树。

<div id="app">
    <p v-show="seen">直接显示的内容</p>
</div>
<script type="text/javascript">
    var vm =new Vue({
        el:"#app",
        data:{
            seen:false
        }
    })
</script>

浏览器显示:


当seen为false改变了css样式

<p style="display: none;">直接显示的内容</p>
3、列表渲染

指令:v-for
显示的数据是一个数组

<div id="app">
    <ul>
        <li v-for="todo in todos">{{todo.text}}</li>
    </ul>
</div>
<script type="text/javascript">
    var vm =new Vue({
        el:"#app",
        data:{
            todos:[{text:"爱学习,爱java"},{text: "java是世界上最好的语言"},{text: "day day up"}]
        }
    })
</script>

页面效果:

爱学习,爱java
java是世界上最好的语言
day day up

在控制台里,输入vm.todos.push({ text: '新的内容' }),列表最后会添加新内容。
复杂一点的数据

<div id="app">
    <ul>
        <li v-for="goods in goodsList">商品名:{{goods.name}}<br>商品价格:{{goods.price}}</li>
    </ul>
</div>
<script type="text/javascript">
    var vm = new Vue({
        el: "#app",
        data: {
            goodsList: [{"id": 1, "name": "苹果", "price": 10},
                {"id": 2, "name": "香蕉", "price": 12},
                {"id": 3, "name": "梨", "price": 8}]
        }
    })
</script>

浏览器显示:

商品名:苹果
商品价格:10
商品名:香蕉
商品价格:12
商品名:梨
商品价格:8

获取索引可以使用v-for="(goods,index) in goodsList" ,其中index是当前元素的索引,{{index}}可以获取到当前元素的索引

4、原始html

如果响应式的内容是HTML,就不能使用双大括号,需要使用v-html指令

<div id="app">
    <ul>
        <li>差值表达式支持输出的内容:{{rawHtml}}</li>
        <li>指令v-html输出的内容:<span v-html="rawHtml"></span></li>
    </ul>
</div>
<script type="text/javascript">
    var vm = new Vue({
        el: "#app",
        data: {
            rawHtml:"<span><a href='#' style='color: red'>文字内容</a></span>"
        }
    })
</script>

浏览器显示:

差值表达式支持输出的内容:<span><a href=’#’ style=‘color: red’>文字内容</a></span>`
指令v-html输出的内容:文字内容

5、表达式

对于所有的数据绑定,Vue 都提供了完全的JavaScript 表达式支持。每个绑定都只能包含单个表达式

<div id="app">
    <ul>
        <li>{{!seen?"false":"true"}}</li>
        <li>{{num+1}}</li>
        <li>{{text+",你来自哪里"}}</li>
    </ul>
</div>
<script type="text/javascript">
    var vm = new Vue({
        el: "#app",
        data: {
            seen:true,
            num:1,
            text:"你是谁"
        }
    })
</script>

浏览器显示:

true
2
你是谁,你来自哪里
6、绑定属性

指令:v-bind
缩写是::属性名
用于响应式地更新HTML属性

<div id="app">
    <ul>
        <li v-bind:class="id"></li>
        <li :class="id"></li>
    </ul>
</div>
<script type="text/javascript">
    var vm = new Vue({
        el: "#app",
        data: {
            id:"top"
        }
    })
</script>

审查元素看元素节点属性:

<ul>
    <li class="top"></li>
    <li class="top"></li>
</ul>
7、绑定样式

可以传给v-bind:class一个对象,以动态地切换class, 也可以传递数组,或者进行一些计算。
使用v-bind:style绑定css样式。

    <style type="text/css">
        .active{
            color: red;
        }
        .large-cls{
            font-weight: bolder;
        }
    </style>

<div id="app">
    <ul>
        <li v-bind:class="{active:isActive}">文本内容1</li>
        <!--静态和指令共存-->
        <li :class="{active:isActive}" class="large-cls">文本内容2</li>
        <!--绑定数组-->
        <li :class="[activeClass,largeClass]">文本内容3</li>
        <!--绑定对象-->
        <li :class="classObj1">文本内容4</li>
        <!--绑定计算的对象-->
        <li :class="classObj2">文本内容5</li>
    </ul>
</div>
<script type="text/javascript">
    var vm = new Vue({
        el: "#app",
        data: {
            isActive:false,
            activeClass:"active",
            largeClass:"large-cls",
            classObj1:{active:true}
        },
        computed:{
            classObj2:function () {
                return{
                    active:this.isActive,
                    'large-cls':!this.isActive//名字中有特殊符号,如“-”,用单引号
                }
        }
        }
    })
</script>

生成的静态class属性

<ul>
    <li class="">文本内容1</li>
    <li class="large-cls">文本内容2</li>
    <li class="active large-cls">文本内容3</li>
    <li class="active">文本内容4</li>
    <li class="large-cls">文本内容5</li>
</ul>
8、绑定事件

指令:v-on:事件名
简写:@事件名
使用v-on绑定事件

<div id="app">
    <ul>
        <li >num={{num}} &nbsp;<button v-on:click="num+=1" >add 1</button></li>
        <li ><button v-on:click="method1(str)">点击领红包</button></li>
        <li ><button @click="method2">hello</button></li>
    </ul>
</div>
<script type="text/javascript">
    var vm = new Vue({
        el: "#app",
        data: {
            num:0,
            str:"恭喜你获得500元"
        },
        methods:{
            method1:function (str) {
                alert(str)
            },
            method2:function () {
                console.log("helllo vue")
            }
        }
    })
</script>

显示效果:
在这里插入图片描述

9、表单数据

指令:v-model
在表单元素上创建双向数据绑定。v-model会忽略表单元素默认值,而将Vue实例的数据作为数据来源。

<div id="app">
    <ul>
        <li >用户名:<input type="text" name="userName" v-model="nameVal"></li>
        <li >密码:<input type="password" name="password" v-model="passwordVal"></li>
        <li >性别:<input type="radio" name="sex" value="1" v-model="sexVal"><input type="radio" name="sex" value="2" v-model="sexVal"></li>
        <li >爱好:<input type="checkbox" name="hobby" value="1" v-model="hobbyVal">看书<input type="checkbox" name="hobby" value="2" v-model="hobbyVal">电影<input type="checkbox" name="hobby" value="3" v-model="hobbyVal">唱歌</li>
        <li ><select name="city" v-model="sityVal">
            <option value="1">深圳</option>
            <option value="2">上海</option>
        </select></li>
    </ul>
</div>
<script type="text/javascript">
    var vm = new Vue({
        el: "#app",
        data: {
            nameVal:"张三",
            passwordVal:"a66666",
            sexVal:1,
            hobbyVal:[1,2],
            sityVal:1
        }
    })
</script>

浏览器显示:
在这里插入图片描述

10、过滤器
<div id="app">
    <ul>
        <li >{{message|filter1}}</li>
        <li >{{message|filter2('arg1', 'arg2')}}</li>
    </ul>
</div>
<script type="text/javascript">
    var vm = new Vue({
        el: "#app",
        data: {
            message:"Hello Vue"
        },
        filters:{
            filter1:function (value) {
               return value.toUpperCase();
            },
            filter2:function (value,arg1,arg2) {
                return value+arg1+arg2;
            }
        }
    })
</script>

浏览器显示:

HELLO VUE
Hello Vuearg1arg2
11、计算属性

对于复杂逻辑,需要使用计算属性。computed将不经常变化的计算结果进行缓存,以节约系统开销。

<div id="app">
    <ul>
        <li >{{getTime1}}</li>
        <li >{{getTime2()}}</li>
    </ul>
</div>
<script type="text/javascript">
    var vm = new Vue({
        el: "#app",
        computed:{
            getTime1:function () {
                return new Date();
            }
        },
        methods:{
            getTime2:function () {
                return new Date();
            }
        }
    })
</script>

methods和computed区别是:
methods需要带括号, computed不需要
computed计算的值会缓存起来,多次调用,其值不变:
在这里插入图片描述

12、声明组件

组件可复用的Vue实例。可以把组件看成小型的,独立的U模块。
一个组件必须有一个根节点
全局组件,在当前Vue实例中都可用,局部注册的组件只在父组件中可用。
父子组件data无法共享

<div id="app">
    <button-counter></button-counter>
    <button-counter></button-counter>
    <comp2></comp2>
</div>
<script type="text/javascript">
    //声明组件
    Vue.component('button-counter', {
        template:'<div>num={{num}}&nbsp;<button v-on:click="num+=1">add 1</button>&nbsp;<button v-on:click="method1(str)">点击领红包</button>&nbsp;<button @click="method2()">hello</button><innerChild></innerChild></div>',
        methods: {
            method1: function (str) {
                alert(str)
            },
            method2: function () {
                alert("hello vue")
            }
        },
        data:function () {
            return{
                num:0,
                str: "恭喜你获得500元"
            }
        },
        components:{
            innerChild:{
                template:'<span>局部组件</span>'
            }
        }
    })
    Vue.component('comp2',{
        template:'<button-counter></button-counter>'
    })
    var vm = new Vue({
        el: "#app"
    })
</script>
13、axios动态数据

引入文件

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<div id="app">
    <button @click="search">查询</button>
    <ul><li v-for="data in dataList">{{data.id}}-{{data.name}}-{{data.price}}</li></ul>
</div>
<script type="text/javascript">
    var vm= new Vue({
        el:"#app",
        data:{
            dataList:[]
        },
        methods:{
            search:function () {
                axios.get("./data.json").then(res=>{
                    console.log(res.data)
                    this.dataList=res.data;
                });
            }
        }
    })
</script>

data.json

[{"id": 1, "name": "苹果", "price": 10},
  {"id": 2, "name": "香蕉", "price": 12},
  {"id": 3, "name": "梨", "price": 8}]

打开浏览器点击查询显示数据
在这里插入图片描述

三、组件详解

1、属性(父传子)

自定义属性props:组件的props中声明的属性
原生属性attrs:没有声明的属性,默认自动挂载到组件根元素上。
特殊属性class、style:挂载到组件根元素上,支持字符串、对象。数组等多种语法

属性可以通过数组的形式列出:

props:['title','commentIds','author']

但在正式开发的时候,为了系统的维护性,我们还是推荐使用如下形式,注意组件中的属性名,在html标签中并不是使用驼峰。如果使用的是数字类型或者其它动态值,需要使用v-bind:

<div id="app">
<!--数字和布尔绑定需要动态赋值,不然会报错,:prop-c="abc"会报错,字母动态赋值会被认为是方法或变量-->
    <button-counter :prop-a="1" :prop-b="1" prop-c="abc" :prop-d="20" prop-f="success"></button-counter>
</div>
<script type="text/javascript">
    //声明组件
    Vue.component('button-counter', {
        template: '<div>propA:{{propA}}<br/>propB:{{propB}}<br/>propC:{{propC}}<br/>propD:{{propD}}<br/>propE:{{propE}}<br/>propF:{{propF}}</div>',
        //声明属性
        props: {
            //基础的类型检查('null'和、'undefined'会通过任何类型验证)
            propA: Number,
            //多个可能的类型
            propB: [String, Number],
            //必填的字符串
            propC: {
                type: String,
                required: true
            },
            //带有默认值的数字类型
            propD: {
                type: Number,
                default: 100
            },
            //带有默认值的对象类型
            propE: {
                type: Object,
                //对象或数组默认值必须从一个工厂函数获取
                default: function () {
                    return {
                        message:"hello Vue!"
                    }
                }
            },
            propF:{
                validator:function (value) {
                    //这个值必须匹配下列字符串的一个
                    return ['success','warning','danger'].indexOf(value)!==-1
                }
            }
        }
    })
    var vm = new Vue({
        el: "#app"
    })
</script>

浏览器显示:

propA:1
propB:1
propC:abc
propD:20
propE:{ "message": "hello Vue!" }
propF:success
2、事件

普通事件:@click@change等事件, 通过this.$emit( 'myEvent' )触发(子传父)。
修饰符事件:@input.trim@click.stop等, 自定义组件需要自行开发。

<div id="app">
    <my-component></my-component>
</div>
<script type="text/javascript">
    Vue.component('my-component',{
        template: '<div @click="HandlerDivClick"><button @click="HandlerButClick">向上传递</button><button @click.stop="HandlerButClick">阻止冒泡</button></div>',
        methods:{
            HandlerDivClick:function () {
                console.log("aaa")
            },
            HandlerButClick:function () {
                console.log("bbb")
            }
        }
    })
  var vm=new Vue({
      el:"#app"
  })
</script>

浏览器显示:
在这里插入图片描述
父传子靠属性,子传父靠事件

<div id="app">
    <!--不带括号默认传event,默认写法-->
    <child @myevent="father"></child>
    <!--带括号$event固定写法-->
    <child @myevent="father($event)"></child>
</div>
<script type="text/javascript">
    Vue.component('child', {
        template: `    <div>
            <button @click="callParent()">子传父</button>
        </div>`,
        data:function () {
            return {
                childName:"aaa"
            }
        },
        methods: {
            callParent: function () {
                console.log("child")
                this.$emit('myevent',this.childName)//子组件触发父组件的方法
            }
        }
    })
    var vm = new Vue({
        el: "#app",
        methods: {
            father:function (e) {
                console.log("I’m father:"+e)
            }
        }
    })
</script>

控制台输出:

child
I’m father:aaa
3、插槽

在Vue中如果在自定义组件的标签内部写东西,默认是不显示的。使用slot实现插槽功能,可以显示在组件中写的内容。

<div id="app">
    <div-counter>默认不显示</div-counter>
</div>
<script type="text/javascript">
    //声明组件
    Vue.component('div-counter', {
        template: `    <div>
        <ul>
            <slot></slot>
            <li>这是内容1</li>
            <li>这是内容1</li>
        </ul>
    </div>`,
    })
    var vm = new Vue({
        el: "#app"
    })
</script>

浏览器显示:

默认不显示
这是内容1
这是内容1

具名插槽
把内容插入到指定的插槽中,当插槽名都有名字,而插入的内容没有名字指向,则内容不会显示

<div id="app">
    <div-counter><div slot="a">插槽a的内容</div><div slot="b">插槽b的内容</div></div-counter>
</div>
<script type="text/javascript">
    //声明组件
    Vue.component('div-counter', {
        template: `    <div>
        <ul>
            <slot name="a"></slot>
            <li>这是内容1</li>
            <li>这是内容1</li>
            <slot name="b"></slot>
        </ul>
    </div>`,
    })
    var vm = new Vue({
        el: "#app"
    })
</script>

浏览器显示:

插槽a的内容
这是内容1
这是内容1
插槽b的内容
4、中央事件组件

兄弟组件之间相互调用,可以使用中央事件组件

<div id="app">
    <c1></c1>
    <c2></c2>
</div>
<script type="text/javascript">
    var bus=new Vue();
    Vue.component('c1', {
        template: `<div><input ref="msg">
            <button @click="HandleClick">这是组件1</button>
        </div>`,
        methods:{
            HandleClick:function () {
                console.log(this.$refs.msg.value)
                bus.$emit('myListener',this.$refs.msg.value)//发布携带的事件myListener
            }
        }
    })
    Vue.component('c2', {
        template: `<div>
            <button>这是组件2</button>
        </div>`,
        mounted:function () {
            bus.$on('myListener',function (data) {//订阅事件
                console.log('组件2接收的内容:'+data)
            })
        }

    })
    var vm = new Vue({
        el: "#app"
    })
</script>

控制台显示内容
在这里插入图片描述

5、动态组件

动态组件使用<component>标签占位,使用is属性指定具体替换为哪个组件。每次切换都会重新渲染组件。使用<keep-alive>

<div id="app">
    <!--组件只被初始化一次-->
    <keep-alive>
        <component :is="nav"></component>
    </keep-alive>
    <!--点击改变nav值切换组件-->
    <button @click="nav='home'">home</button>
    <button @click="nav='list'">list</button>
</div>
<script type="text/javascript">
    var vm = new Vue({
        el: "#app",
        components:{
            list:{
                template:`<div>list<input></div>`,
                mounted:function () {
                    console.log('mounted')//查看组件初始化次数
                }
            },
            home:{
                template: `    <div>home</div>
`
            }
        },
        data:{
            nav:"list"
        }
    })
</script>

浏览器显示:
在这里插入图片描述

四、生命周期

每个Vue实例在被创建时都要经过一系列的初始化过程,叫做生命周期钩子

<div id="app">
    <button  @click="message='content changed'" >{{ message }}</button>
</div>

<script type="text/javascript">

    var vm = new Vue({
        el: '#app',
        data: {
            message : "Hello Vue!"
        },
        beforeCreate: function () {
            console.group('beforeCreate 创建前状态===============》');
            console.log("%c%s", "color:red" , "el     : " + this.$el); //undefined
            console.log("%c%s", "color:red","data   : " + this.$data); //undefined
            console.log("%c%s", "color:red","message: " + this.message)//undefined
        },
        created: function () {
            console.group('created 创建完毕状态===============》');
            console.log("%c%s", "color:red","el     : " + this.$el); //undefined
            console.log("%c%s", "color:red","data   : " + this.$data); //已被初始化
            console.log("%c%s", "color:red","message: " + this.message); //已被初始化
        },
        beforeMount: function () {
            console.group('beforeMount 挂载前状态===============》');
            console.log("%c%s", "color:red","el     : " + (this.$el)); //已被初始化
            console.log(this.$el);
            console.log("%c%s", "color:red","data   : " + this.$data); //已被初始化
            console.log("%c%s", "color:red","message: " + this.message); //已被初始化
        },
        mounted: function () {
            console.group('mounted 挂载结束状态===============》');
            console.log("%c%s", "color:red","el     : " + this.$el); //已被初始化
            console.log(this.$el);
            console.log("%c%s", "color:red","data   : " + this.$data); //已被初始化
            console.log("%c%s", "color:red","message: " + this.message); //已被初始化
        },
        beforeUpdate: function () {
            console.group('beforeUpdate 更新前状态===============》');
            console.log("%c%s", "color:red","el     : " + this.$el);
            console.log(this.$el);
            console.log("%c%s", "color:red","data   : " + this.$data);
            console.log("%c%s", "color:red","message: " + this.message);
        },
        updated: function () {
            console.group('updated 更新完成状态===============》');
            console.log("%c%s", "color:red","el     : " + this.$el);
            console.log(this.$el);
            console.log("%c%s", "color:red","data   : " + this.$data);
            console.log("%c%s", "color:red","message: " + this.message);
        },
        beforeDestroy: function () {
            console.group('beforeDestroy 销毁前状态===============》');
            console.log("%c%s", "color:red","el     : " + this.$el);
            console.log(this.$el);
            console.log("%c%s", "color:red","data   : " + this.$data);
            console.log("%c%s", "color:red","message: " + this.message);
        },
        destroyed: function () {
            console.group('destroyed 销毁完成状态===============》');
            console.log("%c%s", "color:red","el     : " + this.$el);
            console.log(this.$el);
            console.log("%c%s", "color:red","data   : " + this.$data);
            console.log("%c%s", "color:red","message: " + this.message)
        }
    })
</script>

生命周期代码来源:https://segmentfault.com/a/1190000008010666
挂载结束前的状态
在这里插入图片描述
更新状态
在这里插入图片描述

五、脚手架Vue CLI

1、安装node.js

官网下载:https://nodejs.org/en/download/
在这里插入图片描述
安装版直接双击安装,解压版解压文件
解压后创建两个文件夹
在这里插入图片描述

配置环境变量,在系统变量下新建一个NODE_HOME变量,把新建的NODE_HOME添加到PATH中
在这里插入图片描述
cmd配置刚才新建的两个文件夹
执行命令

npm config set cache "E:\study\node-v12.18.2-win-x64\npm_cache"
npm config set prefix "E:\study\node-v12.18.2-win-x64\npm_global"

再添加环境变量

%NODE_PATH%\npm_global

安装cnmp,加快下载速度

npm install -g cnpm --registry=https://registry.npm.taobao.org

安装vue脚手架:

cnpm install -g @vue/cli
2、创建项目

创建一个项目路径,在该项目路径中执行vue create 名字,按上下箭头切换,选择手动配置Manually这个再回车进入下一步
在这里插入图片描述
空格选中需要安装的模块
在这里插入图片描述
后面几步选择,右侧有对应值
在这里插入图片描述
之后开始下载…

工程下载完成
在这里插入图片描述
按照提示信息,进入到项目内,执行命令

npm run serve

提示访问地址
在这里插入图片描述
根据提示访问地址,出现如下页面表示项目创建成功
在这里插入图片描述

idea中打开启动方式
在这里插入图片描述
idea中的npm工具启动
在这里插入图片描述
在工具中启动,默认端口8080,修改端口在Arguments使用-- --port 80

3、单文件组件

在App.vue写入如下内容:
单页面分为三部分:模板标签、js和css

<template>
  <div id="app">
    <div>
      <input ref="msg">
      <button @click="add()">添加</button>
      <ul>
        <li v-for="data in dataList" :key="data">{{data}}</li>
      </ul>
    </div>
  </div>
</template>

<script>
export default {
  // ()相当于:funtion()
  data () {
    return {
      dataList: []
    }
  },
  methods: {
    add () {
      console.log(this.$refs.msg.value)
      this.dataList.push(this.$refs.msg.value)
    }
  }
}
</script>

<style>
  ul,li{
    list-style: none;
    background-color: #ccc;
  }
</style>
4、项目打包

使用nmp run lint 可以将代码格式化,符合ES6风格。
使用npm run build 可以将项目打包,打包成功后会有一个dist文件夹, 将这个文件夹中的内容给后端开发人员即可(emmm就是你自己咯)
在这里插入图片描述

5、axios反向代理

跨域:端口、协议或域名不一致
模块化开发需要在当前的工程下安装axios模块npm install axios ,在页面中引入axios模块,跨域的时候,axios的请求路径不写域名,交给代理实现

<template>
  <div>
    <ul>
      <button @click="search">查询</button>
      <li v-for="data in dataList">{{data.id}}-{{data.name}}</li>
    </ul>
  </div>
</template>

<script>
import Vue from 'vue'
import axios from 'axios'

export default {
  data () {
    return {
      dataList: []
    }
  },
  methods: {
    search: function () {
      axios.get('/tupes')
        .then(res => {
          this.dataList = res.data
        })
    }
  }
}
</script>

axios跨域请求时会报错,可以请求到数据,但无法使用
在这里插入图片描述
这时需要配置反向代理,在项目根目录src下创建vue.config.js文件:

module.exports = {
  devServer: {
    proxy: {
      '/types': {
        target: 'http://localhost:8099',
        changeOrigin: true
      }
    }
  }
}

六、路由

1、一级路由

对於单页面应用,使用路由切换组件,先创建两个组件

<template>
  <div>
    <h1>用户</h1>
  </div>
</template>
<script>
export default {}
</script>

在router文件夹下的index.js中配置路由信息。这个路径是可以自定义的,和main.js中的路径相对应

import Vue from 'vue'
import VueRouter from 'vue-router'
import User from '../views/User'
import Order from '../views/Order'

Vue.use(VueRouter)

const routes = [
  {
    path: '/user', // 对应页面中的#/user
    component: User // 组件User
  },
  {
    path: '/order',
    component: Order
  }
]

const router = new VueRouter({
  routes
})

export default router

main.js中引入路由文件:此处创建项目会默认配置
在这里插入图片描述
在App.vue主页面中,需要展示组件的地方加上<router-view></ router-view>

      <ul>
        <li><a href="#/user">用户页面</a></li>
        <li><a href="#/order">订单页面</a></li>
      </ul>
      <!--类似插槽,渲染切换页面的组件-->
      <router-view></router-view>

访问路径: http://localhost:8080/#/order, 其中的/#/order就是路由的请求路径了
在这里插入图片描述

2、声明式导航

使用路由标签,可以管理路由连接和高亮样式
to:路径
tag:渲染成什么标签
activeClass:高亮的样式

    <div>
      <ul>
        <router-link to="/user" tag="button" active-class="myActive">用户管理</router-link>
        <router-link to="/order" tag="button" active-class="myActive">订单管理</router-link>
      </ul>
      <!--类似插槽,渲染切换页面的组件-->
      <router-view></router-view>
    </div>
<style>
.myActive{
  color: #444;
  background-color: coral;
}
button:hover{
  cursor:pointer
}
</style>

浏览器显示:
在这里插入图片描述

3、重定向

路由中指定一个默认的地址,当访问路径没有匹配到组件的时候,会重定向到指定页面:

{
    path: '*',
    redirect: '/order'
  }
4、二级路由

如果在子组件中更新部分内容们可以使用二级路由,如Order.vue中 :

<template>
  <div>
    <h1>订单页面</h1>
    <ul>
      <router-link to="paid" tag="button" active-class="myActive">已支付</router-link>
      <router-link to="notpay" tag="button" active-class="myActive">未支付</router-link>
    </ul>
    <router-view></router-view>
  </div>
</template>
<script>
export default {}
</script>

路由配置(在一级路由的节点上加children节点):

{
    path: '/order',
    component: Order,
    children: [{
      path: 'paid',
      component: Paid
    }, {
      path: '/order/notpay',
      component: NotPay
    }, {
      path: '', // 默认重定向
      redirect: '/order/notpay'
    }]
  }

浏览器效果:
在这里插入图片描述

5、动态路由

如果路由中有动态的参数,可以进行如下配置:
发起请求的组件(Nopay.vue):

<template>
    <div>
        <h2>未支付订单</h2>
      <ul>
        <li v-for="num in dataList" :key="num" @click="changePage(num)">文章{{num}}</li>
      </ul>
    </div>
</template>
<script>
export default {
  data () {
    return {
      dataList: ['1', '2', '3']
    }
  },
  methods: {
    changePage: function (id) {
      console.log(id)
      this.$router.push(`/order/detail/${id}.html`) // 传url动态参数
    }
  }
}
</script>

路由配置:

    {
      path: '/order/detail/:myid.html', // myid是动态参数
      component: Detail
    },

详情页面组件

<template>
  <div>
    <h3>订单{{num}}的详情内容</h3>
  </div>
</template>
<script>
export default {
  mounted () {
    console.log(this.$route.params.myid) // 输出动态id
  },
  data () {
    return {
      num: this.$route.params.myid
    }
  }
}
</script>

浏览器显示:
在这里插入图片描述
在这里插入图片描述

6、命名路由

配置路由的时候设置一个name属性

    {
      name: 'od',
      path: '/order/detail/:myid.html', // myid是动态参数
      component: Detail
    }

跳转的时候

this.$router.push({ name: 'od', params: { myid: id } }) 
7、history模式

在定义路由的地方加上mode: ’ history’可以去掉路径中的#:

const router = new VueRouter({
  mode: 'history',
  routes
})

这种模式会真的向后端发送一个请求, 后端需要配置:如果URL 匹配不到任何资源,则返回同一个index.html

8、路由守卫

全局解析守卫,定义在路由js里
使用路由守卫,相当于一个过滤器:

// 模拟用户没有登录
const auth = {
  isLogin () {
    return false
  }
}
// to去哪个页面,form从哪个页面来,下一个页面
router.beforeEach((to, from, next) => {
  console.log(to.path)
  if (/\/order\/.*/.test(to.path)) { // 匹配正则路径,所有以order开头的页面
    console.log('拦截')
    if (auth.isLogin()) {
      next()
    } else {
      next('/login')
    }
  } else { // 不需要登录的页面直接放行
    next()
  }
})

组件内的守卫,定义在组件内

<script>
// 模拟用户没有登录
const auth = {
  isLogin () {
    return false
  }
}
export default {
  beforeRouteEnter (to, from, next) {
    // 在渲染该组件的对应路由被confirm前调用
    // 不能获取组件实例 `this`
    // 因为当守卫执行前,组件实例还没被创建
    if (auth.isLogin()) {
      next()
    } else {
      next('/login')
    }
  }
}
</script>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章