VUE.JS

VUE

Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。 Vue中文网址为:Vue.js - 渐进式 JavaScript 框架 | Vue.js

1. VUE概述

1.1 MVVM模式

MVVM(Model-View-ViewModel)是一种软件架构设计模式,它是一种简化用户界面的事件驱动编程方式。

Model: 数据模型,泛指后端各种业务逻辑处理和数据操控,围绕数据库系统展开的 JavaScript对象。 ​ View: 视图层,主要由HTML和CSS来构成的用户界面,为了更方便地展现ViewModel或者Model层的数据。 ViewModel:连接视图和数据的中间件, 由前端开发人员组织生成和维护的视图数据层。前端开发者从后端获取得到Model数据进行转换出来,二次封装成符合View层使用预期的视图数据模型。视图状态和行为都封装在这里。这样的封装使得ViewModel可以完整地去描述View层。 Vue.js就是MVVM中的ViewModel层的实现者。

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

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

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

到此,我们就明白了,Vue.js就是一个MVVM的实现者,它的核心就是实现了DOM监听与数据绑定。

1.2 Vue的特点

  • 轻量级,体积小。Vue.js压缩后只有30多kb(Angular压缩后56kb以上,React压缩后44kb以上)

  • 更适合移动端,比如移动端的Touch事件

  • 易上手,文档齐全

  • 吸取了Angular(模块化)和React(虚拟DOM)的长处,并拥有自己独特的功能,如计算属性

  • 开源,社区活跃度高

1.3 Vue的核心

  • 数据驱动

    Vue.js 是一个提供了 MVVM 风格的双向数据绑定的 Javascript 库,专注于View 层。它让开发者省去了操作DOM的过程,只需要改变数据。Vue会通过Dircetives指令,对DOM做一层封装,当数据发生改变会通知指令去修改对应的DOM,数据驱动DOM变化,DOM是数据的一种自然映射。

    Vue还会对操作进行监听,当视图发生改变时,vue监听到这些变化,从而改变数据,这样就形成了数据的双向绑定。

    Vue是一种MVVM框架。而DOM是数据的一个种自然映射。传统的模式是通过Ajax请求从model请求数据,然后手动的触发DOM传入数据修改页面。Vue中,Directives对view进行了封装,当model里的数据发生变化是,Vue就会通过Directives指令去修改DOM。同时也通过DOM Listener实现对视图view的监听,当DOM改变时,就会被监听到,实现model的改变,实现数据的双向绑定

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

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

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

  • 组件化

    页面上每个独立的可交互区域都视为一个组件。

    每个组件对应一个工程目录,组件所属的各种资源在这个目录下就近维护。

    页面不过是组件的容器,组件可以嵌套自由组合(复用)形成完整的页面。

2. 第一个Vue应用程序

2.1 下载地址

<!-- 开发环境版本,包含了有帮助的命令行警告 初学者使用-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>

或者:

<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>

2.2 建立项目

编写html页面代码如下

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>第一个Vue</title>
        <!-- 开发环境版本,包含了有帮助的命令行警告 初学者使用-->
        <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    </head>
    <body>
        <div id="app">  <!-- View层 -->
            {{msg}}     <!-- 在下面Vue代码中定义了msg变量 -->
        </div>
        
        <script>        
            //声明式渲染     
            var first = new Vue({               //View Model层
                el: "#app", //挂载#app页面元素    //View Model层中的 View
                data:{                          //View Model层中的model
                    msg:"hello first vue"   //定义挂载元素中可以使用的变量
                }
            })
            
        </script>
    </body>
</html>

运行效果: ​

2.3 Vue实例生命周期

下图展示了实例的生命周期。你不需要立马弄明白所有的东西,不过随着你的不断学习和使用,它的参考价值会越来越高。

创建期间的生命周期函数:

  • beforeCreate:实例刚在内存中被创建之前,还没有初始化好 data 和 methods 属性。

  • created:实例已经在内存中创建OK,此时 data 和 methods 已经创建OK,此时还没有开始编译模板。

  • beforeMount:此时已经完成了模板的编译,但是还没有渲染到页面中。

  • mounted:此时,已经将编译好的模板渲染到到了页面并在的容器中显示给用户。

运行期间的生命周期函数:

  • beforeUpdate:状态更新之前执行此函数, 此时 data 中的状态值是最新的,但是界面上显示的数据还是旧的,因为此时还没有开始重新渲染DOM节点。

  • updated:实例更新完毕之后调用此函数,此时 data 中的状态值和界面上显示的数据,都已经完成了更新,界面已经被重新渲染好了!

销毁期间的生命周期函数:

  • beforeDestroy:实例销毁之前调用。在这一步,实例仍然完全可用。

  • destroyed:Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。

注意:这里有一些钩子,其实也是函数,可以这样理解:生命周期钩子 = 生命周期函数 = 生命周期事件。

3. 条件渲染

  • v-if 指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回 truthy 值的时候被渲染。

  • v-else 元素必须紧跟在带 v-if 或者 v-else-if 的元素的后面,否则它将不会被识别。

  • v-else-if,顾名思义,充当 v-if 的 “else-if 块”,可以连续使用 。

<!DOCTYPE html>
<html>
    <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">
            <span v-if="isShow">可以看见Vue的v-if</span>
            <span v-else>--什么也没有--</span>
        </div>
        
        <script>
            //声明式渲染
            var first = new Vue({
                el: "#app",         //挂载#app页面元素
                data:{
                    isShow: true    //定义挂载元素中可以使用的变量
                }
            })
            
        </script>
        
        <div id="appifelse">
            <div v-if="type === 'A'">
              A
            </div>
            <div v-else-if="type === 'B'">
              B
            </div>
            <div v-else-if="type === 'C'">
              C
            </div>
            <div v-else>
              Not A/B/C
            </div>
        </div>
        
        <script>
            //声明式渲染
            var first = new Vue({
                el: "#appifelse",       //挂载#app页面元素
                data:{
                    type: "C"           //定义挂载元素中可以使用的变量
                }
            })
        </script>
        
    </body>
</html>

