Vue2.x学习笔记(一)


一、组件间通信

以下5种组件间通信,数据传递的方法中,第1~3中是比较常用的。

1. 使用 props 和 $emit 进行父子组件通信

1) 父==>子组件传值

  • Step1:先通过v-bind给父组件中绑定自定义的属性;
  • Step2: 在子组件中使用props接收父组件传递的数据;
  • Step3: 在子组件中使用接收的数据。

2) 子==>父组件传值

  • Step1: 在父组件绑定自定义的事件;
  • Step2: 在子组件中触发原生的事件,在事件函数中使用$emit触发父组件自定义的事件;
  • Step3: $emit的参数是回传给父组件的数据。
Vue.component("Child", {
    template: `
        <div>
            <input type="text" v-model="childData" @input='changeValue'/>
        </div>
    `,
    props: ['childData'], 
    methods: {
        changeValue(val){
            // 父组件自定义的事件一定是通过this.$emit()去触发
            // $emit(自定义的事件名, 消息)
            this.$emit('childHandler', val)
        }
    }
});

Vue.component("Parent", {
    data: {
        msg: "我是父组件"
    },
    template: `
        <div>
            <p>我是父组件</p>
            <Child :childData='msg' @childHandler='getDataHandler' />
        </div>,
    `,
    methods: {
        getDataHandler(val){
            console.log(val)
        }
    }
})

2. 使用 $attrs 和 $listeners 进行多层组件间通信

第一种方式处理组件之间的数据传输有一个问题:多层组件之间的数据传递只能一层一层传递。Vue2.4开始提供了$attrs$listeners来解决这个问题。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>组件通信二</title>
</head>
<body>
<div id="app"></div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
    Vue.component("C", {
        data() {
            return {}
        },
        // 通过$attrs接收父组件传递来的数据
        template: `
            <div>
                <h4>这是子组件的内容</h4>
                <p>父组件传入子组件的数据:{{$attrs.messageParent}}</p>
                <button @click="cClickHandler">向父组件传递数据</button>
            </div>
        `,
        methods: {
            cClickHandler() {
                // 通过$listeners触发父组件监听的自定义事件向父组件传递数据
                this.$listeners.getSubData('组件C传入父组件数据')
            }
        }
    });

    Vue.component("B", {
        data() {
            return {}
        },
        template: `
            <div>
                <C v-bind="$attrs" v-on="$listeners"></C>
            </div>
        `,
        methods: {}
    });

    Vue.component("A", {
        data() {
            return {}
        },
        template: `
            <div>
                <B v-bind="$attrs" v-on="$listeners"></B>
            </div>
        `,
        methods: {}
    });

    let App = {
        data() {
            return {
                msg: "我是父组件的内容",
                msg2: "Hello sub component"
            }
        },
        template: `
            <div>
                <h4>这是一个父组件</h4>
                <p>注意:{{msg}}</p>
                <A :messageParent="msg2" v-on:getSubData="showData"></A>
            </div>
        `,
        methods: {
            showData(val)  {
                console.log(val);
                this.msg = val;
            }
        },
    };

    new Vue({
        el: "#app",
        data() {
            return {}
        },
        components: {
            App
        },
        template: "<App/>"
    })
</script>
</body>
</html>

3. 使用 中央事件总线 bus 进行组件间通信

上面两种方式处理的都是父子组件之间的数据传递,如果两个组件不是父子关系呢?这种情况下可以使用中央事件总线的方式:
新建一个Vue对象bus,然后通过bus.$emit触发事件传递数据,通过bus.$on监听触发的事件接收数据。

// 中央事件总线
var bus = new Vue();

Vue.component("brother1", {
    data() {
        return {
            brother2Msg: ''
        }
    },
    template: `
        <div>
            <p>我是同级组件A</p>
            <p>同级组件B传递过来的数据:{{brother2Msg}}</p>
        </div>
    `,
    mounted() {
        // 绑定自定义的全局事件globalEvent
        bus.$on('globalEvent', (val)=>{
            this.brother2Msg = val;
        })
    }
});

Vue.component("brother2", {
    data() {
        return {
            msg: ""
        }
    },
    template: `
        <div>
            <p>我是同级组价B</p>
            <input type="text" v-model="msg" @input="passData(msg)"/>
        </div>
    `,
    methods: {
        passData(val){
            // 触发自定义的全局事件globalEvent
            bus.$emit('globalEvent', val)
        }
    }
});

var App = {  // 父组件
    template: `
        <div>
            <brother1></brother1>
            <brother2></brother2>
        </div>
    `
};

new Vue({
    el: "#app",
    components: {App},
    template: "<App/>"
})

4. 使用 $parent 和 $children 实现父子组件之间的通信

在父组件中通过this.$children[<index>].<prop_name>可以向子组件传递数据;在子组件中通过this.parent.<prop_name>可以向父组件传递数据。

