Vue基础07api盘点

136 阅读2分钟

Vue基础07api盘点

1 数据相关,批量设置商品价格

1.1 Vue.set

向响应工对象中添加一个属性,并确保这个属性民同样是响应式的且触发视图更新

使用方法: Vue.set(target, propertyName/index, value)

批量设置商品价格

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>购物车</title>
</head>
<body>
    <div id="app">
        <h2>{{title}}</h2>
        <course-add v-model="course" @add-course="addCourse"></course-add>
        <p><input type="text" v-model.number="price"> <button @click="batchUpdate">批量更新价格</button></p>
        <course-list :courses="courses"></course-list> 
        <p>课程总数:{{this.courses.length}}</p>
    </div>

    <script src="../js/vue.js"></script>

    <script>

        // 课程新增组件
        Vue.component('course-add', {
            props: ['value'],
            template: `
            <div>
                <input :value="value" @input="onInput" @keydown.enter="addCourse">
                <button @click="addCourse">新增</button>
            </div>
            `,
            methods: {
                addCourse() {
                    this.$emit('add-course')
                },
                onInput(e) {
                    this.$emit('input', e.target.value)
                }
            },
        })

        // 课程列表组件
        Vue.component('course-list', {
            data() {
                return {
                    selectedCourse: ''
                }
            },
            props: {
                courses: {
                    type: Array,
                    default: []
                }
            },
            template: `
            <div>
                <div v-if="courses.length < 1">
                    没有课程
                </div>
                <div v-if="courses.length > 0">
                    <div v-for="item in courses" :key="item.name" 
                        @click="selectedCourse = item.name" 
                        :style="{backgroundColor: (selectedCourse == item.name ? '#ddd' : 'transparent')}">
                        {{ item.name }} - ¥{{ item.price }}
                    </div>
                </div>
            </div>
            `
        })

        function getCourses() {
            return new Promise(resolve => {
                setTimeout(resolve([{name: 'Java开发'}, {name: 'Web开发'}]), 100)
            })
        }

        const app = new Vue({
            el: '#app',
            data() {
                return {
                    title: '购物车',
                    courses: [],
                    course: '',
                    price: 0
                }
            },
            async created() {
                this.courses = await getCourses()
                this.batchUpdate()
            },
            methods: {
                addCourse() {
                    // if (this.course == '' || this.courses.indexOf(this.course) > -1) {
                    //     return
                    // }
                    this.courses.push({name: this.course, price: this.price})
                    this.course = ''
                },
                batchUpdate() {
                    this.courses.forEach(e => {
                        // e.price = this.price // 这样写没有响应式
                        Vue.set(e, 'price', this.price)
                    });
                }
            },
        })
    </script>
    
</body>
</html>

1.2 Vue.delete

删除对象的属性,如果对象是响应式的,确保删除能触发更新视图

使用方法 Vue.delete(target, propertyName/index)

1.3 实例方法

vue.$set()
vue.$delete()

2 事件相关,批量清除多个消息窗口

2.1 vm.$on

监听当前实例上的自定义事件。事件可以由vm.$emit触发。回调函数会接收所有传入事件触发函数的额外参数。

说明:

  1. 事件的监考者和派发者是同一个实例
vm.$on('test', function(msg){
  console.log(msg)
})

2.2 vm.$emit

触发当前实例上的事件。附加参数都会传给监听器调用。

vm.$emit('test', 'hi')

2.3 vm.$once

监听一个自定义事件,但是只触发一次,一旦触发之后,监听器就会被移除。

vm.$on('test', function(msg){
  console.log(msg)
})

2.4 vm.$off

移除自定义事件监听器

  • 如果没有提供参数,则移除所有的事件监听器
  • 如果只提供了事件,则移除该事件所有的监听器
  • 如果同时提供了事件与回调,则只移除这个回调的监听器
vm.$off()
vm.$off('test')
vm.$off('test', callback)

2.5 典型应用:事件总线

通过在Vue原型上添加一个Vue实例合为事件总线,实现组件间相互通信,而且不受组件间关系影响

这样做可以在任意组件中使用this.$bus访问该组件实例

