Vue入门笔记

1.前瞻

前端需要做的东西

逻辑

  • 判断
  • 循环

事件

  • 浏览器事件BOM windows document
  • 文档事件DOM
  • jQuery

视图

  • html
  • css (最难)

通信

  • ajax

其它需要掌握的

  • PS(美化)

2. Vue

Soc:

HTML+CSS +JS:视图:给用户看,刷新后台给的数据

网络通信:axious

页面跳转:vue-router

状态管理:vuex

Vue-UI

  • Ant-Desigm 阿里出品
  • ElementUI、ICE 饿了么出品
  • Bootstrap Twitter出品
  • AmazeUI 妹子UI,开源H5跨屏前端框架

MVVM模式

MVVP即(Model-View-ViewModel)来自于经典的MVC(Model-View-Controller)

所以,Vue.js就是一个MVVM模式的实现者,核心是实现了DOM的监听和数据绑定

3.第一个Vue程序

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!--    导入Vue.js-->
    <script crossorigin="anonymous" integrity="sha512-TpgbLHXaTCAZ7ULhjopb1PveTz5Jx6KEQUtMfXhV0m0EArh+6O8ybZjjDN1Yug6oagN6iFm6EoMjuYSiFr0qXQ==" src="https://lib.baomitu.com/vue/2.6.14/vue.common.dev.min.js"></script>
</head>
<body>
<!--view层  模板-->
<div id="app">
    {{message}}
</div>

<script>
    var vm = new Vue({
        el: '#app',      //el是element的简写
        //Model层:数据
        data: {
            message: 'hello,vue!'
        }
    })
</script>
</body>
</html>

{{}}是用来获取model层的data数据

4.基本语法

Vue的七大常用属性

  • el
    • 用来指示vue编辑器从什么时候开始解析vue语法,可以说是一个占位符
  • data
    • 用来组织从view中抽象出来的属性,可以说将视图的数据抽象出来放在data中
  • template
    • 用来设置模板,会替换页面元素,包括占位符
  • methods
    • 放置页面中的逻辑,比如js的方法都会放在methods中
  • render
    • 创建真正的virtu Dom
  • computed
    • 用于计算
  • watch
    • watch.function(new,old){}
    • 监听data中的数据变化
    • 两个参数,一个返回新值,一个返回旧值

4.1 v-bind

v-band的作用是绑定一个元素,在这里的作用是将这个元素的title特性和Vue实例的message属性保持一致。像v-band这样带有v-开头的都被称为指令。它们都会在渲染DOM上应用特殊响应行为。

v-band 可以用 : 代替(简写)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!--    导入Vue.js-->
    <script crossorigin="anonymous" integrity="sha512-TpgbLHXaTCAZ7ULhjopb1PveTz5Jx6KEQUtMfXhV0m0EArh+6O8ybZjjDN1Yug6oagN6iFm6EoMjuYSiFr0qXQ==" src="https://lib.baomitu.com/vue/2.6.14/vue.common.dev.min.js"></script>
</head>
<body>
<div id="app">
<!--    span的title属性会在鼠标停留的时候显示内容-->
    <span v-bind:title="message">
        鼠标放在上面悬停几秒看看
    </span>
</div>

<script>
    var vm = new Vue({
        el: '#app',      //el是element的简写
        //Model层:数据
        data: {
            message: 'hello,vue!'
        }
    })
</script>
</body>
</html>

4.2 判断-循环

1. v-if v-else判断

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <h1 v-if="type==='A'">A</h1>
    <h1 v-else-if="type==='B'">B</h1>
    <h1 v-else>C</h1>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
    var vm = new Vue({
        el: '#app',      //el是element的简写
        //Model层:数据
        data: {
            type : 'A'
        }
    })
</script>
</body>
</html>

2. v-for循环

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">
    <!--注意空格,否则会报错!index-->
  <li v-for="(item, index) in items">
    {{item.message}}--{{index}}
  </li>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
  var vm = new Vue({
    el: '#app',      //el是element的简写
    //Model层:数据
    data: {
      items : [
        {message:'jaijia'},
        {message: 'tingting'},
        {message: 'forever'}
      ]
    }
  })
</script>
</body>
</html>

4.3 v-on事件

v-on监听事件

