【Vue学习】基础语法(四)

本文详细介绍了Vue.js中v-model指令的使用,包括其基本原理、与不同表单元素的结合以及修饰符的应用。同时,文章深入探讨了Vue的组件化开发,包括组件的创建、注册、使用,以及父子组件间的通信方法,如props和自定义事件。此外,还讨论了组件数据存放和访问策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

七. v-model 的使用

  • Vue中使用v-model指令来实现表单元素和数据的双向绑定
1.v-model的基本使用及原理
<!-- 改变输入框内值或message的值,另一值都会相应改变 -->
<body>
    <div id="app">
        <!-- <input type="text" v-model="message"> -->
        <!-- <input type="text" :value="message" @input="valueChange"> -->
        <input type="text" :value="message" @input="message = $event.target.value">
        <h2>{{message}}</h2>     
    </div>

    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                message : '你好啊',
            },
            methods: {
                valueChange(event) {
                    this.message = event.target.value;
                }
            },
        })
    </script>
</body>

v-model的原理

  • 通过v-bind动态绑定输入框内的value属性,实现改变message的值的同时输入框内值也随之改变(单向绑定),再通过v-on监听input事件event绑定valueChange方法来实现改变输入框内的值的同时message值也随之改变(简便方法:引号内写表达式,通过$来直接获取当前事件)
2.v-model与其它类型的结合使用
1.结合radio类型(单选按钮)
<body>
    <div id="app">
        <label for="male">
            <input type="radio" name="sex" id="male" value="" v-model="sex"></label>   
        <label for="female">
            <input type="radio" name="sex" id="female" value="" v-model="sex"></label> 
        <h2>您选择的性别是:{{sex}}</h2>
    </div>

    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                message : '你好啊',
                sex : '男',
            }
        })
    </script>
</body>
  • 注意:
    • 当两标签用v-model绑定的是同一变量时,name属性(保证标签互斥)可省略不写
2.结合checkbox类型(复选框)
<body>
    <div id="app">

        <!-- 1.checkbox单选框 -->
        <!-- <label for="license">
            <input type="checkbox" id="license"  v-model="isAgree">同意协议
        </label>   
        <h2>您选择的是:{{isAgree}}</h2>
        <button :disabled="!isAgree">下一步</button> -->

        <!-- 2.checkbox多选框 -->
        <input type="checkbox" value="御姐" v-model="favorites">御姐
        <input type="checkbox" value="萝莉" v-model="favorites">萝莉
        <input type="checkbox" value="青春" v-model="favorites">青春
        <input type="checkbox" value="成熟" v-model="favorites">成熟
        <h2>您希望您的另一半是:{{favorites}}</h2>
    </div>

    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                message : '你好啊',
                isAgree : false, //单选框,布尔值
                favorites : [], //多选框, 数组
            }
        })
    </script>
</body>
3.结合select类型(下拉选项)
<body>
    <div id="app">
    
        <!-- 1.只能选择一个  -->
        <select name="aaa" v-model="fruit">
            <option value="苹果">苹果</option>
            <option value="香蕉">香蕉</option>
            <option value="葡萄">葡萄</option>
            <option value="榴莲">榴莲</option>
        </select>
        <h2>您选择的水果是:{{fruit}}</h2>

        <!-- 2.可选择多个 -->
        <!-- 按Ctrl键多选 -->
        <select name="aaa" v-model="fruits" multiple>
            <option value="苹果">苹果</option>
            <option value="香蕉">香蕉</option>
            <option value="葡萄">葡萄</option>
            <option value="榴莲">榴莲</option>
        </select>
        <h2>您选择的水果是:{{fruits}}</h2>
    </div>

    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                message : '你好啊',
                fruit : '榴莲',
                fruits : [],
            }
        })
    </script>
</body>
3.值绑定(动态的给value赋值)
  • 之前value中的值都是在定义input时直接给定的,但是在真实开发中,这些input的值可能是从网络获取或定义在data中的,所以我们可以通过v-bind:value动态的给value绑定值
<body>
    <div id="app">
        <label v-for="item in originFavorites" :for="item">
            <input type="checkbox" :value="item" :id="item" v-model="favorites">{{item}}
        </label>
        <h2>您希望您的另一半是:{{favorites}}</h2>
    </div>

    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                message : '你好啊',
                favorites : [],
                originFavorites : ["御姐","萝莉","青春","成熟"]
            }
        })
    </script>
