Vue 异步通信、计算属性、slot插槽和自定义事件

Vue 异步通信、计算属性、slot插槽和自定义事件

参考【狂神说Java】Vue最新快速上手教程通俗易懂 视频学习内容

1. Axios 异步通信

Axios 是一个开源的可以用在浏览器和 NodeJS 的异步通信框架,它的主要作用就是实现 Ajax 异步请求通信

CDN 安装方法:

<script src="https://cdn.staticfile.org/axios/0.18.0/axios.min.js"></script>

为什么要使用 Axios?

由于 Vue.js 是一个视图层框架且作者严格遵守 SoC(关注度分离原则),所以 Vue.js 并不包含 Ajax 的通信功能。为了解决通信问题,作者单独开发了一个名为 vue-resources 的插件,不过在进入 2.0 版本之后停止了对该插件的维护,并推荐使用 Axios 框架,减少使用 JQuery 下的 Ajax 请求,因为它操作 DOM 元素过于频繁。

使用方法:

Vue.axios.get(api).then((response) => {
  console.log(response.data)
})

数据准备 JSON:

{
  "name": "trainingl",
  "age": "22",
  "sex": "男",
  "url":"https://www.suda.edu.cn/",
  "address": {
    "street": "干将东路",
    "city": "江苏省苏州市",
    "country": "中国"
  },
  "links": [
    {
      "name": "Web of suda",
      "url": "https://www.suda.edu.cn/"
    },
    {
      "name": "baidu",
      "url": "https://www.baidu.com"
    },
    {
      "name": "Graduate of SUDA",
      "url": "http://yjs.suda.edu.cn/"
    }
  ]
}

测试内容:给按钮绑定一个点击事件 v-on:click="getInfo()",当用户点击按钮时会通过 axios 触发异步请求,请求的内容是本地的一个 JSON 数据。

<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <h3>{{message}}</h3>
    <button v-on:click="getInfo()">获取用户信息</button>
    <div>{{info.name}}</div>
    <div>{{info.age}}</div>
    <div>{{info.address.country}}{{info.address.city}}{{info.address.street}}</div>
    <div><a v-bind:href="info.url">点我跳转</a></div>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script src="https://cdn.staticfile.org/axios/0.18.0/axios.min.js"></script>
<script>
    var vm = new Vue({
        el:"#app",
        data(){
            return{
                message: 'Hello World',
                //请求调用的返回参数格式,必须和json字符串一样
                info:{
                    name: null,
                    age: null,
                    sex: null,
                    url: null,
                    address: {
                        street: null,
                        city: null,
                         country: null
                    }
                }
            }
        },
        methods:{
            getInfo: function () {
                axios
                    .get("./data.json")
                    .then(response => (this.info=response.data))
                    .catch(function (error) { //请求失败处理
                        console.log(error);
                    })
            }
        },
        //钩子函数,链式编程,ES6新特性
        mounted(){
            //如果希望加载页面时触发异步请求,则将axios写在这里
        }
    })
</script>
</body>
</html>

在这里插入图片描述


2. Vue 计算属性

计算属性的重点突出在属性两个字上(属性是名词),首先它是个属性,其次这个属性有计算的能力(计算是动词),这里的计算就是个函数。简单地说,它就是一个能够将计算结果缓存起来的属性(将行为转化成立静态的属性)。

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

<div id="app">
    <div>currentTime1:{{currentTime1()}}</div>
    <div>currentTime2:{{currentTime2}}</div>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            message: 'Hello, World!'
        },
        methods:{
            currentTime1: function () {
                return new Date().toLocaleString(); //返回一个时间
            }
        },
        computed: {
            //计算属性:method,computed 方法名不能重名
            currentTime2: function () {
                this.message;
                return new Date().toLocaleString();
            }
        }
    })
</script>
</body>
</html>

我们可以使用 methods 来替代 computed,效果上两个都是一样的,但是 computed 是基于它的依赖缓存,只有相关依赖发生改变时才会重新取值。而使用 methods ,在重新渲染的时候,函数总会重新调用执行。

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


3. slot 插槽

在了解 slot 插槽之前,需要对 vue 组件基础以及传值过程有所理解。