v-on:可以用@代替(简写)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
<!--    <button v-on:click="sayHi"></button>-->
    <button @click="sayHi">click me</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
    var vm = new Vue({
        el: '#app',      //el是element的简写
        //Model层:数据
        data: {
            message:'jiajia'
        },
        methods:{
            //方法注意定义在Vue的methonds对象中
            //method和methods的区别,前者是一个方法,后者是一堆方法
            sayHi:function () {
                alert(this.message)
            }
        }    
    })
</script>
</body>
</html>

5. vue双向绑定

可以用 v-model 在表单<input><textarea>以及select元素上创建双向绑定。它会根据控件类型来字典选取正确的方法来更新元素。

注意:v-model会忽略所有表单元素的初始值,如value、checke、selected,而始终将 Vue的数据作为来源。所以要通过JavaScript在组件的data选项中声明初始值

5.1 单行文本

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--view层,模板-->
<div id="app">
    
输入的文本:<input type="text" v-model="message">{{message}}
    
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
    var vm = new Vue({
        el: '#app',      //el是element的简写
        //Model层:数据
        data: {
            message: ''
        }
    })
</script>
</body>
</html>

5.2 多行文本

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<!--view层,模板-->
<div id="app">
    
<textarea name="" id="" cols="30" rows="10" v-model="message">v-model="message"</textarea>
{{message}}
    
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
    var vm = new Vue({
        el: '#app',      //el是element的简写
        //Model层:数据
        data: {
            selected: ''
        }
    })
</script>
</body>
</html>

5.3 单选按钮

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<!--view层,模板-->
<div id="app">

<!--    选择性别:-->
<input type="radio" name="sex"  v-model="message" value="man">男
<input type="radio" name="sex"  v-model="message" value="woman">女
<p>{{message}}</p>

</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
    var vm = new Vue({
        el: '#app',      //el是element的简写
        //Model层:数据
        data: {
            message: ''
        }
    })
</script>
</body>
</html>

5.4 下拉框

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<!--view层,模板-->
<div id="app">

    下拉框:
    <select v-model="selected">
        <option value="" disabled>--请选择--</option>
        <option>A</option>
        <option>B</option>
        <option>C</option>
    </select>
    <saan>{{selected}}</saan>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
    var vm = new Vue({
        el: '#app',      //el是element的简写
        //Model层:数据
        data: {
            selected: ''
        }
    })
</script>
</body>
</html>

注意:v-model表达式的初始值未能匹配任何选项,<select>元素将被渲染为“未选中”状态。在iOS系统中,这会使用户无法选择第一个选项。因为在这种情况下,iOS不会触发change事件。因此,更推荐像上面这样提供一个值为空的禁用选项。

5.5 组件

注册组件并实例化

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">
    <jiajia></jiajia>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
    Vue.component('jiajia',{
        template: '<li>hello</li>'
    });
    var vm = new Vue({
        el: '#app',      //el是element的简写
        //Model层:数据
    });
</script>
</body>
</html>

了解即可,没有意义

使用 props 属性传递参数

注意:props里的值不能大写,即不能使用驼峰命名

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">
    <jiajia v-for="item in items" v-bind:jia="item"></jiajia>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
    Vue.component('jiajia',{
        props: ['jia'],
        template: '<li>{{jia}}</li>'
    });
    var vm = new Vue({
        el: '#app',      //el是element的简写
        //Model层:数据
        data:{
            items:['1','23','456']
        }
    });
</script>
</body>
</html>

!!以上代码着重理解

  • v-for="item in items" 遍历Vue中命名为items的数组赋值给item,并创建同等数量的组件。
  • v-bind:jia="item" 将遍历的item绑定到组件中props定义的名为jia的属性;=号左边jiaprops定义的属性名,右边的为item in items中遍历的item

6. Axios异步通信

6.1 简介

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

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

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

6.2 Vue的生命周期

在这里插入图片描述

6.3 浅试一下

先准备一个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/"
    }
  ]
}

然后上代码!

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        [v-cloak]{
            display: none;
        }
    </style>
</head>
<body>

<div id="jia" v-cloak>
    <div>{{info.name}}</div>
    <div>{{info.address.city}}</div>
    <a v-bind:href="info.url">jump!</a>
