Vue完整版(三)

八、Axios异步通信

  1. 什么是Axios

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

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

GitHub:https://github.com/axios/axios

中文文档:http://www.axios-js.com/

  1. 为什么要使用Axios

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

  1. 导入Axios
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
  1. 实例 demo

咱们开发的接口大部分都是采用 JSON 格式,可以先在项目里模拟一段 JSON 数据,数据内容如下:创建一个名为 data.json的文件并填入上面的内容,放在项目的根目录下。

{
  "name": "roc",
  "url": "https://blog.csdn.net/",
  "page": 1,
  "isNonProfit": true,
  "address": {
    "street": "南昌",
    "city": "江西",
    "country": "中国"
  },
  "links": [
    {
      "name": "博客园",
      "url": "https://www.cnblogs.com/"
    },
    {
      "name": "GitHub",
      "url": "https://github.com/"
    },
    {
      "name": "Gitee",
      "url": "https://gitee.com/"
    }
  ]
}

新建一个demo.html,来试试Axios的异步通信:

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

    <!--v-clock 解决闪烁问题-->
    <style>
        [v-clock] {
            display: none;
        }
    </style>

</head>
<body>

<!--view层 模板-->
<div id="vue" v-clock>
    <div>名称:{{info.name}} </div>
    <div>地址:{{info.address.country}}-{{info.address.city}}-{{info.address.street}} </div>
    <div>博客:<a v-bind:href="info.url">{{info.url}}</a></div>
</div>

<!--导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!--导入axios-->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

<script>
    var vm = new Vue({
        el: "#vue",
        //Model:数据
        data: {
        },
        //data   : vm的属性
        //data() : vm方法
        data(){
            return{
                //请求的返回参数,必须和json字符串一样
                info:{
                    name: null,
                    url: null,
                    address: {
                        street: null,
                        city: null,
                        country: null
                    }
                }
            }
        },
        //钩子函数,链式编程,ES6新特性
        mounted(){
            axios.get("../data.json").then(response => (this.info = response.data))
            axios.get("../data.json").then(response => (console.log(response.data)))
        }
    });
</script>

</body>
</html>
  • data: vm的属性
  • data() : vm方法
    • return{}: 请求的返回参数,必须和json字符串一样
  • mounted(){}: 钩子函数,链式编程,ES6新特性

说明:

  1. 在这里使用了 v-binda:href 的属性值与 Vue 实例中的数据进行绑定
  2. 使用 Axios 框架的 get 方法请求AJAX自动将数据封装进了 Vue 实例的数据对象中
  3. 我们在data中的数据结构必须要和Ajax响应回来的数据格式匹配!
  4. 关于代码中的v-clock 解决闪烁问题,可参考 Vue指令:v-clock解决页面闪烁问题

九、计算属性

文档:https://cn.vuejs.org/v2/guide/computed.html

  1. 什么是计算属性
  • 计算属性的重点突出在 属性 两个字上(属性是名词),首先它是个属性其次这个属性有 计算的能力(计算是动词),这里的 计算 就是个函数;
  • 简单点说,它就是一个能够将计算结果缓存起来的属性(将行为转化成了静态的属性),仅此而已;可以想象为缓存!
  1. 实例 demo
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<!--view层 模板-->
<div id="app">
    <!-- 调用methods里的方法,得用() -->
    <p>currentTime1: {{currentTime1()}}</p>
    <!-- 调用计算属性computed的方法,不能用() -->
    <p>currentTime2: {{currentTime2}}</p>
</div>

<!--1. 导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<script>
    var vm = new Vue({
        el: "#app",
        //Model:数据
        data: {
            message: "Hello,Roc!"
        },
        methods: {
            currentTime1: function () {
                return Date.now(); //返回当前时间戳
            }
        },
        //计算属性
        computed: { //methods、computed中的方法名不能重名;重名后,只会调用methods中的方法
            currentTime2: function () {
                return Date.now(); //返回一个时间戳
            },
        }
    });
</script>

</body>
</html>

说明:

  • 调用methods里的方法,得用()
    • methods是方法
  • 调用computed的方法,不能用()
    • computed计算属性,是属性
  • methods、computed中的方法名不能重名;重名后,只会调用methods中的方法
  1. 进阶
//计算属性
computed: { //methods、computed中的方法名不能重名;重名后,只会调用methods中的方法
    currentTime2: function() {
    //currentTime1: function() {
        this.message;
        return Date.now(); //返回一个时间戳
    }
}

属性返回前,如果有数据刷新,缓存页也刷新!

  1. 结论

调用方法时,每次都需要进行计算,既然有计算过程则必定产生系统开销,那如果这个结果是不经常变化的呢?

此时就可以考虑将这个结果缓存起来,采用计算属性可以很方便的做到这一点,计算属性的主要特性就是为了将不经常变化的计算结果进行缓存以节约我们的系统开销。

十、插槽slot:内容分发