Vue.property.$bus = new Vue()

批量清除多个消息窗口

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>购物车</title>
    <style>
        .message-box {
            padding: 10px 20px;
        }
        .success {
            background: #4fc08d;
            border: 1px solid #42b983;
        }
        .warning {
            background: #f66;
            border: 1px solid #d63200;
        }
        .message-box-close {
            float: right;
        }
    </style>
</head>
<body>
    <div id="app">
        <message :show.sync="show" class="success">
            <template v-slot:title>恭喜</template>
            <template>新增成功</template>
        </message>
        <message :show.sync="showWarn" class="warning">
            <template v-slot:title>警告</template>
            <template>新增失败</template>
        </message>
        <h2>{{title}}</h2>
        <div class="toolbar"><button @click="$bus.$emit('message-close')">清空消息</button></div>
        <course-add v-model="course" @add-course="addCourse"></course-add>
        <p><input type="text" v-model.number="price"> <button @click="batchUpdate">批量更新价格</button></p>
        <course-list :courses="courses"></course-list> 
        <p>课程总数:{{this.courses.length}}</p>
    </div>

    <script src="../js/vue.js"></script>

    <script>
        Vue.prototype.$bus = new Vue()

        // 弹窗组件
        Vue.component('message', {
            props: ['show'],
            template: `
            <div v-if="show" class="message-box">
                <slot name="title"></slot>
                <slot></slot>
                <span class="message-box-close" @click="$emit('update:show', false)">X</span>
            </div>
            `,
            mounted () {
                this.$bus.$on('message-close', () => {
                    this.$emit('update:show', false)
                })
            },
        })

        // 课程新增组件
        Vue.component('course-add', {
            props: ['value'],
            template: `
            <div>
                <input :value="value" @input="onInput" @keydown.enter="addCourse">
                <button @click="addCourse">新增</button>
            </div>
            `,
            methods: {
                addCourse() {
                    this.$emit('add-course')
                },
                onInput(e) {
                    this.$emit('input', e.target.value)
                }
            },
        })

        // 课程列表组件
        Vue.component('course-list', {
            data() {
                return {
                    selectedCourse: ''
                }
            },
            props: {
                courses: {
                    type: Array,
                    default: []
                }
            },
            template: `
            <div>
                <div v-if="courses.length < 1">
                    没有课程
                </div>
                <div v-if="courses.length > 0">
                    <div v-for="item in courses" :key="item.name" 
                        @click="selectedCourse = item.name" 
                        :style="{backgroundColor: (selectedCourse == item.name ? '#ddd' : 'transparent')}">
                        {{ item.name }} - ¥{{ item.price }}
                    </div>
                </div>
            </div>
            `
        })

        function getCourses() {
            return new Promise(resolve => {
                setTimeout(resolve([{name: 'Java开发'}, {name: 'Web开发'}]), 100)
            })
        }

        const app = new Vue({
            el: '#app',
            data() {
                return {
                    title: '购物车',
                    courses: [],
                    course: '',
                    price: 0,
                    show: false,
                    showWarn: false
                }
            },
            async created() {
                this.courses = await getCourses()
                this.batchUpdate()
            },
            methods: {
                addCourse() {
                    // if (this.course == '' || this.courses.indexOf(this.course) > -1) {
                    //     return
                    // }
                    if (this.course) {
                        this.courses.push({name: this.course, price: this.price})
                        this.course = ''
                        this.show = true
                    } else {
                        this.showWarn = true
                    }
                },
                batchUpdate() {
                    this.courses.forEach(e => {
                        // e.price = this.price // 这样写没有响应式
                        Vue.set(e, 'price', this.price)
                    });
                }
            },
        })
    </script>
    
</body>
</html>

3 节点引用,改造消息提示组件

3.1 ref和vm.$refs

ref被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的$refs对象上。如果在普通的DOM元素上使用,引用指向的就是DOM元素,如果用在子组件上,引用就指向组件实例

注意:

  1. ref是作为渲染结果被创建的,在初始渲染时不能访问它们
  2. $refs不是响应式的,不要试图用它在模板中做数据绑定
  3. v-for用于元素或组件时,引用信息将是包含DOM节点或股份制实例的数组