</div>
<!--导入vue-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script>
<!--导入axios-->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script type="text/javascript">
    var Learnanxios = new Vue({
        el: "#jia",
        //这里的data()是方法,data是属性
        data(){
            return{
                info:{
                    name:null,
                    address:{
                        street:null,
                        city:null,
                        country:null
                    }
                }
            }
        },
        mounted() {//钩子函数,链式编程,ES6新特性
            axios.get('a.json').then(funtion(response){
                                     return this.info = response.data
                                     })
            axios.get('a.json').then(response => (this.info = response.data))
        }
    })
</script>
</body>
</html>

image-20220315225821798

注意:

  1. 在这里使用了v-bind将a:href的属性值与Vue实例中的数据进行绑定
  2. 使用axios框架的get方法请求AJAX并自动将数据封装进了Vue实例的数据对象中
  3. 我们在data中的数据结构必须和Ajax响应回来的数据格式匹配

通过看评论区,发现了另外一种写法

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        [v-cloak]{
            display: none;
        }
    </style>
</head>
<body>

<div id="jia" v-cloak>
    <div>{{info.name}}</div>
    <div>{{info.address.city}}</div>
    <a v-bind:href="info.url">jump!</a>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script type="text/javascript">
    var Learnanxios = new Vue({
        el: "#jia",
        data: {//主要是这里的data的写法与上面不同,多对照区别。
            info: {}
        },
        mounted() {//钩子函数,链式编程,ES6新特性
          axios.get('a.json').then(response => (this.info = response.data))
            }
        })
</script>
</body>
</html>

7. 计算属性、内容分发、自定义事件

5.1 计算属性

定义

计算属性的重点突出在属性两个字上(属性是名词),首先它是个属性其次这个属性有计算的能力(计算是动词),这里的计算就是个函数:简单点说,它就是一个能够将计算结果缓存起来的属性(将行为转化成了静态的属性),仅此而已;可以想象为缓存

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--view层,模板-->
<div id="app">
    <p>MethodsTime:{{ttiimmee1()}}</p>
    <p>ComputeDtime:{{ttiimmee2}}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
    var vm = new Vue({
        el: '#app',      //el是element的简写
        //Model层:数据
        data: {
            message : 'hello,tingting'
        },
        methods:{
            ttiimmee1: function () {
                return Date.now();
                //返回一个时间戳
            }
        },
        computed: {
            ttiimmee2: function () {
                this.message;
                return Date.now();
                //返回一个时间戳
            }
        }
    })
</script>
</body>
</html>

image-20220316160422280

image-20220316160323186

注意:methods和conputed不能重名,重名之后,只会调用methods里的方法。

好好理解methods和computed的区别:

  1. 首先,methods里定义的是一堆方法,方法的调用要加括号(),而computed名为计算属性,所以是一个属性,调用属性不用加括号直接用属性名调用就好。
  2. 在调用方法的时候,每次调用都需要从新计算,这样便会产生大量的系统开销。但是如果这个值是不经常变化的,就没必要每次都进行重新计算,就可以将它缓存起来,计算属性就可以做到这一点,以节省系统开销。缓存只有在发生增删改查的变化时会失效然后重新进行计算。

5.2 内容分发(插槽)

1.概念

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

2.浅试一下

  • 需求:需要把下面的内容,让标题和内容通过插槽插入内容
<p>标题</p>
<ul>
    <li>abcd</li>
    <li>abcd</li>
    <li>abcd</li>
</ul>
  • 定义一个代办事情的组件
 Vue.component('chacao',{
        template:'<div>\
                <div>代办事项</div>\
                <ul>\
                <li>笨蛋</li>\
                </ul>\
            </div>'
    });
  • 将上面的代码留出一个插槽,即slot
 Vue.component('todo',{
        template:'<div>\
                  	<slot"></slot>\
                  <ul>\
                  	<slot"></slot>\
                  </ul>\
                  </div>'
    });
  • 定义一个名为cc-title的待办标题组件 和 cc-item的待办内容组件
Vue.component('cc-title',{
        props:['fake'],
        template:'<div>{{fake}}</div>'
    });
   
//这里的index,就是数组的下标,使用for循环遍历的时候,可以循环出来!
    Vue.component("cc-items",{
        props:["item","index"],
        template:"<li>{{index+1}},{{item}}</li>"
    });
  • slot通过name和组件绑定
 Vue.component('chacao',{
        template:'<div>\
                	<slot name="c-title"></slot>\
                <ul>\
                    <slot name="c-items"></slot>\
                </ul>\
            </div>'
    });
  • 实例化Vue并初始化数据
 var vm = new Vue({
        el:"#vue",
        data:{
            todoItems:['test1','test2','test3']
        }
    });
  • 将数据通过插槽插入预留出来的位置
