前端开发之Vue框架

一、Vue组件间通信

问题补充:

  • 在组件中,this 代指当前组件
  • 在局部组件中data是1个函数,需要有返回值(return)
  • 由于组件间的数据并不能直接共享,因此需要进行数据传递

组件间通讯注意事项:

  • 传值只能在当前父组件的局部组件中使用
  • 父子组件绑定数据的变量名不能冲突
  • 属性指令不可以使用驼峰体
  • 属性指令中可以进行简单的逻辑判断或简单的数学运算
  • 在子标签的props中,可以约束接收值的类型,但不能强制规定

1、组件间通讯父传子

父传子:使用自定义属性方式

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>父子间通信</title>
    <script src="../js/vue.js"></script>
</head>
<body>
<div id="app01">

    <div style="background-color: antiquewhite">
        <h1>全局组件</h1>
        <!--子组件的数据不能直接在父组件中直接使用-->
        <span>姓名:{{name}}</span>
        <!--父组件中的数据不能直接在子组件中使用-->
        <!--在局部组件上定义属性指令,将需要传递的数据作为属性的值传递-->
        <child :child_name="name"></child>
        <!--可以在属性中进行简单的逻辑和运算-->
        <!--<child :child_name="name+'qqq'"></child>-->
    </div>

</div>
</body>
<script>
    // 生成局部组件
    var child = {
        template: `
                <div>
                    <h1>局部组件</h1>
                    <span>姓名:{{child_name}}</span>
                    <span>年龄:{{age}}</span>
                <div>`,
        data() {
            return {
                age: 18
            }
        },
        // 该属性用于接收父组件中的数据
        // props: ['name']  // 列表可直接用于接受变量
        // 字典可以控制介绍数据的类型,如果类型没有匹配也可以正常显示在前端(打印页面会报错)
        props: {
            child_name: String
        }
    }
    // 实例化全局Vue组件
    var vm = new Vue({
        el: '#app01',
        data: {
            name: 'kangkang'
        },
        // 在全局组件中组测局部组件
        components: {
            child
        },
    })
</script>
</html>

2、组件间通讯子传父

父传子:使用自定义事件的方式

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>父子间通信</title>
    <script src="../js/vue.js"></script>
</head>
<body>
<div id="app01">

    <div style="background-color: antiquewhite">
        <h1>全局组件</h1>
        <!--子组件的数据也不能在父组件中直接使用-->
        <p><span>姓名:{{name}}</span></p>
        <p><span>年龄:{{child_age}}----子组件传来的数据</span></p>
        <p><span>爱好:{{child_hobby}}----子组件传来的数据</span></p>
        <!--父组件中的数据不能直接在子组件中使用-->
        <!--在局部组件的标签上定义属性指令,将需要传递的数据作为属性的值传递-->
        <child @myevent="handleEvent"></child>
    </div>

</div>
</body>
<script>
    // 生成局部组件
    var child = {
        template: `
                <div>
                    <h1>局部组件</h1>
                    <p><span>年龄:{{age}}</span></p>
                    <p><span>爱好:{{hobby}}</span></p>
                     <span>--在子标签内绑定事件,通过点击触发传值--</span>
                    <p><button @click="handleSend">点我向父标签传值</button></p>
                <div>`,
        data() {
            return {
                age: 18,
                hobby: 'read'
            }
        },
        methods: {
            handleSend() {
                // 当子组件中的事件被触发时,调动父组件中的自定义方法,然后将需要传入的值写在后方
                this.$emit('myevent', this.age, this.hobby)
            }
        }
    }
    // 实例化全局Vue组件
    var vm = new Vue({
        el: '#app01',
        data: {
            name: 'kangkang',
            // 该变量用于接收子组件传值
            child_age: '',
            // 该变量用于接收子组件传值
            child_hobby: '',
        },
        methods: {
            // 当子标签中的事件被点击后触发传值
            handleEvent(age, hobby) {
                this.child_age = age
                this.child_hobby = hobby
            }
        },
        // 在全局组件中组测局部组件
        components: {
            child
        },
    })
</script>
</html>

3、ref属性

用法简介:

​ ref属性可以更为方便的实现父子传通信

  • 将ref设置为标签的属性
    • 普通标签:直接获取该标签
    • 表单标签:直接获取该标签
    • 组件标签:获取该组件标签对象

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>父子间通信</title>
    <script src="../js/vue.js"></script>
</head>
<body>

<div id="app01">

    <div style="background-color: antiquewhite">
        <h1>ref属性用法</h1>
        <hr>
        <div><h3>普通标签</h3>
            <p ref="my_p">我是普普通通P标签</p>
        </div>
        <hr>
        <div><h3>表单标签</h3>
            <p>
                <input type="text" ref="my_input" v-model="my_text">
            </p>
        </div>
        <div><h3>组件标签</h3>
            <child ref="my_child"></child>
        </div>
        <hr>
        <div>
            <button @click="handleClick">点我获取所有ref属性的标签</button>
        </div>
        <div>
            <span>我是全局组件</span>
            <p>{{name}}----子组件向父传值</p>

        </div>

    </div>