运行结果如下: ​

  • template 元素上使用 v-if 条件渲染分组

    因为 v-if 是一个指令,所以必须将它添加到一个元素上。但是如果想切换多个元素呢?此时可以把一个元素当做不可见的包裹元素,并在上面使用 v-if。最终的渲染结果将不包含 template 元素。

    <div id="apptemp">
        <template v-if="ok">
            <h1>Title</h1>
            <p>Paragraph 1</p>
            <p>Paragraph 2</p>
        </template>
        <template v-else>
            <h1>noTitle</h1>
            <p>Paragraph 3</p>
            <p>Paragraph 4</p>
        </template>
    </div>
    ​
    <script>
        //声明式渲染
        var first = new Vue({
            el: "#apptemp",     //挂载#apptemp页面元素
            data:{
                ok: false           //定义挂载元素中可以使用的变量
            }
        })
    ​
    </script>

4. 列表渲染

4.1 v-for使用数组

可以用 v-for 指令基于一个数组来渲染一个列表。v-for 指令需要使用 item in items 形式的特殊语法,其中 items 是源数据数组,而 item 则是被迭代的数组元素的别名

<div id="app">
    <ul>
        <li v-for="item in items" :key="item.message">
            {{ item.message }}
        </li>
    </ul>
</div>
​
<script>
    //声明式渲染
    var first = new Vue({
        el: "#app",         //挂载#app页面元素
        data:{
            items: [
                { message: 'Foo' },
                { message: 'Bar' }
            ]
        }
    })
​
</script>

运行如下: ​

v-for 块中,我们可以访问所有父作用域的 property。v-for 还支持一个可选的第二个参数,即当前项的索引。。v-for 指令需要使用 (item,index) in items 形式的特殊语法,其中 items 是源数据数组,而 item 则是被迭代的数组元素的别名

<div id="appIndex">
    <ul>
        <li v-for="(item,index) in items" :key="item.message">
            {{ parentMessage }} - {{ index }} - {{ item.message }}
        </li>
    </ul>
</div>
​
<script>
    //声明式渲染
    var first = new Vue({
        el: "#appIndex",            //挂载#app页面元素
        data:{
            parentMessage: 'Parent',
            items: [
                { message: 'Foo' },
                { message: 'Bar' }
            ]
        }
    })
​
</script>   

运行结果: ​

4.2 v-for使用对象

可以使用 v-for 来遍历一个对象的 property 。。v-for 指令需要使用 value in objet 形式的特殊语法,其中 object 是源数据中的对象,而 value 则是遍历对象中属性的别名

<div id="appObject">
    <ul>
        <li v-for="value in object">
            {{ value }}
        </li>
    </ul>
</div>
​
<script>
    //声明式渲染
    var first = new Vue({
        el: "#appObject",           //挂载#app页面元素
        data: {
            object: {
                title: 'How to do lists in Vue',
                author: 'Jane Doe',
                publishedAt: '2016-04-10'
            }
        }
    })
​
</script>

运行结果如下: ​

当然,如果对象在数组里面,v-for 指令需要使用 todo in todos 形式的特殊语法,其中 todos 是源数据数组,而 todo 则是被迭代的数组元素的别名

<div id="app-4">
    <ol>
        <li v-for="todo in todos">
            {{ todo.text }}
        </li>
    </ol>
</div>
<script>
    var app4 = new Vue({
        el: '#app-4',
        data: {
            todos: [
                { text: '学习 JavaScript' },
                { text: '学习 Vue' },
                { text: '整个牛项目' }
            ]
        }
    })
</script>

5. 事件处理

可以用 v-on 指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码。v-on 还可以接收一个需要调用的方法名称 ,该方法在绑定的 Vue 实例中定义。比如我们用 v-on 指令添加一个事件监听器 :

<div id="appevent">
    <button v-on:click="testClick">点击事件测试</button> <!-- v-on:click="方法名"  -->
</div>											<!-- 该方法名在Vue实例中methods定义 -->
<script>
    var app4 = new Vue({
        el: '#appevent',
        methods:{								/* Vue实例中定义的方法 */
            testClick:function(){				
                alert("点击事件");	
            }
        }
    })
</script>

在看一个实现内容反转的例子:

<div id="appReverse">
    <p>{{message}}</p>
    <button v-on:click="reverseMessage">反转文本</button>
</div>
<script>
    var app5 = new Vue({
        el: '#appReverse',
        data: {
            message: 'Hello Vue.js!'
        },
        methods: {
            reverseMessage: function () {
                this.message = this.message.split('').reverse().join('')
            }
        }
    })
</script>

注意在 reverseMessage 方法中,我们更新了应用的状态,但没有触碰 DOM——所有的 DOM 操作都由 Vue 来处理,你编写的代码只需要关注逻辑层面即可。

6. Axios异步通信

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

  • 从浏览器中创建 XMLHttpRequests

  • node.js 创建http请求

  • 支持 Promise API

  • 拦截请求和响应

  • 转换请求数据和响应数据

  • 取消请求

  • 自动转换 JSON 数据

  • 客户端支持防御

Github:GitHub - axios/axios: Promise based HTTP client for the browser and node.js

6.1 第一个Axios应用

6.1.1 创建JSON测试数据

由于接口大部分都是采用JSON格式,可以先在项目中创建一个data.json文件模拟JSON数据,内容如下:

{
    "message": "ok",
    "num": "JT0004301991791",
    "ischeck": "0",
    "com": "jtexpress",
    "status": "200",
    "data": [
        {
            "time": "2021-12-14 21:08:34",
            "context": "【上海市】快件离开【上海浦西转运中心】已发往【杭州转运中心】",
            "ftime": "2021-12-14 21:08:34",
            "areaCode": "CN310118000000",
            "areaName": "上海,上海,青浦区",
            "status": "干线",
            "location": "上海 上海市 青浦区",
            "areaCenter": "121.124178,31.150681",
            "areaPinYin": "qing pu qu",
            "statusCode": "1002"
        },
        {
            "time": "2021-12-14 20:54:22",
            "context": "【上海市】 快件到达【上海浦西转运中心】",
            "ftime": "2021-12-14 20:54:22",
            "areaCode": "CN310118000000",
            "areaName": "上海,上海,青浦区",
            "status": "干线",
            "location": "上海 上海市 青浦区",
            "areaCenter": "121.124178,31.150681",
            "areaPinYin": "qing pu qu",
            "statusCode": "1002"
        },
        {
            "time": "2021-12-14 17:25:58",
            "context": "【上海市】快件离开【上海杨浦黄兴路网点】已发往【上海浦西转运中心】",
            "ftime": "2021-12-14 17:25:58",
            "areaCode": "CN310110000000",
            "areaName": "上海,上海,杨浦区",
            "status": "干线",
            "location": "上海 上海市 杨浦区",
            "areaCenter": "121.526077,31.259541",
            "areaPinYin": "yang pu qu",
            "statusCode": "1002"
        },
        {
            "time": "2021-12-14 09:03:58",
            "context": "【上海市】【上海杨浦黄兴路网点】已取件。",
            "ftime": "2021-12-14 09:03:58",
            "areaCode": "CN310110000000",
            "areaName": "上海,上海,杨浦区",
            "status": "揽收",
            "location": "上海 上海市 杨浦区",
            "areaCenter": "121.526077,31.259541",
            "areaPinYin": "yang pu qu",
            "statusCode": "1"
        }
    ],
    "state": "5",
    "condition": "00",
    "routeInfo": {
        "from": {
            "number": "CN310110000000",
            "name": "上海,上海,杨浦区"
        },
        "cur": {
            "number": "CN330102000000",
            "name": "浙江,杭州市,上城区"
        },
        "to": null
    },
    "isLoop": false
}
6.1.2 引入Axios
<!-- 引入Axios框架 -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

<div id="appAxs">
    订单号:{{info.num}}
    <br/>
    消息:{{info.message}}
</div>
<script>
    //Vue实例
    var app4 = new Vue({

        el: '#appAxs',
        data(){				//data是一个函数
            return {
                info:{	
                    message:'测试1',
                    num:'测试2'
                }
            }
        }
    })
</script>
6.1.3 mounted函数发送请求
<div id="appAxs">
    订单号:{{info.num}}
    <br/>
    消息:{{info.message}}
    <br/>
</div>
<script>
    var app4 = new Vue({

        el: '#appAxs',
        data( ){
            return {
                info:{	
                    message:'测试1',
                    num:'测试2'
                }
            }
        },
        mounted( ){
            //alert(11);
            axios.get("data.json")
                .then(response => this.info = response.data)
			//
        }

    })
</script>

再试试读取一下JSON格式中的数组:

<div id="appAxs">
    订单号:{{info.num}}
    <br/>
    消息:{{info.num}}
    <br/>
    <!-- 增加 v-for 遍历数组 -->
    <ul>
        <li v-for="his in info.data" >
            {{his.time}} {{his.context}}
        </li>
    </ul>
</div>
<script>
    var app4 = new Vue({

        el: '#appAxs',
        data(){
            return {
                info:{	
                    message:'测试1',
                    num:'测试2',
                    data:[]			//新增JSON中的数组属性
                }
            }
        },
        mounted(){
            //alert(11);
            axios.get("data.json")
                .then(response => this.info = response.data)
        }
    })
</script>

7. 表单输入绑定

Vue是个MVVM框架,具有数据双向绑定的特点,即当数据发生变化时,视图也会发生变化。反之当视图发生变化时,数据也会同步变化。但这一特定时对于UI控件来说的,非UI控件并不会涉及到数据双向绑定。

在Vue中,双向数据绑定对于我们处理表单来说非常容易。 可以用 v-model 指令在表单 inputtextareaselect 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但 v-model 本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。

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

v-model 在内部为不同的输入元素使用不同的 property 并抛出不同的事件:

  • text 和 textarea 元素使用 value property 和 input 事件;

  • checkbox 和 radio 使用 checked property 和 change 事件;

  • select 字段将 value 作为 prop 并将 change 作为事件。

对于需要使用输入法(如中文、日文、韩文等) 的语言,你会发现 v-model 不会在输入法组合文字过程中得到更新。如果你也想处理这个过程,请使用 input 事件。

7.1 文本

双向绑定的文本框信息:

<div id="apptext">
    <input v-model="message" placeholder="edit me">
    <p>Message is: {{ message }}</p>

    <span>多行文本:</span>
    <p style="white-space: pre-line;">{{ multiplemessage }}</p>
    <br>
    <textarea v-model="multiplemessage" placeholder="add multiple lines"></textarea>
</div>
<script>
    var app4 = new Vue({
        el: '#apptext',
        data:{
            message : "",
            multiplemessage : ""
        }
    })
</script>

使用v-model绑定message以及multiplemessage,在视图和数据模型层同步输入的内容。

7.2 复选框

单个复选框,绑定到布尔值

<div id="appCheckBox">
    <input type="checkbox" id="checkbox" v-model="checkState">
    <label for="checkbox">{{ checkState }}</label>
</div>
<script>
    var app4 = new Vue({
        el: '#appCheckBox',
        data:{
            checkState : ""
        }
    })
</script>

多个复选框,绑定到同一数组

<div id="appMulCheckBox">
    <input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
    <label for="jack">Jack</label>
    <input type="checkbox" id="john" value="John" v-model="checkedNames">
    <label for="john">John</label>
    <input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
    <label for="mike">Mike</label>
    <br>
    <span>Checked names: {{ checkedNames }}</span>
</div>
<script>
    var app4 = new Vue({
        el: '#appMulCheckBox',
        data:{
            checkedNames : []		//必须是数组
        }
    })
</script>

7.3 单选框

<div id="appRadio">
    <input type="radio" id="one" value="One" v-model="picked">
    <label for="one">One</label>
    <br>
    <input type="radio" id="two" value="Two" v-model="picked">
    <label for="two">Two</label>
    <br>
    <span>Picked: {{ picked }}</span>
</div>
<script>
    var app4 = new Vue({
        el: '#appRadio',
        data:{
            picked : ""
        }
    })
</script>

7.4 选择框

单选时:

<div id="appSelect">
    <select v-model="selectValue">
        <option disabled value="">请选择</option>
        <option value="AA">A</option>
        <option value="BB">B</option>
        <option value="CC">C</option>
    </select>
    <span>Selected: {{ selectValue }}</span>
</div>
<script>
    var app4 = new Vue({
        el: '#appSelect',
        data:{
            selectValue : ""
        }
    })
</script>

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

多选时绑定到一个数组:

<div id="appMulSelect">
    <select v-model="selectMul" multiple style="width: 50px;">
        <option disabled value="">请选择</option>
        <option value="AA">A</option>
        <option value="BB">B</option>
        <option value="CC">C</option>
    </select>
    <span>Selected: {{ selectMul }}</span>
</div>
<script>
    var app4 = new Vue({
        el: '#appMulSelect',
        data:{
            selectMul : []
        }
    })
</script>

v-for渲染一个动态选项:

<div id="appForSelect">
    <select v-model="selectFor" style="width: 50px;">
        <option disabled value="">请选择</option>
        <option v-for="option in options" v-bind:value="option.value">
            {{ option.text }}
        </option>
    </select>
    <span>Selected: {{ selectFor }}</span>
</div>
<script>
    var app4 = new Vue({
        el: '#appForSelect',
        data:{
            selectFor : "B2",			//默认选中
            options: [
                { text: 'One', value: 'A1' },
                { text: 'Two', value: 'B2' },
                { text: 'Three', value: 'C3' },
                { text: 'four', value: 'D4' }
            ]
        }
    })
</script>

8. 组件

组件是可复用的 Vue 实例,且带有一个名字,我们把这个组件作为自定义元素来使用。 通常一个应用会以一棵嵌套的组件树的形式来组织,也就是说组件中可以嵌套子组件,子组件中也可以嵌套子组件: 组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 datacomputedwatchmethods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。

8.1 注册组件

这里我们演示一种注册组件的方式,在实际开发采用的是vue-cli创建.vue模板文件的方式。 为了能在模板中使用,这些组件必须先注册以便 Vue 能够识别。这里有两种组件的注册类型:全局注册局部注册。至此,我们的组件都只是通过 Vue.component 全局注册的,比如注册一个自定义li组件:

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

然后在页面使用时,就可以在ul标签中使用了:

<div id="app">
    <ul>
    	<my-first-li></my-first-li>		<!-- 自定义组件代替li -->
    </ul>
</div>

完整代码如下:

<div id="app">
    <ul>
    	<my-first-li></my-first-li>		<!-- 自定义组件代替li -->
    </ul>
</div>

<script>
    //注册一个组件
    Vue.component("my-first-li",{
        template:"<li>Hello Vue-component</li>"
    })

    //声明式渲染
    var first = new Vue({
        el: "#app",			//挂载#app页面元素
    })

</script>

8.2 组件数据绑定

Prop 是你可以在组件上注册的一些自定义 attribute。当一个值传递给一个 prop attribute 的时候,它就变成了那个组件实例的一个 property。为了给组件传递一个数据,我们可以用一个 props选项将其包含在该组件可接受的 prop 列表中,再使用v-bind绑定该数据。

比如要使用自定义列表展示如下data中的数组 :

var first = new Vue({
    el: "#app",			//挂载#app页面元素
    data:{
        names:["孙权","曹操","刘备"]
    }
})

自定义组件中需要使用v-for来循环渲染:

<div id="app">
    <ul>
        <my-first-li v-for="str in names">{{str}}</my-first-li>
    </ul>
</div>

这样代码看起来并没有什么错误,但运行效果却并没有显示数组names中的数据,这是因为my-first-li这个自定义组件的显示内容是由注册组件中的template定义的。

Vue.component("my-first-li",{
	template:"<li>Hello Vue-component</li>"   //组件的显示内容由这里决定
})

因此我们需要改变自定义组件中的显示内容:

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

此时组件中的x_data需要两步操作

  • 将组件上的自定义attribute即 x_data使用props选项将其包含在该组件可接受的 prop 列表中

    Vue.component("my-first-li",{
        props:["x_data"]
    	template:"<li>{{x_data}}</li>"
    })
  • 在html上使用时通过v-bind:attribute绑定运行时的数据

    <my-first-li v-for="str in names" v-bind:x_data="str"</my-first-li>

完整代码如下:

<div id="app">
    <ul>
        <my-first-li v-for="strin names" v-bind:x_data="str"></my-first-li>
    </ul>
</div>

<script>
    //注册一个组件
    Vue.component("my-first-li",{
        props:["x_data"],
        template:"<li>{{x_data}}</li>"
    })

    //声明式渲染
    var first = new Vue({
        el: "#app",			//挂载#app页面元素
        data:{
            names:["孙权","曹操","刘备"]
        }
    })

</script>

运行效果如下:

如果需要下标,我们再添加一个自定义属性x_ind并使用v-bind:attr绑定:

<div id="app">
    <ul>
        <my-first-li 
        	v-for="(str,index) in names" 
            v-bind:x_data="str" 
            v-bind:x_ind="index">
        </my-first-li>
    </ul>
</div>

<script>
    //注册一个组件
    Vue.component("my-first-li",{
        props:["x_data","x_ind"],
        template:"<li>{{x_ind}}-{{x_data}}</li>"
    })

    //声明式渲染
    var first = new Vue({
        el: "#app",			//挂载#app页面元素
        data:{
            names:["孙权","曹操","刘备"]
        }
    })

</script>

最终运行效果如下:

8.3 插槽

Vue 实现了一套内容分发的 API,这套 API 的设计灵感源自 Web Components 规范草案,将 slot元素作为承载分发内容的出口。 也可以这样理解:插槽就是子组件中的提供给父组件使用的一个占位符,用slot元素表示,父组件可以使用任何代码(html,组件等)替换子组件slot的位置。

比如我们定义一个组件my-second,内置一个插槽slot占位,名为abcd

<div id="app">
    <my-second></my-second>
</div>
<script>
    //组件
    Vue.component("my-second",{
        template:"<div>"
        			+"<h1>看看今天的天气</h1>"
        			+"<slot name='abcd'></slot>"
        		+"</div>"
        //上面的写法可读性比较强,也可更多地使用下面的写法:
		//template:"<div><h1>看看今天的天气</h1><slot name='abcd'></slot></div>"
    })