<chacao>
        <cc-title slot="c-title" :fake="titles"></cc-title>
        <cc-item slot="c-items" v-for="item in itemss" :jia="item" ></cc-item>
</chacao>
  • 完整代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">
  <chacao>
    <cc-title  slot="c-title" :fake="title"></cc-title>
    <cc-item slot="c-item" v-for="item in itemss" :jia="item" ></cc-item>
  </chacao>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
  Vue.component('chacao',{
    template:
            // '<div>' +
            // '<slot name="c-title"></slot>' +
            // '<ul>' +
            // '<slot name="c-item"></slot>' +
            // '</ul>' +
            // '</div>'
    //上下为两种不同的写法
            '<div>\
             <slot name="c-title"></slot>\
             <ul>\
             <slot name="c-item"></slot>\
             </ul>\
             </div>'
  });
  Vue.component('cc-title',{
    props: ['fake'],
    template: '<div>{{fake}}</div>'
  });
  Vue.component('cc-item',{
    props:['jia'],
    template:'<li>{{jia}}</li>'
  });
  var vm = new Vue({
    el: '#app',      //el是element的简写
    //Model层:数据
    data:{
        title:'笨蛋婷婷',
      titles:'婷婷笨',
      itemss:['婷','婷','笨蛋']
    }
  });
</script>
</body>
</html>

运行结果:

image-20220316213225395

5.3 自定义事件

怎么理解自定义事件呢,引用网友的一句话。

子组件给父组件传参数用的是props:["参数一","参数二"]

父组件给子组件传方法用的是this.$emit("自定义事件","参数")

完整代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">
    <chacao>
        <cc-title  slot="c-title" :fake="titles"></cc-title>
        <cc-item slot="c-item"
                 v-for="(item,index) in itemss"
                 :jia="item"
                 :wei="index"
                 @myremove="vueremove(index)" ></cc-item>
    </chacao>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
    Vue.component('chacao',{
        template:
            `<div>
             <slot name="c-title"></slot>
             <ul>
             <slot name="c-item"></slot>
             </ul>
             </div>`
    });
    Vue.component('cc-title',{
        props: ['fake'],
        template: '<div>{{fake}}</div>'
    });
    Vue.component('cc-item',{
        props:['jia','wei'],//参数传递
        template:'<li>{{wei}}----{{jia}}&nbsp;&nbsp;<button @click="componentremove()">删除</button></li>',
        methods:{
            componentremove:function (nn) {
                // 这里的myremove就是自定义事件
                this.$emit('myremove',nn)
            }
        }
    });
    var vm = new Vue({
        el: '#app',      //el是element的简写
        //Model层:数据
        data:{
            titles:'婷是笨蛋',
            itemss:['婷','是','笨蛋']
        },
        methods: {
            vueremove: function (abc) {
                console.log('删除了'+this.itemss[abc]);
                this.itemss.splice(abc,1);
            }
        }
    });
</script>
</body>
</html>

8.第一个vue-cli项目

8.1 简介

vue-cli官方提供的一个脚手架,用于快速生成一个vue的项目模板预先定义好的目录结构及基础代码,就好比咱们在创建Maven项目时可以选择创建一个骨架项目,这个估计项目就是脚手架,我们的开发更加的快速

8.2 环境配置

1.node.js

下载地址: http://nodejs.cn/download/ 安装的时候一直下一步直到结束

确认是否安装成功:

  • 在cmd中运行node -v命令,查看是否能够输出版本号
  • 在cmd中运行npm -v命令,查看是否能够输出版本号

image-20220318170350938

2.安装node.js淘宝镜像加速器(cnpm)

# -g 就是全局安装
npm install cnpm -g

# 或使用如下语句解决npm速度慢的问题,但是每次install都需要(妈发)
npm install --registry=https://registry.npm.taobao.org

3.安装vue-cli

//3.0之后的版本Vue CLI的包名称由vue-cli改成了@vue/cli
npm install -g @vue/cli

8.3 第一个vue-cli程序

  1. 找到一个项目路径(空文件夹)
  2. 创建一个基于webpack模板的vue应用程序()