</body>
4.修饰符
<div id="app">
        <!-- 1.lazy修饰符 -->
        <input type="text" v-model.lazy="message">
        <h2>{{message}}</h2> 
        
        <!-- 2.number修饰符 -->
        <input type="number" v-model.number="age">
        <h2>{{age}}-{{typeof age}}</h2>

        <!-- 3.trim修饰符 -->
        <input type="text" v-model.trim="name">
        <h2>那输入的名字为:{{name}}</h2>
    </div>

    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                message : '你好啊',
                age : 18,
                name : ''
            }
        })
    </script>
1.lazy修饰符(v-model.lazy)
  • 默认情况下,v-model 默认是在 input 事件中同步输入框中的数据的,一旦有数据发生改变对应的data中的数据也会自动发生改变,而lazy修饰符可以让数据在失去焦点或者回车时才会更新。
2.number修饰符(v-model.number)
  • 默认情况下,在输入框中输入的数字或字母都会被当做字符串处理,但是如果我们希望处理的是数字类型,那么最好直接将内容当做数字处理,而number修饰符可以让输入框输入的内容自动转成数字类型。
3.trim修饰符(v-model.trim)
  • 如果输入内容首尾有多个空格,通常我们希望将其去除,trim修饰符可以过滤内容左右两边的空格。

八.组件化开发

1.组件化思想及基本步骤
  • 组件化是Vue.js中的重要思想,提供一种抽象,让我们可以开发出一个个独立可复用的小组件来构建我们的应用,任何应用都会被抽象成一颗组件树。
  • 基本步骤:
    创建组件构造器(调用Vue.extend()方法)
    注册组件(调用Vue.component()方法)
    使用组件(在Vue实例的作用范围内使用)
2.全局组件和局部组件
  • 调用Vue.component()方法注册的组件为全局组件,可以在多个Vue的实例下使用。
  • 若想要注册的组件为局部组件,需在对应的Vue实例中增加components属性(将注册组件挂载在某个实例中)
<body>
    <div id="app">
        <!-- 3.组件的基本使用(必须在Vue实例的作用范围内使用) -->
        <cpn></cpn>    
        <cpn></cpn>    
        <cpn></cpn>    
        <cpn></cpn>    
    </div>

    <div id="app2">
        <cpn></cpn>
    </div>
    
    <script src="../js/vue.js"></script>
    <script>
        //1.创建组件构造器对象
        const cpnC = Vue.extend({
            template:`
            <div>
                <h2>我是可复用的组件</h2>
                <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Expedita, harum! Corrupti inventore voluptatem eius optio in excepturi quidem numquam illum, non illo sint cum ab soluta praesentium animi, nihil vel.</p>
                <p>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Doloremque laboriosam voluptate eum temporibus praesentium quo nesciunt eveniet rerum odio modi eius dolor atque sint ratione necessitatibus est, placeat veritatis amet.</p>
            </div>`
        })

        //2.注册组件(全局组件)
        //Vue.component('cpn', cpnC)

        const app = new Vue({
            el: '#app',
            data: {
                message : '你好啊',
            },
            //局部组件
            components: {
                //形式: "使用组件时的标签名: 组件构造器名"
                cpn: cpnC
            }
        })

        const app2 = new Vue({
            el: '#app2',
        })
    </script>
</body>
3.父组件和子组件
<!-- Vue实例 -->
<div id="app">
    <cpn2></cpn2>
    <!-- <cpn1></cpn1> 会报错-->
</div>

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

    //创建第一个组件构造器(子组件)
    const cpnC1 = Vue.extend({
        template:`
        <div>
            <h2>我是标题一</h2>    
            <p>hahahaha</p>
        </div>`
    })

    //创建第二个组件构造器(父组件)
    const cpnC2 = Vue.extend({
        template:`
        <div>
            <h2>我是标题二</h2>    
            <p>emememem</p>
            <cpn1></cpn1>
        </div>`,
        components: {
            cpn1: cpnC1
        }
    })

    const app = new Vue({
        el: '#app',
        data: {
            message : '你好啊',
        },
        components: {
            cpn2: cpnC2,
            // cpn1: cpnC1  解决办法
        }
    })
</script>
  • 注意:
  • 错误用法:以子标签的形式在Vue实例中使用。如:在Vue实例中添加该行时,会报错。这是因为当子组件注册到父组件的components时,Vue会编译好父组件的模块,相当于父组件中已经有子组件中的内容了,子标签是只能在父组件中被识别的。
  • 解决办法: 想要子标签也生效,需在Vue实例的组件中注册该标签 cpn1: cpnC1