</script>

此时我们对插槽abcd并没有填充内容,运行后只显示“看看今天的天气“。

下面我们定义两个不同的组件sub-onesub-two分别展示两种天气:

<script>
    //子组件1
    Vue.component("sub-one",{
        template :"<div style='color:red'>5~17度<br/>暴雨<br/>东北风7级</div>"
    })

    //子组件2
    Vue.component("sub-two",{
        template :"<div style='color:green'>10~25度<br/>多云转晴<br/>东北风小于3级</div>"
    })
</script>

然后子组件填入指定name的插槽中,就可以了:

<div id="app">
    <my-second>
        <sub-one slot="abcd"></sub-one> 
        <!-- 可切换成观察运行效果 <sub-two slot="abcd"></sub-two>  -->
    </my-second>
</div>

效果如下:

如果需要传递数据,还是使用Vue实例的data和标签中的v-bind:attr来进行绑定,例如我们定义一个sub-three来进行天气各项数据的传递:

<div id="app">
    <my-second>
        <sub-three
            slot="abcd"       
        	v-bind:clr="color"
            v-bind:tpr="temperature"
            v-bind:wth="weather"
            v-bind:wfc="wind_force"
        />
    </my-second>
</div>
<script>
    //组件
    Vue.component("my-second",{

        template:"<div>"
        +"<h1>看看今天的天气2</h1>"
        +"<slot></slot>"
        +"</div>"
        //template:"<div><h1>看看今天的天气</h1><slot name='abcd'></slot></div>"
    })

    //子组件3
    Vue.component("sub-three",{
        props:["clr","tpr","wth","wfc"],
        template :"<div :style='clr'>{{tpr}}度<br/>{{wth}}<br/>{{wfc}}</div>"
    })

    //声明式渲染
    var second = new Vue({
        el: "#app",			//挂载#app页面元素
        data:{
            color:{"color":"orange"},
            temperature: "8~20",
            weather: "小雨",
            wind_force:"东北风小于5级"
        }
    })
</script>

其中:style是Vue中利用样式对象color:{"color":"orange"}渲染html样式的方法,当前代码运行效果如下:

这种有name属性的插槽也叫具名插槽,如果只有一个插槽的话就可以不添加name属性,叫做默认插槽,大家可以自行测试,代码如下:

<div id="app">
    <my-second>
        <sub-two></sub-two>  <!-- 只有一个插槽填入时不需要指定插槽name -->
    </my-second>
</div>

<script>
    //组件
    Vue.component("my-second",{

        template:"<div>"
        			+"<h1>看看今天的天气</h1>"
        			+"<slot></slot>"		//定义时去掉name属性
        		+"</div>"
    })

    //子组件1
    Vue.component("sub-one",{
        template :"<div style='color:red'>5~17度<br/>暴雨<br/>东北风7级</div>"
    })

    //子组件2
    Vue.component("sub-two",{
        template :"<div style='color:green'>10~25度<br/>多云转晴<br/>东北风小于3级</div>"
    })

    //子组件3
    Vue.component("sub-three",{
        props:["clr","tpr","wth","wfc"],
        template :"<div :style='clr'>{{tpr}}度<br/>{{wth}}<br/>{{wfc}}</div>"
    })

    //声明式渲染
    var second = new Vue({
        el: "#app",			//挂载#app页面元素
        data:{
            color:{"color":"orange"},
            temperature: "8~20",
            weather: "小雨",
            wind_force:"东北风小于5级"
        }
    })

</script>

8.4 自定义事件

自定义事件主要用来解决子组件和父组件数据传递,触发的事件名需要完全匹配监听这个事件所用的名称。即子组件如果要触发一个cameCase名字的事件:

this.$emit('myEvent')

则监听这个名字的事件名要完全一致:

<sub-component v-on:myEvent="fatherEvent"></sub-component>

比如下面这个例子:

<div id="app">
    <my-second>
        <sub-one v-bind:clr="color" v-on:facherbig="big" ></sub-one>
    </my-second>
</div>
<script>
    //组件
    Vue.component("my-second",{
        template:"<div>"
        +"<h1>看看今天的天气</h1>"
        +"<slot></slot>"
        +"</div>"
    })

    //子组件1 
    Vue.component("sub-one",{
        props:["clr"],
        template :"<div :style='clr' @mouseover='subover'>5~17度<br/>暴雨<br/>东北风7级</div>",
        methods:{
            subover : function(){
                console.log(1);
                this.$emit('facherbig');
            }

        }
    })

    //声明式渲染
    var second = new Vue({
        el: "#app",			//挂载#app页面元素
        data:{
            color:{"color":"orange"},
            temperature: "8~20",
            weather: "小雨",
            wind_force:"东北风小于5级"
        },
        methods:{
            big : function( ){
                //console.log( 2 );
                this.color={"font-size":"20px"}
            }
        }
    })
</script>

代码的18行@mouseover='subover'就是子组件的事件,也可以写成v-on:mouseover='subover',在子组件的定义中第20行就是该方法的执行代码;其中第22行this.$emit('facherbig')在子组件嵌入插槽时绑定监听到Vue实例的big方法,在第3行v-on:fatherbig="big"这里明确了该子组件事件调用Vue实例中的big方法。运行结果大家可以通过观察控制台就会发现先执行的时子组件的subover方法,然后才是父组件的big方法。这就是自定义事件的基本用法。

9. 计算属性

计算属性是用来声明式的使用其他数据算出一个新数据,并能把新数据缓存下来,当其依赖数据发生改变时,它会自动更新缓存的数据,这就极大的提高了我们程序的性能。

计算属性通常声明Vue在computed中,声明在methods中也可以但没有缓存功能。比如计算小计时:

<div id="app">
    <p>{{testTotal()}}</p>
    <p>{{myTotal}}</p>
    <hr/>
    <p>{{testTotal()}}</p>
    <p>{{myTotal}}</p>
</div>