Vue 实现了一套内容分发的 API,将 <slot> 元素作为承载分发内容的出口,被称作插槽。**插槽实质是对子组件的扩展,通过<slot>插槽向组件内部指定位置传递内容。**可以应用在组合组件的场景中。

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

<div id="app">
    <todo>
        <todo-title slot="todo-title" v-bind:name="title"></todo-title>
        <todo-items slot="todo-items" v-for="item in todoItems" v-bind:item="item"></todo-items>
    </todo>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
    //slot 插槽。这个组件要定义在前面
    Vue.component("todo", {
        template: '<div>\
                <slot name="todo-title"></slot>\
                <ol>\
                <slot name="todo-items"></slot>\
                </ol>\
                </div>'
    });

    //子组件,子组件的传值方式与组件是一样的
    Vue.component('todo-title',{
       //属性
       props: ["name"],
       template: '<div>{{name}}</div>'
    });
    Vue.component('todo-items',{
        //属性
        props: ["item"],
        template: '<li>{{item}}</li>'
    });
    
    var vm = new Vue({
        el:"#app",
        data:{
            //标题
            title: "中国华东五大名校",
            //列表
            todoItems: ['浙江大学', '上海交通大学', '复旦大学', '南京大学', '中国科学技术大学']
        }
    })
</script>
</body>
</html>

在自定义组件 todo 中声明两个 slot 插槽,然后定义两个子组件 todo-titletodo-items,将这两个组件插入到这两个槽位。组件与子组件之间如果需要传递数据,就会用到 v-bindprops


4. Vue 自定义事件

我们现在如果想在 slot 插槽(子组件) 上绑定事件,比如在每个 <li>Item</li> 项后增加一个删除按钮,用户点击该按钮则删除该项。由于数据项在 Vue 的实例中,但删除操作要在组件中完成,那么组件如何才能删除 Vue 实例中的数据呢?

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

<div id="app">
    <todo>
        <todo-title slot="todo-title" v-bind:name="title"></todo-title>
        <todo-items slot="todo-items" v-for="(item, index) in todoItems" v-bind:item="item" v-bind:index="index" v-on:removes="removeItem(index)"></todo-items>
    </todo>
</div>


<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
    //slot 插槽。这个组件要定义在前面
    Vue.component("todo", {
        template: '<div>\
                <slot name="todo-title"></slot>\
                <ol>\
                <slot name="todo-items"></slot>\
                </ol>\
                </div>'
    });
    Vue.component('todo-title',{
       //属性
       props: ["name"],
       template: '<div>{{name}}</div>'
    });
    Vue.component('todo-items',{
        //属性
        props: ["item", "index"],
        template: '<li>{{item}}&emsp;<button @click="remove">删除</button></li>',
        methods: {
            remove: function (index) {
                //this.$emit 自定义事件分发
                this.$emit('removes', index)
            }
        }
    });

    var vm = new Vue({
        el:"#app",
        data:{
            //标题
            title: "中国华东五大名校",
            //列表
            todoItems: ['浙江大学', '上海交通大学', '复旦大学', '南京大学', '中国科学技术大学']
        },
        methods: {
            removeItem: function (index) {
                console.log("删除了"+this.todoItems[index]+"OK");
                this.todoItems.splice(index,1);
            }
        }
    })
</script>
</body>
</html>

测试效果:

下面我们分析一下上面的执行过程:

首先,我们给每个列表项增加一个按钮并绑定点击事件 '<li>{{item}}&emsp;<button @click="remove">删除</button></li>,在该子组件 todo-items 的 methods 方法中进行事件分发 this.$emit('自定义事件名', 参数)

methods: {
    remove: function (index) {
        //this.$emit 自定义事件分发
        this.$emit('removes', index)
    }
}

将该事件分发到上层处理 v-on:removes="removeItem(index)",最后调用 Vue 实例 methods 属性中定义的方法完成。

methods: {
    removeItem: function (index) {
        console.log("删除了"+this.todoItems[index]+"OK");
        this.todoItems.splice(index,1);
    }
}

注:this.todoItems.splice(index, len) 是 JavaScript 的数组内置方法,表示从数组某一个索引开始,向后删除 len 个元素。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值