//这是3.0之后版本的语法
vue create 项目名;//项目名不建议存在大写,中间用-隔开
  1. 初始化并运行
1.cd 项目名

2.npm run serve  运行项目
  1. 访问根据提示localhost:8080即可

也可以通过vue ui图形化界面来创建项目

vue ui

image-20220318171715309

9. webpack的使用

9.1 安装webpack

npm install webpack -g
npm install webpack-cli -g

测试安装成功

webpack -v
webpack-cli -v

image-20220318172116361

配置:

  • entry:入口文件, 指定Web Pack用哪个文件作为项目的入口
  • output:输出, 指定WebPack把处理完成的文件放置到指定路径
  • module:模块, 用于处理各种类型的文件
  • plugins:插件, 如:热更新、代码重用等
  • resolve:设置路径指向
  • watch:监听, 用于设置文件改动后直接打包
module.exports = {
	entry:"",
	output:{
		path:"",
		filename:""
	},
	module:{
		loaders:[
			{test:/\.js$/,;\loade:""}
		]
	},
	plugins:{},
	resolve:{},
	watch:true
}

打包:直接运行webpack命令

9.2 使用webpack

  1. 创建项目
  2. 创建一个名为modules的目录,用于放置JS模块等资源文件
  3. 在modules下创建模块文件hello.js
//暴露一个方法   sayHi
exports.sayi=function () {
    document.write('<h1>嘉嘉学ES6</h1>')
}
  1. 在modules下创建一个名为main.js的入口文件main.js,用于打包时设置entry属性
//require 导入一个模块,就可以调用这个模块中的方法了
var hello= require('./hello');
hello.sayi();
  1. 在项目目录下创建webpack.config.js配置文件,使用webpack命令打包
module.exports={
    entry:'./modules/main.js',
    output:{
        filename:'./js/bundle.js'
    },
    mode:'development'
}

打包的注意事项:

  • 新版本要在属性加上mode:'development'
  • 注意设使用管理员模式运行
  • 遇到别的错误复制去CSDN解决

image-20220318173047163

  1. 在项目目录下创建HTML页面,如index.html,导入webpack打包后的JS文件
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<!--前端的模块化开发-->
<script src="dist/js/bundle.js"></script>
</body>
</html>
  1. 直接打开index.html

image-20220318173226296说明:

# 参数--watch 用于监听变化,如果要打包的东西有变化,就重新打包
webpack --watch

10. Vue vue-router路由

10.1 安装vue-router

//正常安装
npm install vue-router --save-dev
//如果运行启动报错,有可能是因为版本太高的问题,则用下面的版本
cnpm install vue-router@3.1.3 --save-dev

安装路由:

import Vue from 'vue'
//导入路由
import VueRouter from 'vue-router'
//安装路由
Vue.use(VueRouter);

10.2 测试路由

  • 删除第一个vue-cli项目中的没用的东西
  • components 目录下存放我们自己编写的组件
  • 定义几个自己的组件 Content.vue 、Main.vue、MyStyle.vue

Content.vue

<template>
	<div>
		<h1>内容页</h1>
	</div>
</template>

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

Main.vue

<template>
<div>
    <h1>首页</h1>
    </div>
</template>

<script>
    export default {
        //可以忽略下一句的语法检查(弹出错误)
        // eslint-disable-next-line
        name:"Main"
    }
</script>

MyStyle.vue

<template>
  <h1>我自己的页面</h1>
</template>

<script>
export default {
    // eslint-disable-next-line
  name: "MyStyle"
}
</script>

注意:组件名有命名规范,应该由多个单词的驼峰命名组成或者-连接,否则会报错,如果一定要使用单个单词,要在上一行加一句 // eslint-disable-next-line

  • 安装路由,在src目录下,新建一个文件夹:router,专门存放路由,配置路由index.js
//注意,这里的index只是一个命名规范,不是代表首页,是代表router的主配置,可以在main.js导入时自动扫描

import Vue from'vue'
//导入路由插件
import Router from 'vue-router'
//导入上面定义的组件
import Content from '../components/Content'
import Main from '../components/Main'
import MyStyle from "@/components/MyStyle";
//安装路由
Vue.use(Router) ;
//配置路由
export default new Router({
    routes:[
        {
            //路由路径
            path:'/content',
            //路由名称
            name:'content',
            //跳转到组件
            component:Content
        },{
            //路由路径
            path:'/main',
            //路由名称
            name:'main',
            //跳转到组件
            component:Main
        },
        {
            //路由路径
            path:'/mystyle',
            //路由名称
            name:'mystyle',
            //跳转到组件
            component:MyStyle
        }
    ]
});
  • main.js中配置路由