<script>
    //声明式渲染
    var first = new Vue({
        el: "#app",			//挂载#app页面元素
        data:{
            count: 10,
            price: 5.5
        },
        methods:{
            testTotal( ){
                console.log("--testTotal--");
                return this.count * this.price;		//结果没有缓存,每次都要计算
            }
        },
        computed:{
            myTotal( ){
                console.log("--myTotal--");
                return 	this.count * this.price;	//结果有缓存
            }
        }
    })

</script>

注意计算属性和方法的区别,一是计算属性调用时不需要小括号,而传统方法一定是需要小括号的;二是计算属性第一次计算后会缓存起来,以后调用时不再计算直接使用缓存中的值。因此上面代码在执行时,控制台会输出两次--testTotal----myTotal--只会输出一次。只有当依赖的属性值发生改变时才会再次计算并缓存起来,如上个例子中的this.countthis.price有一个发生了变化,会再输出一次--myTotal--

10. VScode安装

(1)下载安装 :Visual Studio Code - Code Editing. Redefined 选择操作系统版本,直接下载安装

安装时下面的选项其实可以都选上

(2)安装中文插件包

安装好后会提示:

如果这一步忽略了的话,还可以点击插件安装:

10.1 创建项目

(1)在磁盘上建立项目文件夹test01,然后右键选择 “通过Code打开”,然后进入VScode自己创建文件夹和文件

(2)在磁盘上建立项目文件夹test01,然后在文件夹地址栏输入cmd,然后进入VScode自己创建文件夹和文件

编写html可以使用!默认模板。

10.2 主题和插件

我们可以选择自己喜欢的主题和风格:

还有文件图标主题也可以选择和删除

下面我们看看可以安装的插件:

(1)Auto Rename Tag 自动对称标签,安装好就可以使用

<!-- 修改标签头自动更新标签尾 -->
<divcccc></divcccc>
<divaaaa></divaaaa>

(2)Prettier 格式化标签,安装好需要设置:

设置如下:

点击右下角,弹出窗口中选择设置,进入文本编辑器面板,选择 Format On Save :

首次使用时在页面点击右键,选择 "使用...格式化文档":

弹出页面上选择:“配置默认格式化程序”,然后再选择 Prettier ,配置完毕,保存页面时,页面上的 html js 和 css 都可以格式化。

(3)Live Server节点应用程序,安装好就可以在页面右键弹出菜单中使用。

(4)Vetur 组件高亮显示代码插件,安装好项目中 .vue 文件会有代码着色,否则全是白色代码:

后期如果代码有红色波浪线,可以点击上图中的小齿轮,点击扩展设置,下拉到最底下,去掉5个validation :

(5)Emmet语法 ,大家可以参考官网 Cheat Sheet ,提高代码效率。

11. Vue-CLI

vue-cli(俗称:vue 脚手架)是 vue 官方提供的、快速生成 vue 工程化项目的工具。Vue CLI 是一个基于 Vue.js 进行快速开发的完整系统,提供:

  • 通过 @vue/cli 实现的交互式的项目脚手架。

  • 通过 @vue/cli + @vue/cli-service-global 实现的零配置原型开发。

  • 一个运行时依赖 (

    @vue/cli-service

    ),该依赖:

    • 可升级;

    • 基于 webpack 构建,并带有合理的默认配置;

    • 可以通过项目内的配置文件进行配置;

    • 可以通过插件进行扩展。

  • 一个丰富的官方插件集合,集成了前端生态中最好的工具。

  • 一套完全图形化的创建和管理 Vue.js 项目的用户界面。

11.1 使用步骤

(1)安装Nodejs ,网址:下载 | Node.js 中文网

默认都是next,碰到这里勾选即可,安装完成后检测,两个版本都能正常打印出来就代表安装完成。 ​

如果有同学碰见报错 :npm WARN config global --global, --local are deprecated 的情况,进入nodejs安装目录,找到npm和npm.cmd修改两个文件中的 prefix -g 为 prefix --location=global 即可。初次打开可能没有修改权限,管理员授权在属性里面改一下就行了。

(2)安装 Vue-Cli ,打开 cmd ,输入下列命令:

#设置淘宝镜像下载
npm config set registry https://registry.npm.taobao.org

#安装vue脚手架
npm install -g @vue/cli

等待安装成功后,输入 vue -V检测版本:

(3) 使用脚手架创建项目:

建立一个工作目录test02,右键"通过Code打开"进入VScode界面,在test02下新建项目hello01,hello01上右键''在集成终端中打开"进入终端界面:

这里其实和 cmd 一样,接下来输入创建项目的命令 :

vue create hello01

弹出选择项目 vue 版本2还是3,按下回车,就开始创建项目了。

创建完成之后如图:

创建项目时,有碰到 无法加载文件" C:\Users\86136\AppData\Roaming\npm\browserify.ps1,因为在此系统上禁止运行脚本。有关详细信息, 请参阅 https:/go.microsoft.com/fwlink/?LinkID=135170 中的 about_Execution_Policies" 这样的错误请参照下述步骤解除:

(4)运行脚手架项目:

在终端界面,进入项目目录,输入指令运行:

#进入项目目录
cd hello01
#运行
npm run serve 

这里对应的是项目中的 package.json 中 scripts 中的 serve 项,脚手架自己提供的一款服务器:

编译完成后,点击链接即可显示界面:

如果要终止项目,在终端界面里输入 Ctrl + C 就好了。

也可以使用 vue ui 来创建项目,在终端界面输入 vue ui ,点击 链接即可进入:

vue ui

(5)项目打包

Vue-CLI打包后的目录在 dist 中,使用在hello01中使用命令 npm run build即可。

#如果没有进入hell01项目,先进入
#cd hello01
#打包到dist中,
npm run build

11.2 项目结构说明

node_modules 通过 npm 下载的项目中使用的依赖包 public 存放网站标签favicon.icoindex首页,打包时打包到dist文件夹下

src 存放业务相关的代码和资源 src -> assets 存放图片之类的资源文件,这个目录中放的都是想被 webpack 的各种 loader 当作模块处理的文件 src -> components 存放项目中想被复用的公共 UI 组件 src -> App.vue 项目根组件 src -> main.js 项目打包入口文件