Vue.component("Child", {
    props: {
        value: String, //v-model会自动传递一个属性名为value的prop属性
    },
    data() {
        return {
            myMessage: this.value
        }
    },
    methods: {
        changeValue() {
            // 通过如此调用,可以向父组件传递数据,改变父组件的值
            this.$parent.message = this.myMessage;
        }
    },
    template: `
        <div>
            <input type="text" v-model="myMessage" @change="changeValue">
            <p>{{myMessage}}</p>
        </div>
    `
});

Vue.component('Parent', {
    data() {
        return {message: 'Hi, child'}
    },
    template: `
        <div>
            <p>我是父组件</p>
            <p>{{message}}</p>
            <button @click="changeChildValue">test</button>
            <Child></Child>
        </div>
    `,
    methods: {
        changeChildValue() {
            // 通过如此调用,可以向子组件传递数据,改变子组件的值
            this.$children[0].myMessage = this.message;
        }
    },
});

var App = {
    template: `
        <div>
            <h2>我是入口组件</h2>
            <Parent/>
        </div>
    `
};

new Vue({
    el: "#app",
    components: {App},
    template: "<App/>"
})

5. 使用 provide 和 inject 实现父组件向子组件的单向通信

父组件中通过provide来提供变量,然后子组件中通过inject来注入变量。不论子组件有多深,只要调用了inject那么就可以注入provide中的数据,而不是局限于只能从当前父组件的props属性来获取数据。只要在父组件的生命周期内,子组件都可以调用。

Vue.component("Child", {
    data() {
        return {msg: ""}
    },
    template: "<div>我是子组件: {{msg}}</div>",
    inject: ['for'],
    created() {
        this.msg = this.for;
    }
});

Vue.component("Parent", {
    template: `
        <div>
            <p>我是父组件</p>
            <Child/>
        </div>
    `
});

var App = {
    provide: {
        for: "从祖先组件跨代传递到子孙组件的数据"
    },
    template: `
        <div>
            <h2>我是入口组件,也是祖先组件</h2>
            <Parent/>
        </div>
    `
};

new Vue({
    el: "#app",
    components: {
        App
    },
    template: "<App/>"
})

二、过滤器

  • 过滤器的作用:为页面中的数据进行添油加醋。
  • 过滤器的种类:局部过滤器、全局过滤器。

1. 局部过滤器

  • 声明过滤器: 在组件的filters选项中定义函数。
  • 使用过滤器:{{data|myFilter}}

2. 全局过滤器

使用Vue.filter(<name>, func)创建全局过滤器。

Vue.filter("moneyFormat", function(value) {
    return "¥" + value;
})

3. 过滤器中还可以传入参数

Vue.filter("myFilter", function(value, arg) {
    return arg + value.split('').reverse().join('');
})

三、插槽

插槽slotVue内置的组件,它的作用是作为承载内容分发的出口。

具名插槽

slot添加name属性的插槽叫做具名插槽,在使用时,将根据name去分别替换内容。

Vue.component("myLi", {
    template: `
        <li>
            <slot name="one">第一个插槽</slot>
            <slot name="two">第二个插槽</slot>
        </li>
    `
});
new Vue({
    el: "#app",
    template: `
        <ul>
            <myLi>
                <h3 slot="two">插入第二插槽</h3>
                <h2 slot="one">插入第一插槽</h2>
            </myLi>
        </ul>
    `
})

四、watch 监听

watch监听的是单个属性,当监听基本数据类型时,使用简单监视;当监听复杂数据类型(引用数据类型),使用深度监视

  • 定义watch监听时,watch对象的属性名称必须与被监听的data对象中数据属性的名称相同

示例代码:

new Vue({
    el: "#app",
    data: {
        msg: "",
        arr_obj: [
            {
                name: "Jack",
                age: 18,
                sex: male
            }
        ]
    },
    watch: {
        // 基本数据类型,简单监视
        msg: function(newValue, oldValue) {
            console.log(newValue, oldValue);
        },
        // 复杂数据类型,深度监视
        arr_obj: {
            deep: true,
            handler: function(newValue, oldValue) {
                console.log(newValue);
            }
        }
    }
})

五、计算属性

计算属性可以同时监听多个数据属性。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue-computed</title>
    <script src="node_modules/vue/dist/vue.js"></script>
    <style>
        .active{
            background-color: #409eff;
        }
    </style>
</head>
<body>
<div id="app">
    <audio autoplay controls :src="getCurrentMusicSrc"></audio>
    <ul>
        <li
            v-for="(item, index) in musicData"
            @click="playMusic(index)"
            :class="{active: currentIndex == index}">
            <h4>{{item.name}}</h4><span>--{{item.author}}</span>
        </li>
    </ul>
</div>