import Vue from 'vue'
import App from './App.vue'
import router from './router'//自动扫描里面的路由配置

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
  router,
}).$mount('#app')
  • App.vue中使用路由
<template>
  <div id="app">
    <!--
          router-link:默认会被渲染成一个<a>标签,to属性为指定链接
          router-view:用于渲染路由匹配到的组件
        -->
    <h1>嘉嘉学vue-router路由</h1>
    <router-link to="/main">这是首页</router-link>
    &nbsp;<!--这是空格符-->
    <router-link to="/content">这是内容</router-link>
    &nbsp;
    <router-link to="/mystyle">这是自己的页面</router-link>
      <!--显示视图-->
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: 'App',
}
</script>
  • 运行npm run serve,然后浏览器访问localhost:8080

image-20220319151751577

11. 小试一下吧~

11.1 创建工程

  1. 创建一个名为hello-vue的工程
//建议用图形界面来创建
vue ui
  1. 安装依赖, vue-router、element-ui、sass-loader和node-sass四个插件
#进入工程目录
cd hello-vue
#安装vue-routern 
npm install vue-router --save-dev
#安装element-ui
npm i element-ui -S
#安装依赖
npm install
# 安装SASS加载器
cnpm install sass-loader node-sass --save-dev
#启功测试
npm run serve
  • npm命令说明
  • npm install moduleName:安装模块到项目目录下

  • npm install -g moduleName:-g的意思是将模块安装到全局,具体安装到磁盘哪个位置要看npm

    config prefix的位置

  • npm install -save moduleName:–save的意思是将模块安装到项目目录下, 并在package文件的dependencies节点写入依赖,-S为该命令的缩写

  • npm install -save-dev moduleName:–save-dev的意思是将模块安装到项目目录下,并在package文件的devDependencies节点写入依赖,-D为该命令的缩写

  • 还可以用图形界面来完成

image-20220319234349282

注意:这里依赖插件的区别

  • 插件在命令行中通过 vue add 安装

    如: vue add eslint

    这个命令将 @vue/eslint 解析为完整的包名 @vue/cli-plugin-eslint,然后从 npm 安装它,调用它的生成器。

    # 这个和之前的用法等价
    vue add cli-plugin-eslint
    
  • 依赖在命令行中通过 npm install 安装

    如: npm install axios

每个 CLI 插件都会包含一个生成器 (用来创建文件的) 和一个运行时插件 (用来调整 webpack 核心配置和注入命令的) 。

提示:

vue add 的设计意图是为了安装和调用 Vue CLI 插件。这不意味着替换掉普通的 npm 包。对于这些普通的 npm 包,你仍然需要选用包管理器。

  1. idea打开创建好的项目

11.2 创建登录界面

  1. 先删除没用的文件和没用的代码
  2. 然后像下面这样建立项目结构

image-20220320000108691

  1. 在views目录下创建首页视图Main.vue组件
<template>
<div>首页</div>
</template>
<script>
    export default {
        name:"Main"
    }
</script>
<style scoped>
</style>
  1. 在views目录下创建登录页面视图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="dialogVisiable" 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:"密码不可为空",tigger:"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>
  1. 在router目录下创建一个名为index.js的vue-router路由配置文件
//导入vue
import Vue from 'vue';
import VueRouter from 'vue-router';
//导入组件
import Main from "../views/Main";
import Login from "../views/Login";
//使用
Vue.use(VueRouter);
//导出
export default new VueRouter({
  routes: [
    {
      //登录页
      path: '/main',
      component: Main
    },
    //首页
    {
      path: '/login',
      component: Login
    },
  ]
})
  1. 编写 APP.vue (这是入口界面)
<template>
  <div id="app">
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name:'App'
}
</script>
  1. main.js中配置路由 (这是入口文件,加载组件,初始化等)
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';

Vue.config.productionTip = false

Vue.use(ElementUI)

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

  1. 测试npm run serve

说明: 如果出现错误: 可能是因为sass-loader的版本过高导致的编译错误 ,可以去package.json文件中把sass-loder的版本降低,也有可能是node-sass版本过高,看报错内容修改相应的版本