</div>
</body>
<script>
    var child = {
        template:
            `
            <div>
                <p>我是局部局部组件</p>
                <p>{{age}}----父组件向子传值</p>
            </div>
            `,
        data() {
            return {
                name: 'kangkang',
                age: ''
            }
        }
    }
    var vm = new Vue({
        el: '#app01',
        data: {
            name: '',
            age: 18,
            my_text: ''
        },
        methods: {
            handleClick() {
                // 父向子传值
                this.$refs.my_child.age = this.age
                // 子向父传值
                this.name = this.$refs.my_child.name
            }
        },
        components: {
            child
        }
    })

</script>
</html>

二、动态组件

简介:

​ 动态组件指,在一个页面上有很多按钮,在点击需要的按钮后会展示对应的组件,其他不需要的组件就会收起

1、不使用动态组件

通过绑定事件和简单的逻辑完成

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>动态组件</title>
    <script src="../js/vue.js"></script>
</head>
<body>

<div id="app01">

    <div style="background-color: antiquewhite">
        <div>
            <button @click="handleClick('home')">首页</button>
            ---
            <button @click="handleClick('goods')">商城</button>
            ---
            <button @click="handleClick('order')">订单</button>
        </div>
        <div v-if="page_type=='home'">
            <home></home>
        </div>
        <div v-else-if="page_type=='goods'">
            <goods></goods>
        </div>
        <div v-else="page_type=='order'">
            <order></order>
        </div>
    </div>
</div>
</body>
<script>
    var home = {
        template:
            `<div style="background-color: aqua;width: 500px;height: 500px">我是首页</div>`
    }
    var goods = {
        template:
            `<div style="background-color:palevioletred;width: 500px;height: 500px">我是商城页面</div>`
    }
    var order = {
        template:
            `<div style="background-color:#dbab70;width: 500px;height: 500px">我是订单页面</div>`
    }
    var vm = new Vue({
        el: '#app01',
        data: {
            page_type: 'home'
        },
        methods: {
            handleClick(type) {
                this.page_type = type
            }
        },
        components: {
            home, goods, order
        }
    })
</script>
</html>

2、使用动态组件

简介:

​ 使用动态组件component标签,配合该标签的属性,在属性内填入需要展示的组件就会将该组件展示出来

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>动态组件</title>
    <script src="../js/vue.js"></script>
</head>
<body>

<div id="app01">

    <div style="background-color: antiquewhite">
        <div>
            <button @click="handleClick('home')">首页</button>
            ---
            <button @click="handleClick('goods')">商城</button>
            ---
            <button @click="handleClick('order')">订单</button>
        </div>
        <component :is="who"></component>
    </div>
</div>

</body>
<script>
    var home = {
        template:
            `<div style="background-color: aqua;width: 500px;height: 500px">我是首页</div>`
    }
    var goods = {
        template:
            `<div style="background-color:palevioletred;width: 500px;height: 500px">我是商城页面</div>`
    }
    var order = {
        template:
            `<div style="background-color:#dbab70;width: 500px;height: 500px">我是订单页面</div>`
    }
    var vm = new Vue({
        el: '#app01',
        data: {
            who: 'home'
        },
        methods: {
            handleClick(type) {
                this.who = type
            }
        },
        components: {
            home, goods, order
        }
    })
</script>
</html>

3、keep-alive保持组件不销毁

​ 在上面学习的component标签中,更简介的实现了组件的切换,但是存在一点不足,被切换掉的组件就会被销毁,不会保留浏览和输入的记录,下面用动图进行展示

可以看到,在订单页面输入的内容,被切入其他组件在切回来之后发现内容消失了,如果在日常使用中,就会极大的影响到用户体验,下面将配合keep-alive标签,完成在切换页面后信息不会被清空(组件不会被销毁)

# 其它代码不变,使用keep-alive标签将component标签包裹
    <keep-alive>
        <component :is="who"></component>
    </keep-alive>

三、插槽

简介:

​ 插槽是指,在使用vue生成的局部组件,在应用到全局组件上后,通常内局部组件内部的标签无法在添加其他的标签,只有重新回到局部组件进行编辑,但配合插槽(slot标签)就可以在全局页面上往局部组件中添加标签

1、匿名插槽

​ 匿名插槽是直接放置在局部组件中的标签,该标签在后期使用时,直接将属性定义在要使用的标签上即可使用,因为是匿名插槽所以在一个局部组件中多次使用的时候都只会显示外部编辑的内容(内容相同)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>动态组件</title>
    <script src="../js/vue.js"></script>
</head>
<body>