4.注册组件的语法糖
  • 在上面注册组件的方式,可能会有些繁琐。Vue为了简化这个过程,提供了注册的语法糖。
  • 主要是省去了调用Vue.extend()的步骤,而是直接使用一个对象来代替。
<body>
    <div id="app">
        <cpn1></cpn1>  
        <cpn2></cpn2>  
    </div>
    <script src="../js/vue.js"></script>
    <script>
        //1.注册全局组件的语法糖
        Vue.component('cpn1', {
            template:`
            <div>
                <h2>我是标题一</h2>    
                <p>hahahaha</p>
            </div>`
        })

        const app = new Vue({
            el: '#app',
            data: {
                message : '你好啊',
            },
            //2.注册局部组件的语法糖
            components:{
                'cpn2': {
                    template:`
                    <div>
                        <h2>我是标题二</h2>    
                        <p>emememem</p>
                    </div>`
                }
            }
        })
    </script>
</body>
5.template模板的分离写法
  • 将其中的html代码分离出来,然后用 id 挂载到对应组件上,使结构更加清晰。
  • Vue提供了两种方案:
    ①使用
<body>
    <div id="app">
        <cpn></cpn>
    </div>

    <!-- 模板分离写法1.script标签,注意:类型必须为text/x-template -->
    <!-- 
    <script type="text/x-template" id="cpn">
    <div>
        <h2>我是标题一</h2>    
        <p>hahahaha</p>
    </div>
    </script> -->

    <!-- 模板分离写法2.template标签 -->
    <template id="cpn">
        <div>
            <h2>我是标题二</h2>    
            <p>emememem</p>
        </div>
    </template>


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

        //1.注册一个全局组件
        Vue.component('cpn',{
            template: '#cpn'
        })
        const app = new Vue({
            el: '#app',
            data: {
                message : '你好啊',
            }
        })
    </script>
</body>
6.组件中的数据存放问题
  • 组件不可以访问Vue实例数据。
  • 组件是一个有单独功能模板的封装,这个模块有属于自己的HTML模板和数据data。
  • 组件对象也有一个data属性,但该属性必须是一个函数,并且该函数返回一个内部保存着数据的对象,函数每次返回一个新对象,保证各组件互不影响。
<body>
    <div id="app">
        <cpn></cpn>
    </div>
    
    <template id="cpn">
        <div>
            <h2>{{title}}</h2>    
            <p>emememem</p>
        </div>
    </template>

    <script src="../js/vue.js"></script>
    <script>
        Vue.component('cpn',{
            template: '#cpn',
            data() {
                return {
                    title: '我是标题'
                }
            }
        })
        const app = new Vue({
            el: '#app',
            data: {
                message : '你好啊',
            }
        })
    </script>
</body>
7.父子组件的通信
  • 之前提过,子组件不能引用父组件或Vue实例的数据,但是在开发中,往往一些数据需要从上层传递到下层,例如在一个页面中,我们从服务器请求到的很多数据中有一部分,并非是我们整个页面的大组件来展示的,而是需要下面的子组件进行展示。这时并不会让子组件再次发送一个网络请求,而是直接让大组件(父组件)将数据传递给小组件(子组件)。

  • 如何进行父子间通信?

    1.通过props向子组件传递数据;
    2.通过自定义事件$emit向父组件发送消息

7.1 父组件向子组件传递数据(props)

*props基本用法 *

  • 在组件中,使用props来声明需要从父级接收到的数据。其属性名不能使用驼峰标识(小大写),中间使用“-”隔开
  • props的值有两种方式:
    1.字符串数组,数组中的字符串就是传递时的名称。
    2.对象,对象可以设置传递时的类型,也可以设置默认值等。
	<div id="app">
        <cpn v-bind:cmovies="movies" :cmessage="message"></cpn>    
    </div>

    <template id="cpn">
        <div>
            <ul>
                <li v-for="item in cmovies">{{item}}</li>
            </ul>
            <h2>{{cmessage}}</h2>
        </div>
    </template>

    <script src="../js/vue.js"></script>
    <script>
        //父传子:props
        const cpn = {
            template:'#cpn',
            // 1.字符串数组
            // props: ['cmovies','cmessage'],

            // 2.对象
            props: {
                //1.可以进行类型限制
                // c-movies: Array,

                //2.也可以提供默认值,或设置其是否为必须传入的值
                cmessage:{
                    type:String,
                    default:'aaaaaa',
                    required: true 
                },
                // 类型是对象或者数组时,默认值必须是一个函数
                cmovies: {
                    type: Array,
                    default(){
                        return []
                    }
                }
            },
            data() {
                return {}
            }
        }

        const app = new Vue({
            el: '#app',
            data: {
                message : '你好啊',
                movies :['海贼王','海王','海尔兄弟']
            },
            components:{
                // 'cpn' : cpn
                // 增强写法
                cpn
            }
        })
    </script>