11.3 路由嵌套

定义:嵌套路由又称子路由,在实际应用中,通常由多层嵌套的组件组合而成

  1. 创建用户信息组件,在 views/user 目录下创建一个名为 Profile.vue 的视图组件
<template>
  <h1>个人信息</h1>
</template>
<script>
  export default {
    name: "UserProfile"
  }
</script>
<style scoped>
</style>
  • 在用户列表组件在 views/user 目录下创建一个名为 List.vue 的视图组件
<template>
  <h1>用户列表</h1>
</template>
<script>
  export default {
    name: "UserList"
  }
</script>
<style scoped>
</style>
  • 修改首页视图,我们修改 Main.vue 视图组件,此处使用了 ElementUI 布局容器组件
<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>
            <el-menu-item-group>
              <el-menu-item index="2-1">分类管理</el-menu-item>
              <el-menu-item index="2-2">内容列表</el-menu-item>
            </el-menu-item-group>
          </el-submenu>

          <el-submenu index="3">
            <template slot="title"><i class="el-icon-caret-right"></i>乱七八糟管理</template>
            <el-menu-item-group>
              <el-menu-item index="3-1">乱七</el-menu-item>
              <el-menu-item index="3-2">八糟</el-menu-item>
              <el-menu-item index="3-3">乱七八糟</el-menu-item>
            </el-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 {
  // eslint-disable-next-line
  name: "Main"
  //第七行的语句可以忽略下一行的错误)
}
</script>

<style scoped lang="scss">
.el-header {
  background-color: #5fbfff;
  color: #333;
  line-height: 60px;
}
.el-aside {
  color: #333;
}
</style>
  • 添加了组件,去router修改配置文件
import Vue from 'vue'
import VueRouter from 'vue-router'
import Main from "@/views/Main";
import Login from "@/views/Login";
import UserList from "@/views/uesr/List";
import UserProFile from "@/views/uesr/ProFile";
//安装路由
Vue.use(VueRouter)
//导出
const routes = [
  {//登录页
    path: '/login',
    name: 'login',
    component: Login
  },
  {//首页
    path: '/main',
    name: 'main',
    component: Main,
    //路由嵌套
    children:[
      {path:'/user/list',component:UserList},
      {path:'/user/profile',component:UserProFile},
    ]
  }
]

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

export default router
  • 运行npm run serve测试

image-20220320002745008

11.4 参数传递和重定向

11.4.1 参数传递

方法一:

  1. 修改路由配置, 主要是router下的index.js中的 path 属性中增加了 :id 这样的占位符
{
	path: '/user/profile/:id', 
	name:'UserProfile', 
	component: UserProfile
}
  1. 视图层传递参数
<!--name是组件的名字 params是传的参数 如果要传参数的话就需要用v:bind:来绑定-->
<router-link :to="{name:'UserProfile',params:{id:1}}">个人信息</router-link>

说明: 此时我们在Main.vue中的route-link位置处 to 改为了 :to,是为了将这一属性当成对象使用,注意 router-link 中的 name 属性名称 一定要和 路由中的 name 属性名称 匹配,因为这样 Vue 才能找到对应的路由路径

  1. 接收参数
<template>
  <!--  所有的元素必须在根节点下-->
  <div>
    <h1>个人信息</h1>
    {{$route.params.id}}
  </div>
</template>

说明:所有的元素必须在根节点下面,否则会报错

  1. 测试

image-20220320184349625

(方法一二效果完全相同,建议使用方法二)

方法二:

使用props 减少耦合

  1. 修改路由配置 , 主要在router下的index.js中的路由属性中增加了 props: true 属性
{
	path: '/user/profile/:id', 
	name:'UserProfile', 
	component: UserProfile, 
	props: true  //允许使用props传递参数
}
  1. 传递参数和之前一样

  2. 在Profile.vue接收参数为目标组件增加 props 属性

<template>
  <div>
    个人信息
    {{ id }}
  </div>
</template>
<script>
    export default {
      props: ['id'],
      name: "UserProfile"
    }
</script>
<style scoped>
</style>
  1. 测试

    image-20220320184349625

11.4.2 重定向

Vue 中的重定向是作用在路径不同但组件相同的情况

  1. 在router/index.js配置重定向路径
{
  path: '/main',
  name: 'Main',
  component: Main
},
{
    //重定向
    path:'/gohome',
    name:'gohome',
    redirect:'/main'
  }
  1. 视图增加