<script>
    var musicData = [
        {
            name: "起风了",
            author: "买辣椒也用券",
            songSrc: './Music/起风了.mp3'
        },
        {
            name: "芒种",
            author: "赵方婧",
            songSrc: './Music/芒种.mp3'
        },
        {
            name: "野狼disco",
            author: "宝石gem",
            songSrc: './Music/野狼disco.mp3'
        }
    ];
    new Vue({
        el: "#app",
        data: {
            musicData: musicData,
            currentIndex: 0
        },
        computed: {
            getCurrentMusicSrc(){
                return this.musicData[this.currentIndex].songSrc
            }
        },
        methods: {
            playMusic(index){
                this.currentIndex = index
            }
        }
    })
</script>
</body>
</html>

六、生命周期

生命周期钩子函数:

  1. beforeCreate: 组件创建之前,此时组件对象实例已经创建,但实例的属性还没有初始化。
  2. created: 组件创建之后,在这个方法中通常会请求后端,获取数据。
  3. beforeMount: 挂载数据到DOM之前会调用。
  4. mounted: 挂载数据到DOM之后会调用,应用:操作DOM
  5. beforeUpdate: 在更新DOM之前会调用,应用:可以获取原始的DOM
  6. updated: 在更新DOM之后会调用,应用:可以获取最新的DOM
  7. activated: 当keep-alive组件激活时调用。
  8. deactivated: 当keep-alive组件停用时调用。
  9. beforeDestroy: 在组件销毁之前调用。
  10. destroyed: 在组件销毁之后调用。
  11. errorCaptured:

七、keep-alive 内置组件

Vue 内置组件keep-alive能在组件的切换过程中将组件的状态保留在内存中,即缓存组件,防止重复渲染DOM

var App = {
    data() {
        return {
            isShow: true
        }
    },
    template: `
        <div>
            <keep-alive>
                <sub-component v-if="isShow"></sub-component>
            </keep-alive>
            <button @click="isShow=!isShow">显示切换</button>
        </div>
    `
}

new Vue({
    el: "#app",
    components: {App}
})

八、其他补充

  • 如果给HTML标签绑定ref="xxx"属性,使用this.$refs.xxx获取原生的JS-DOM对象。
  • 如果给组件绑定ref=“xxx”属性,那么this.$refs.xxx获取的是这个组件对象。
  • $nextTick()会在DOM更新循环结束之后自动触发,执行它的回调函数。在修改数据之后必须使用此方法,在其回调函数中获取更新之后的DOM
  • 获取更新后的DOM,除了使用$nextTick()外,还可以在生命周期钩子函数updated中获取。
let App = {
    data() {
        return {
            isShow: false
        }
    },
    template: `
        <div class="app">
            <input type="text" v-show="isShow" ref="input" />
        </div>
    `,
    mounted() {
        this.isShow = true;
        /*this.$nextTick(function() {  // 通过$nextTick的回调函数获取DOM,并获取焦点
            this.$refs.input.focus();
        });*/
        this.$nextTick(()=>{  // 通过$nextTick定义回调函数为箭头函数,获取DOM,并获取焦点
            this.$refs.input.focus();
        })
    }
};

new Vue({
    el: "#app",
    template: "<App/>",
    components: {App}
})

九、RESTful 规范

RESTful规范是一种软件的架构风格、设计风格,而不是标准,为客户端和服务端的交互提供一组设计原则和约束条件。
前后端分离:

  • 后端提供接口(API)
  • 前端写页面和Ajax技术

1. 面向资源变成

每个URL代表一种资源,URL中尽量不要使用动词,要用名词,往往名词跟数据库表格相对应。一般来说,数据库中的表都是同种记录的集合,所有API中的名词也应该使用复数。
例如:一个提供动物园信息的API,包括各种动物和雇员的信息,它的路径应该设计成:

https://api.example.com/v1/zoos
https://api.example.com/v1/animals
https://api.example.com/v1/employees

RESTful规范参考

2. 在URL中的过滤条件

如果记录数量很多,服务器不可能将所有的数据都返回给用户。API应该提供参数,用于过滤返回结果。

?limit=10: 指定返回记录的数量
?offset=10: 指定返回记录的开始位置
?page=2&per_page=100: 指定第几页,以及每页的记录数
?sortby=name&order=asc: 指定返回结果按照哪个属性排序,以及排序顺序
?item_id=1: 指定筛选条件

3. 尽量使用HTTPS

4. 相应时设置状态码

5. 返回错误信息

如果状态码是4XX,应该向用户返回错误信息。一般来说,返回的信息中将error作为键名,错误信息作为键值即可。

6. Hypermedia API

如果遇到需要跳转的情况,那么就要携带跳转接口的URL。
Hypermedia API 的设计,比如github的API就是这种设计。访问api.github.com就会得到一个所有可用的API的网址列表。

7. 其他

  1. API的身份认证应该使用OAuth 2.0框架
  2. 服务器返回的数据格式,应该尽量使用JSON,避免使用XML

猜你喜欢

转载自www.cnblogs.com/Oliver-yzx/p/12129670.html