7.2 子组件向父组件传递数据(自定义事件)
  • 之前学过的v-on不仅仅可以用来监听DOM事件,也可以用于组件间的自定义事件。
  • 自定义事件流程:在子组件中,通过**$emit()来触发事件;在父组件中,通过v-on**来监听子组件事件。
<body>
    <!-- 父组件模板 -->
    <div id="app">
        <cpn @item-click="cpnClick"></cpn>
    </div>

    <!-- 子组件模板 -->
    <template id="cpn">
        <div>
            <button v-for="item in categories" 
                    @click="btnClick(item)">
                {{item.name}}
            </button>
        </div>
    </template>

    <script src="../js/vue.js"></script>
    <script>
        // 子组件
        const cpn = {
            template:'#cpn',
            data(){
                return {
                    categories: [
                        {id: 'aaa', name: '热门推荐'},
                        {id: 'bbb', name: '手机数码'},
                        {id: 'ccc', name: '家电家器'},
                        {id: 'ddd', name: '电脑办公'},
                    ]
                }
            },
            methods: {
                btnClick(item) {
                    //发射自定义事件
                    this.$emit('item-click',item)
                }
            },
        }    
        // 父组件
        const app = new Vue({
            el: '#app',
            data: {
                message : '你好啊',
            },
            components:{
                cpn
            },
            methods: {
                cpnClick(item) {
                    console.log("cpnClick",item);
                }
            }
        })
    </script>
</body>
7.3 父子组件的访问方式
  • 父组件访问子组件:使用 $children 或 ** $refs** (reference引用)
  • 子组件访问父组件:使用 $parent
7.3.1 $children 的访问(父访问子)
  • this.$children是一个数组类型,包括所有子组件对象。
  • 这里我们通过一个遍历,取出所有子组件的message状态。
<div id="app">
     <cpn></cpn>
     <cpn></cpn>
     <cpn ref="aaa"></cpn>
     <button  @click="btnClick">按钮</button>
</div>

<template id="cpn">
    <div>我是子组件</div>

</template>

<script src="../js/vue.js"></script>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            message : '你好啊',
        },
        methods: {
            btnClick() {
                //1.$children
                // console.log(this.$children);
                // for(let c of this.$children) {
                //     console.log(c.name);
                //     c.showMessage();
                // }

                //2.$refs(常用) => 对象模型,默认为一个空对象 ref='aaa'
                console.log(this.$refs.aaa)
            }
        },
        components: {
            cpn: {
                template: '#cpn',
                data() {
                    return{
                        name: '我是子组件的name'
                    }
                },
                methods: {
                    showMessage() {
                        console.log('showMessage');
                    }
                },
            }
        }
    })
</script>
7.3.2 $parent 的访问(子访问父)
  • 为保证组件的可复用,开发中不建议使用。
<div id="app">
    <cpn></cpn>
</div>

<template id="cpn">
   <div>
        <ccpn></ccpn>
   </div>
</template>

<template id="ccpn">
   <div>
        <h2>我是子组件</h2>
        <button @click="btnClick">按钮</button>
   </div>
</template>

<script src="../js/vue.js"></script>
<script>
   const app = new Vue({
       el: '#app',
       data: {
           message : '你好啊',
       },
       components: {
           cpn: {
               template: '#cpn',
               data(){
                return {
                    name: '我是cpn组件的name'
                }
               },
               components: {
                   ccpn: {
                      template: '#ccpn',
                      methods: {
                        btnClick(){
                            // 1.访问父组件$parent
                            console.log(this.$parent);
                            console.log(this.$parent.name);

                            //2.访问根组件$root
                            console.log(this.$root);
                            console.log(this.$root.message);
                        }
                    }
                   }
               }
           }
       }
   })
</script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值