<div id="app01">

    <div style="background-color: antiquewhite">

        <div>
            <h1>我是全局组件---顶部</h1>
            <home>
                <div slot>
                    我是匿名插槽--第一部分
                </div>
            </home>
            <h1>我是全局组件--尾部</h1>
        </div>

    </div>
</div>

</body>
<script>
    var home = {
        template:
            `<div style="background-color: aqua;width: 500px;height: 500px">
                   <p>我是局部组件--顶部</p>
                   <slot></slot>
                   <p>我是局部组件--中部</p>
                   <slot></slot>
                   <p>我是局部组件--尾部</p>
            </div>`
    }
    var vm = new Vue({
        el: '#app01',
        data: {
            who: 'home'
        },
        methods: {
            handleClick(type) {
                this.who = type
            }
        },
        components: {
            home
        }
    })
</script>
</html>

2、具名插槽

​ 和匿名插槽用法基本一直,但是在定义阶段需要给插槽命名,这样的好处是在外部使用,需要插入数据的时候,需要指定插槽的名称,在指定的插槽内插入内容

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>动态组件</title>
    <script src="../js/vue.js"></script>
</head>
<body>

<div id="app01">

    <div style="background-color: antiquewhite">

        <div>
            <h1>我是全局组件---顶部</h1>
            <home>
                <div slot="a">
                    我是匿名插槽aaaa
                </div>
                <div slot="b">
                    我是匿名插槽bbbb
                </div>
            </home>

            <h1>我是全局组件--尾部</h1>
        </div>

    </div>
</div>

</body>
<script>
    var home = {
        template:
            `<div style="background-color: aqua;width: 500px;height: 500px">
                   <h3>我是局部组件--顶部</h3>
                   <slot name="a"></slot>
                   <h3>我是局部组件--中部</h3>
                   <slot name="b"></slot>
                   <h3>我是局部组件--尾部</h3>
            </div>`
    }
    var vm = new Vue({
        el: '#app01',
        data: {
            who: 'home'
        },
        methods: {
            handleClick(type) {
                this.who = type
            }
        },
        components: {
            home
        }
    })
</script>
</html>

四、计算属性

场景: 一个变量的值, 需要用另外变量计算而得来

语法:

computed: {
    "计算属性名" () {
        return "值"
    }
}

注意:

  • 计算属性和data属性都是变量-不能重名. 用法和data相同

  • 函数内变量变化, 会自动重新计算结果返回

1、计算属性案例展示

例子:

  • 需求:
    • 获取用户输入:用户名和年龄
    • 将用户名的首字母转为大写,将绑定的函数设置返回值展示在页面
    • 在用户输入年龄时不会触发用户名的函数重新计算
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>动态组件</title>
    <script src="../js/vue.js"></script>
</head>
<body>

<div id="app01">

    <div style="background-color: antiquewhite">
        <div>用户名:
            <p><input type="text" v-model="name">---->{{upGet}}</p>
            年龄:
            <p><input type="text" v-model="age">---->{{age}}</p>
        </div>
    </div>
</div>

</body>
<script>
    var vm = new Vue({
        el: '#app01',
        data: {
            name: '',
            age: ''
        },
        computed:{
            upGet(){
                console.log('我被执行了')
                this.name = this.name.slice(0, 1).toUpperCase() + this.name.slice(1)
                return this.name
            }
        }
    })
</script>
</html>

2、通过计算属性重写过滤案例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="../js/vue.js"></script>
</head>
<body>
<div>
    <div class="app">
        <p>请输入要搜索的内容:<input type="text" v-model="myText" @input="handleInput"></p>
        <ul>
            <li v-for="item in newDataList">{{item}}</li>
        </ul>
    </div>

</div>
</body>
<script>
    var vm = new Vue({
        el: '.app',
        data: {
            myText: '',
            dataList: ['a', 'at', 'atom', 'be', 'beyond', 'cs', 'csrf']
        },
        computed: {
            newDataList() {
                return this.dataList.filter(item => item.indexOf(this.myText) >= 0)
            }
        }
    })
</script>
</html>

五、监听属性

场景: 监听的是属性值,当定义的值发生变化时,执行相对应的函数。

语法:

 watch: {
     "被监听的属性名" (参数){     
     }
 }

例子:

  • 需求:

    • 不使用标签绑定事件,监听name属性等于kangkang时使用事件将age属性修改为18
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>
        属性监听
    </title>
    <script src="../js/vue.js"></script>
</head>
<body>
<div id="app01">
    <p>用户名:</p>
    <input type="text" v-model="name">---->{{name}}
    <p>年龄:{{age}}</p>
</div>

<script>
    new Vue({
        el: '#app01',
        data: {
            name: '',
            age: ''
        },
        methods: {
            handleClick() {
                this.age = 18
            }
        },
        watch: {
            name() {
                if (this.name == 'kangkang') {
                    this.handleClick()
                } else {
                    this.age = ''
                }
            }
        }
    })
</script>
</body>
</html>