要求:

  1. 设置输入框焦点

  2. 改造message组件用打开、关闭方法控制显示

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>购物车</title>
    <style>
        .message-box {
            padding: 10px 20px;
        }
        .success {
            background: #4fc08d;
            border: 1px solid #42b983;
        }
        .warning {
            background: #f66;
            border: 1px solid #d63200;
        }
        .message-box-close {
            float: right;
        }
    </style>
</head>
<body>
    <div id="app">
        <message ref="msgSuccess" class="success">
            <template v-slot:title>恭喜</template>
            <template>新增成功</template>
        </message>
        <message ref="msgWarning" class="warning">
            <template v-slot:title>警告</template>
            <template>新增失败</template>
        </message>
        <h2>{{title}}</h2>
        <div class="toolbar"><button @click="$bus.$emit('message-close')">清空消息</button></div>
        <course-add v-model="course" @add-course="addCourse"></course-add>
        <p><input type="text" v-model.number="price"> <button @click="batchUpdate">批量更新价格</button></p>
        <course-list :courses="courses"></course-list> 
        <p>课程总数:{{this.courses.length}}</p>
    </div>

    <script src="../js/vue.js"></script>

    <script>
        Vue.prototype.$bus = new Vue()

        // 弹窗组件
        Vue.component('message', {
            data() {
                return {
                    show: false
                }
            },
            template: `
            <div v-if="show" class="message-box">
                <slot name="title"></slot>
                <slot></slot>
                <span class="message-box-close" @click="toggle()">X</span>
            </div>
            `,
            mounted () {
                this.$bus.$on('message-close', () => {
                    this.toggle()
                })
            },
            methods: {
                toggle() {
                    this.show = !this.show
                }
            },
        })

        // 课程新增组件
        Vue.component('course-add', {
            props: ['value'],
            template: `
            <div>
                <input :value="value" ref="inp" @input="onInput" @keydown.enter="addCourse">
                <button @click="addCourse">新增</button>
            </div>
            `,
            methods: {
                addCourse() {
                    this.$emit('add-course')
                },
                onInput(e) {
                    this.$emit('input', e.target.value)
                }
            },
            mounted () {
                this.$refs.inp.focus()
            }
        })

        // 课程列表组件
        Vue.component('course-list', {
            data() {
                return {
                    selectedCourse: ''
                }
            },
            props: {
                courses: {
                    type: Array,
                    default: []
                }
            },
            template: `
            <div>
                <div v-if="courses.length < 1">
                    没有课程
                </div>
                <div v-if="courses.length > 0">
                    <div v-for="item in courses" :key="item.name" 
                        @click="selectedCourse = item.name" 
                        :style="{backgroundColor: (selectedCourse == item.name ? '#ddd' : 'transparent')}">
                        {{ item.name }} - ¥{{ item.price }}
                    </div>
                </div>
            </div>
            `
        })

        function getCourses() {
            return new Promise(resolve => {
                setTimeout(resolve([{name: 'Java开发'}, {name: 'Web开发'}]), 100)
            })
        }

        const app = new Vue({
            el: '#app',
            data() {
                return {
                    title: '购物车',
                    courses: [],
                    course: '',
                    price: 0
                }
            },
            async created() {
                this.courses = await getCourses()
                this.batchUpdate()
            },
            methods: {
                addCourse() {
                    // if (this.course == '' || this.courses.indexOf(this.course) > -1) {
                    //     return
                    // }
                    if (this.course) {
                        this.courses.push({name: this.course, price: this.price})
                        this.course = ''
                        this.$refs.msgSuccess.toggle()
                    } else {
                        this.$refs.msgWarning.toggle()
                    }
                },
                batchUpdate() {
                    this.courses.forEach(e => {
                        // e.price = this.price // 这样写没有响应式
                        Vue.set(e, 'price', this.price)
                    });
                }
            },
        })
    </script>
    
</body>
</html>

4 小技巧

vscode小技巧

输入p>input+button后按回车

vue小技巧

<!-- 加一个number修饰符,price会转化成number -->
<input type="text" m-model.number="price">