文档:https://cn.vuejs.org/v2/guide/components-slots.html

  1. 什么是插槽

Vue 实现了一套内容分发的 API,这套 API 的设计灵感源自 Web Components 规范草案,将 <slot>元素作为承载分发内容的出口。

它允许你像这样合成组件:

<navigation-link url="/profile">
  Your Profile
</navigation-link>

然后你在 <navigation-link>的模板中可能会写为:

<a
  v-bind:href="url"
  class="nav-link"
>
  <slot></slot>
</a>

当组件渲染的时候,<slot></slot>将会被替换为“Your Profile”。插槽内可以包含任何模板代码,包括 HTML:

<navigation-link url="/profile">
  <!-- 添加一个 Font Awesome 图标 -->
  <span class="fa fa-user"></span>
  Your Profile
</navigation-link>

甚至其它的组件:

<navigation-link url="/profile">
  <!-- 添加一个图标的组件 -->
  <font-awesome-icon name="user"></font-awesome-icon>
  Your Profile
</navigation-link>

如果 <navigation-link>template没有 包含一个 <slot> 元素,则该组件起始标签和结束标签之间的任何内容都会被抛弃。

  1. 内容分发

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

  1. 实例 demo

比如准备制作一个待办事项组件(todo),该组件由待办标题(todo-title)和待办内容(todo-items)组成,但这三个组件又是相互独立的,该如何操作呢?

  • 第一步: 定义一个待办事项的组件
<!-- 组件:todo -->
<div id="app"">
    <todo></todo>
</div>
              
<!-- 1.导入Vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
    
<script>
    Vue.component('todo', {
        template: '<div>\
                    <div>待办事项</div>\
                    <ul>\
                        <li>Linux</li>\
                        <li>Spring Boot</li>\
                        <li>Vue</li>\
                    </ul>\
                   </div>'
    });
</script>
  • 第二步: 我们需要让,待办事项的标题和值实现动态绑定,怎么做呢? 我们可以留出一个插槽!
  1. 将上面的代码留出一个插槽,即<slot>
Vue.component('todo', {
    template: '<div>\
                    <slot name="todo-title"></slot>\
                    <ul>\
                        <slot name="todo-items"></slot>\
                    </ul>\
               </div>'
});
  1. 定义一个名为 todo-title 的待办标题组件 和 todo-items 的待办内容组件:
Vue.component('todo-title', {
    props: ['title'],
    template: '<div>{{title}}</div>'
});
Vue.component('todo-items', {
    //这里的index,就是数组的下标,使用for循环遍历的时候,可以循环出来!
    props: ['index', 'item'],
    template: '<li>{{index + 1}}. {{item}}</li>',
});
  1. 实例化 Vue 并初始化数据:
var vm = new Vue({
    el: '#app',
    data: {
        todoTitle: 'Jerry学JavaWeb',
        todoItems: ['Linux', 'Spring Boot', 'Vue'],
    }
});
  1. 将这些值,通过插槽插入:
<!-- 组件:todo -->
<div id="app"">
    <todo>
        <todo-title slot="todo-title" 
            v-bind:title="todoTitle">
        </todo-title>
        <todo-items slot="todo-items" 
            v-for="(item, index) in todoItems" 
            v-bind:item="item" 
            v-bind:index="index":key="index"></todo-items>
        </todo-items>
    </todo>
</div>

说明:
我们的 todo-titletodo-items 组件分别被分发到了 todo 组件的 todo-titletodo-items 插槽中。

十一、自定义事件

文档:https://cn.vuejs.org/v2/guide/components-custom-events.html

  1. 什么是自定义事件

通过上面"插槽slot:内容分发"的代码不难发现,数据项在Vue的实例中,但删除操作要在组件中完成,那么组件如何才能删除Vue实例中的数据呢?

此时就涉及到参数传递与事件分发了,Vue为我们提供了自定义事件的功能很好的帮助我们解决了这个问题:

使用this.$emit ('自定义事件名',参数)
在这里插入图片描述

this.$emit('myEvent')

则监听这个名字的 kebab-case 版本是不会有任何效果的:

<!-- 没有效果 -->
<my-component v-on:my-event="doSomething"></my-component>

不同于组件和 prop,事件名不会被用作一个 JavaScript 变量名或 property 名,所以就没有理由使用 camelCase 或 PascalCase 了。并且 v-on 事件监听器在 DOM 模板中会被自动转换为全小写 (因为 HTML 是大小写不敏感的),所以 v-on:myEvent 将会变成 v-on:myevent——导致 myEvent 不可能被监听到。

因此,我们推荐你始终使用 kebab-case 的事件名。

  1. 自定义组件的v-model

2.2.0+ 新增

一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件,但是像单选框、复选框等类型的输入控件可能会将 value attribute 用于不同的目的model 选项可以用来避免这样的冲突:

Vue.component('base-checkbox', {
  model: {
    prop: 'checked',
    event: 'change'
  },
  props: {
    checked: Boolean
  },
  template: `
    <input
      type="checkbox"
      v-bind:checked="checked"
      v-on:change="$emit('change', $event.target.checked)"
    >
  `
})

现在在这个组件上使用 v-model 的时候:

<base-checkbox v-model="lovingVue"></base-checkbox>

这里的 lovingVue 的值将会传入这个名为 checked 的 prop。同时当 <base-checkbox> 触发一个 change 事件并附带一个新的值的时候,这个 lovingVue 的 property 将会被更新。

注意你仍然需要在组件的 props 选项里声明 checked 这个 prop。

  1. 实例 demo
  • 在vue的实例中,增加了 methods 对象并定义了一个名为 removeTodoItems 的方法:
    var vm = new Vue({
        el: '#app',
        data: {
            todoTitle: 'Jerry学JavaWeb',
            todoItems: ['Linux', 'Spring Boot', 'Vue'],
        },
        methods: {
            //该方法可以被模板中自定义事件触发
            removeItems: function (index) {
                console.log("删除 " + this.todoItems[index] + " 成功");
                // splice():方法 向/从 数组中 添加/删除 项目,然后返回被删除的项目,其中 index 为 添加/删除 项目的位置,1 表示删除的数量
                this.todoItems.splice(index,1);//一次删除一个元素
            }
        }
    });
  • 修改 todo-items待办内容组件的代码,增加一个删除按钮,并且绑定事件:
    Vue.component('todo-items', {
        //这里的index,就是数组的下标,使用for循环遍历的时候,可以循环出来!
        props: ['index', 'item'],
        // “:” 是指令 “v-bind”的缩写,“@”是指令“v-on”的缩写;“.”是修饰符
        //只能绑定当前组件的方法
        template: '<li>{{index + 1}}. {{item}} <button @click="remove">删除</button></li>',
        methods: {
            remove: function (index) {
                //这里的 remove 是自定义事件的名称,需要在 HTML 中使用 v-on:remove 的方式指派
                this.$emit('remove', index);
            }
        }
    });
  • 修改 todo-items 待办内容组件的 HTML 代码,增加一个自定义事件,比如叫 remove,可以和组件的方法绑定,然后绑定到vue的方法中:
    <!--增加了 v-on:remove="removeItems(index)" 自定义事件,该事件会调用 Vue 实例中定义的名为 removeItems 的方法-->
    <todo-items slot="todo-items"
                v-for="(item, index) in todoItems"
                v-bind:item="item"
                v-bind:index="index"
                v-on:remove="removeItems(index)"></todo-items>
    </todo-items>
  • 完整代码:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<!-- 组件:todo -->
<div id="app">
    <todo>
        <todo-title slot="todo-title"
                    v-bind:title="todoTitle">
        </todo-title>
        <!--增加了 v-on:remove="removeItems(index)" 自定义事件,该事件会调用 Vue 实例中定义的名为 removeItems 的方法-->
        <todo-items slot="todo-items"
                    v-for="(item, index) in todoItems"
                    v-bind:item="item"
                    v-bind:index="index"
                    v-on:remove="removeItems(index)"></todo-items>
        </todo-items>
    </todo>
</div>

<!--1. 导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<script>
    Vue.component('todo', {
        template: '<div>\
                    <slot name="todo-title"></slot>\
                    <ul>\
                        <slot name="todo-items"></slot>\
                    </ul>\
               </div>'
    });
    Vue.component('todo-title', {
        props: ['title'], //props传递参数不能使用驼峰命名法则,不然数据没法渲染到页面上
        template: '<div>{{title}}</div>'
    });
    Vue.component('todo-items', {
        //这里的index,就是数组的下标,使用for循环遍历的时候,可以循环出来!
        props: ['index', 'item'],
        // “:” 是指令 “v-bind”的缩写,“@”是指令“v-on”的缩写;“.”是修饰符
        //只能绑定当前组件的方法
        template: '<li>{{index + 1}}. {{item}} <button @click="remove">删除</button></li>',
        methods: {
            remove: function (index) {
                //这里的 remove 是自定义事件的名称,需要在 HTML 中使用 v-on:remove 的方式指派
                this.$emit('remove', index);
            }
        }
    });

    //再实例化
    var vm = new Vue({
        el: '#app',
        data: {
            todoTitle: 'Jerry学JavaWeb',
            todoItems: ['Linux', 'Spring Boot', 'Vue'],
        },
        methods: {
            //该方法可以被模板中自定义事件触发
            removeItems: function (index) {
                console.log("删除 " + this.todoItems[index] + " 成功");
                // splice():方法 向/从 数组中 添加/删除 项目,然后返回被删除的项目,其中 index 为 添加/删除 项目的位置,1 表示删除的数量
                this.todoItems.splice(index, 1);//一次删除一个元素
            }
        }
    });
</script>

</body>
</html>
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值