static 存放图片之类的资源文件,这个目录中的文件打包时会被 CopyWebpackPlugin 插件复制到出口根目录

.gitIgnore Git管理需要忽略的文件

babel.config.js ES6模块化转换文件

jsconfig.json 项目工具文件,提供了大量能使我们快速便捷提高代码效率的方法

package.json 记录当前项目所依赖模块的版本信息,更新模块时锁定模块的大版本号(版本号的第一位),不能锁定后面的小版本

package-lock.json 锁定包的版本,确保再次下载时不会因为包版本不同而产生问题

vue.config.js 可选的配置文件,其实也可以使用package.json中的vue字段,但我们还是单独将 vue 的配置文件写在这里。

//vue.config.js
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true,
  //改一下项目启动端口
  devServer : {
    port: 9000
  }
})

main.js 入口文件:

import Vue from 'vue'			//引入node_modules中的依赖
import App from './App.vue'		//引入同目录下的App.vue模块

Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示减少运行时开销

new Vue({						//创建Vue实例,没有el时的创建格式
  render: h => h(App),			//渲染App代表的模块(同目录下的App.vue模块)
}).$mount('#app')				//使用$mount函数挂载到容器#app中(public/index.htmls)

App.vue 单文件组件:

一个vue页面通常由三部分组成:模板(template)、js(script)、样式(style),另外当VUE文件中代码都是白色时,可以通过安装vetur插件来解决问题:

<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <HelloWorld msg="Welcome to Your Vue.js App"/>
  </div>
</template>

<script>
//导入组件(./components/HelloWorld.vue)
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>
  • template : 模板只能包含一个父节点,也就是说顶层的div只能有一个

  • js : 通常用es6来写,用export default导出,其下面可以包含数据data,生命周期(mounted等),方法(methods)等

  • style : 样式默认是影响全局的,如需定义作用域只在该组件下起作用,需在标签上加scoped,<style scoped><\/style>。如要引入外部 css文件,首先需给项目安装css-loader依赖包,打开cmd,进入项目目录,输入npm install css-loader,回车。安装完成后,就可以在style标签下import所需的css文件,例如:

    <style>
        import './assets/css/public.css'
    </style>

11.3 ES6模块化

ES6 引入了模块化,浏览器端和服务器端都支持的规范,其设计思想是在编译时就能确定模块的依赖关系,以及输入和输出的变量。之前的规范都只有一端支持(AMD浏览器端模块化规范,CommonJS服务器端模块化规范)。

在ES6的模块系统中,每个JS文件可以理解为一个模块,模块代码以严格模式执行,所以模块中的变量、函数不会添加全局作用域中。

ES6 的模块化分为导出(export) @与导入(import)两个模块。常见的导入导出方式如下:

可以将需要导出的变量放入一个对象中,然后通过默认暴露进行导出,我们在src下建立一个test1.js,在src的main.js中引入:

/*** test1.js **********导出 test1.js *****************/
export default {
    myFn(){
        return "默认导出一个方法"
    },
    myName:"hp"
}

/*** main.js **********引入 test1.js *****************/
import myObj from "./test1";
console.log(myObj.myFn(),myObj.myName);//默认导出一个方法 hp

可以使用名称导出,然后通过名称默认导入:

/*** test1.js **********导出 test1.js *****************/
let myName = "hp"
let myFun = function(){
    return "用名称导出一个方法"
}
export {
	myName,
    myFn
}

/*** index.js **********引入 test1.js *****************/
import {myName,myFn} from "./test1";
console.log(myFn(),myName);//使用名称导出一个方法 hp

还可以使用as别名导出和导入:

/*** test1.js **********导出 test1.js *****************/
let myName = "hp"
let myFn = function(){
    return "用名称导出一个方法"
}
export {
	myName as name,
    myFn as fn
}

/*** index.js **********引入 test1.js *****************/
import {name,fn} from "./test1.js";
console.log(fn(),name);//使用名称导出一个方法 hp

/* 通过*来批量接收,用as来指定接收的名字 */
/*** index.js **********引入 test.js *****************/
import {name,fn} from "./test1";
console.log(fn(),name);//使用名称导出一个方法 hp

如果只想执行模块的代码,只需编写

import "./test2";

11.4 路由

由于Vue在开发时对路由支持的不足,于是官方补充了vue-router插件。vue的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来。传统的页面应用,是用一些超链接来实现页面切换和跳转的。在vue-router单页面应用中,则是路径之间的切换,实际上就是组件的切换。路由就是SPA(单页应用)的路径管理器。再通俗的说,vue-router就是我们WebApp的链接路径管理系统。

安装

我们新建一个项目:hello02,然后进入该项目,添加router插件:

#进入项目
cd hello02

#安装路由 @3指安装v3版本
npm install vue-router@3

准备页面

在src下创建一个views文件夹,新建3个模块,分别为movie,music,tv:

<!-- 其他三个都一样 ,只是频道汉字不同 -->
<template>
  <div>电影频道</div>
</template>

<script>
export default {

}
</script>

<style>

</style>

配置路由

在要使用的项目中配置路由,在src下建立目router,建立配置文件index.js,在里面配置:

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

//导入路由组件
import Movie from '../views/movie.vue'
import Music from '../views/music.vue'
import Tv from '../views/tv.vue'

//定义路由对象
let router = new VueRouter({
    //routers加载具体的路由信息
    routes:[
        { path:"/mv",component: Movie },       
        { path:"/ms",component: Music },      
        { path:"/tv",component: Tv }    
    ]

})

//导出路由对象
export default router

接下来需要在main.js中引入:

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

Vue.config.productionTip = false

import router from './router'  //简写:index.js 可以不写

new Vue({
  render: h => h(App),
  router               //简写:router:router 名称相同可以简写
}).$mount('#app')

最后需要在使用页面用内置组件 router-link 和 router-view 链接和显示,我就偷懒加在了原项目页面:

<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <!-- 内置组件:路由链接 -->
    <!-- 使用 router-link 组件来导航. -->
    <!-- 通过传入 `to` 属性指定链接. -->
    <!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
    
    <router-link to="/ms">音乐</router-link>
    <router-link to="/tv">电视剧</router-link>
    <router-link to="/mv">电影</router-link>

    <!-- 内置组件:路由输出位置 -->
    <!-- 路由出口  路由匹配到的组件将渲染在这里 -->
    <router-view></router-view>
    <HelloWorld msg="Welcome to Your Vue.js App"/>
  </div>
</template>

期间如果有同学报错:Component name "music" should always be multi-word,是因为eslint验证比较严谨,这里我们配置一下 vue.config.js :

const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true,
  lintOnSave:false	//否在开发环境 下每次保存代码时都启用 eslint 验证
})

12. ElementUI

Elementui是由饿了么前端团队推出的基于vue封装的UI组件库,提供了丰富的PC端组件,简化了常用组件的封装,大大降低了开发难度。它一套为开发者、设计师和产品经理准备的基于Vue 2.0的桌面端组件库。 Elementui是饿了么团队根据MVVM结构Vue封装的UI组件库。中文网站:Element - The world's most popular Vue UI framework

12.1 安装

#进入项目
cd hello03
#根据官网安装
npm i element-ui -S

下载完成后在package.json中可以看见 element-ui 的版本:

12.2 布局

还是在src中建立views,创建MyContainer.vue,template粘贴官网的代码,大致如下:

在src中添加router路由,配置path目录直接到MyContainer.vue中:

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

//定义路由对象
let router = new VueRouter({
    //routers加载具体的路由信息,这里我们换一种写法,不在外部import...from了
    routes:[
        { path:"/",component:()=> import('../views/MyContainer.vue') } 
    ]
})

//导出路由对象
export default router

在 main.js 中按需导入ElementUI提供的组件 container 及其相关组件,以及我们的路由设置:

//import { from } from 'core-js/core/array'
import Vue from 'vue'
import App from './App.vue'

//Element-ui css 导入css
import 'element-ui/lib/theme-chalk/index.css'

//Element-ui 按需导入
import { 
  Container,
  Header,
  Aside,
  Main,
  Footer
} from 'element-ui'

//Element-ui 按需注册
Vue.use(Container)
Vue.use(Header)
Vue.use(Aside)
Vue.use(Main)
Vue.use(Footer)

Vue.config.productionTip = false

import router from './router'  //简写:index.js 可以不写

new Vue({
  render: h => h(App),
  router               //简写:router:router 名称相同可以简写
}).$mount('#app')

修改App.vue,直接使用 router-view :

<template>
  <div id="app">
    <router-view/></router-view>
  </div>
</template>

<script>
export default {
  name: "App"
};
</script>

<style></style>

运行查看效果:

12.3 后台布局

我们这次使用3个组件查看效果:link,button, select 。分别建立MyLink,MyButton,MySelect 三个vue文件,每个文件拷贝官方代码放入template的div标签中:

修改上个例子中的 MyContainer ,加入 router-link 和 router- view , 注意 router-link 在 el-aside ,router-view 在 el-main 中:

编辑路由文件,index.js ,这里我们使用子路由,否则内容会覆盖整个窗体因为默认的路由“/”就是整个窗体。

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

//定义路由对象
let router = new VueRouter({
    //routers加载具体的路由信息
    routes:[
        { 
            path:"/",
            component:()=> import('../views/MyContainer.vue') ,
            //再换一种写法,子路由,再次不使用 import...from 的语法
            children:[
                { path:"/lnk",component:()=> import('../views/MyLink.vue') },
                { path:"/btn",component:()=> import('../views/MyButton.vue') },
                { path:"/sel",component:()=> import('../views/MySelect.vue') }     
            ]
        }
    ]
})

//导出路由对象
export default router

最后在 main.js 中按需引入三个组件及其相关组件:

//Element-ui 按需导入
import { 
  Container,
  Header,
  Aside,
  Main,
  Footer,

  Link,
  Button,
  Select,
  Option
} from 'element-ui'

//Element-ui 按需注册
Vue.use(Container)
Vue.use(Header)
Vue.use(Aside)
Vue.use(Main)
Vue.use(Footer)

Vue.use(Link)
Vue.use(Button)
Vue.use(Select)
Vue.use(Option)

完成后效果如图所示,容器布局和路由可实现左边点击链接右边变化的后台管理界面效果:

vue-axios

13. vue-axios

网站:http://www.axios-js.com

安装:

#安装 axios 
npm install axios -S

引入main.js:

// step1: 引入
import axios from 'axios'

// step2:把axios挂载到vue的原型中,在vue中每个组件都可以使用axios发送请求,
// 不需要每次都 import一下 axios了,直接使用 $axios 即可
Vue.prototype.$axios = axios

此时在其他组件均可以使用:

this.$axios.get("http://www.juhe.cn/simpleWeather/query").then((response) => {
    console.log(response.data);
});

下面我们来解决跨域问题(ip和端口任意一个不一致都不是当前项目):

main.js中加入

//step3:使每次请求都会带一个 /api 前缀 
axios.defaults.baseURL = '/api'

vue.config.js中加入跨域配置:

module.exports = defineConfig({
  transpileDependencies: true,
  devServer:{
    proxy:{
      '/api':{
        // 此处的写法,目的是为了 将 /api 替换成 http://apis.juhe.cn/
        target:'http://apis.juhe.cn/',
        // 允许跨域
        changeOrigin: true,
        // https时需要配置此参数
        //secure:true,

        //是否代理websockets
        ws:true,
        //重写
        pathRewrite: {
          '^/api': ''
        }
      },
      //'xyz':{ target:'http:192.168.0.1:8899/'//其他跨域配置 } 
    }
/*
/api:  请求的url使用/api开始时,才会调用代理。eg:请求url为/api/admin/login实际对应的请求地址为http://apis.juhe.cn/api/admin/login。
但我们的请求的接口url可能并不含/api。所以就需要使用pathRewrite:{ '^/api':'' }来将url中的/api替换为空。得到正确的请求url:http://apis.juhe.cn/admin/login
如果你的请求的所有的url恰好都含有/api,那么可以选择不写pathRewrite或者写成pathRewrite:{ '^/api':'/api' }
*/
  }
})

  • 13
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值