//以下格式是element-ui的
<el-menu-item index="1-3">
    <!--插入的地方-->
    <router-link to="/goHome">返回首页</router-link>
</el-menu-item>

11.4.3 小demo(显示当前登录用户)

  1. 首先在login页面修改methods方法
methods:{
  onSubmit(formName){
    //为表单绑定验证功能
    this.$refs[formName].validate((valid)=>{
      if(valid){
        //使用vue-router路由到指定界面,该方式称为编程式导航
        this.$router.push('/main/'+this.form.username);//先向router多传一个参数username
      }else{
        this.dialogVisible=true;
        return false;
      }
    });
  }
}

2.然后在index.js里接收参数

{//首页
  props: true,
  path: '/main/:name',//获取router发送过来的参数
  name: 'main',
  component: Main
}

3.然后在视图层获取显示接收的参数

eport default {
  props:['name'],
  // eslint-disable-next-line
  name: "Main"
}


// 然后在需要显示的地方加上下列代码

11.5 路由模式、404和路由钩子

11.5.1 路由模式

路由模式有两种

可以在vue ui图形界面新建项目的时候就设定

也可以在路由的配置index.js中修改

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

11.5.2 404页面

  1. 在views文件夹下创建一个NotFound.vue视图
<template>
<div>
  <h1>404,不见啦!</h1>
</div>
</template>

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

<style scoped>

</style>
  1. 修改路由配置index.js
//先导入组件
import NotFound from '../views/NotFound'
{
   path: '*',
   component: NotFound
}
  1. 测试

image-20220320185313667

11.5.3 路由钩子

除了之前的钩子函数还存在两个钩子函数

beforeRouteEnter:在进入路由前执行
beforeRouteLeave:在离开路由前执行

  • 在 Profile.vue 使用
<script>
    export default {
        name: "UserProfile",
        beforeRouteEnter: (to, from, next) => {
            console.log("准备进入个人信息页");
            next();
        },
        beforeRouteLeave: (to, from, next) => {
            console.log("准备离开个人信息页");
            next();
        }
    }
</script>

参数说明:

to:路由将要跳转的路径信息

from:路径跳转前的路径信息
next:路由的控制参数
next() 跳入下一个页面
next(’/path’) 改变路由的跳转方向,使其跳到另一个路由
next(false) 返回原来的页面
next((vm)=>{}) 仅在 beforeRouteEnter 中可用,vm 是组件实例

  • 在钩子函数中进行异步请求

    • 安装Axios
    npm install --save axios vue-axios
    
    • main.js引用 Axios
    import axios from 'axios'
    import VueAxios from 'vue-axios'
    
    Vue.use(VueAxios, axios)
    
    • 准备数据
    {
      "name": "cv战士",
      "url": "https://blog.csdn.net/qq_45408390?spm=1001.2101.3001.5343",
      "page": 1,
      "isNonProfit": true,
      "address": {
        "street": "含光门",
        "city": "陕西西安",
        "country": "中国"
      },
      "links": [
        {
          "name": "bilibili",
          "url": "https://bilibili.com"
        },
        {
          "name": "cv战士",
          "url": "https://blog.csdn.net/qq_45408390?spm=1001.2101.3001.5343"
        },
        {
          "name": "百度",
          "url": "https://www.baidu.com/"
        }
      ]
    }
    

    说明: 只有我们的 public 目录下的文件是可以被访问到的,所以我们就把静态文件放入该目录下

    • 在 beforeRouteEnter 中进行异步请求
    <script>
    export default {
      props:['id'],
      //这里的名字可以和文件名不一样
      name: "UserProFile",
      beforeRouteEnter:(to, from, next) => {
        console.log("准备进入个人信息页")
        next(vm => {
          //进入钩子路由之前执行getData方法
          vm.getDate()
        });
      },
      beforeRouteLeave:(to, from, next) => {
        console.log("准备离开个人信息页"),
            next();
      },
      //axios
      methods:{
        getDate:function () {
          this.axios({
            method:'get',
         	url:'/a.json'
          }).then(response=> {
            console.log(response)
          })
        }
      }
    }
    
    • 测试

image-20220321011653603

posted @ 2022-04-02 23:48  闫池  阅读(121)  评论(0)    收藏  举报