从零开始学Vue——模板语法

本文详细介绍了Vue模板的基本语法,包括插值操作、动态绑定属性(v-bind、v-once、v-html等)、方法与计算属性、侦听器与滤波器、事件监听、条件渲染、列表渲染以及组件化开发的各个方面。实例演示了如何在实践中应用这些特性,如样式绑定、数据传递和父子组件交互。

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


title: vue-模板语法
date: 2020-09-16 21:27:17
tags: Vue
categories: 前端
githubBlog:Click Me

1.Vue模板语法

1.1插值操作

mustache语法{{expr}}

expr可以是变量,常量,表达式,会自动根据Vue中的data进行渲染

<div id="app">
    <h2>{{message}}</h2>
    <h2>{{message+message}}</h2>
    <h2>{{v*2}}</h2>
    <h2>{{firstName+" "+lastName}}</h2>
    <h2>{{firstName}}{{lastName}}</h2>
</div>

<script src="../js/vue.js"></script>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            message: "test",
            firstName: "hello",
            lastName: "world",
            v: 100
        }
    })
</script>
v-once

此时,数据只从vue中得到数据初始化渲染一次,之后该组件(标签内)的数据不会随着data中的数据变化

<!--v-once作用域是整个标签-->
<div id="app">
    <h2  v-once>{{message}}</h2>
</div>

<script src="../js/vue.js"></script>
<script>
    const vm = new Vue({
        el: '#app',
        data: {
            message: "test",
        }
    })
</script>
v-html

类似于innerHtml(),把数据进行解析后显示

v-text

类似于innerText(),把原数据显示出来

v-pre

忽略mustache直接显示出两个大括号

v-cloak

在Vue渲染html标签前,让被渲染的元素隐藏,不显示原生的{ {} }等语法

1.2动态绑定属性

v-bind

为标签的属性绑定Vue的data值,绑定后属性值将根据这个data动态改变

v-bind可用冒号:代替

<div id="app">
    <!-- 绑定属性的操作 -->
    <img v-bind:src="imgurl" alt="">
    <a :href="url">百度一下</a>
</div>

<script src="../js/vue.js"></script>
<script>
    const vm = new Vue({
        el: '#app',
        data: {
            imgurl: 'https://www.baidu.com/img/flexible/logo/pc/result.png',
            url: 'www.baidu.com'
        }
    })
</script>
动态参数

https://cn.vuejs.org/v2/guide/syntax.html#%E5%8A%A8%E6%80%81%E5%8F%82%E6%95%B0

v-bind绑定class

通过对象绑定

<h2 :class={ 类名1:boolean,类名2:boolean}>vue</h2>
<h2 class="title" :class="{'active': isActive, 'line': isLine}">Hello World</h2>

<script src="../js/vue.js"></script>
<script>
    const vm = new Vue({
        el: '#app',
        data: {
            isActive: true,
            isLine: false
        }
    })
</script>

通过一个对象的形式,若类名对应的值(vue中的data)为true值会为标签绑定class,false则不会,可与原生的class共存。若对象过于复杂,可通过methods或计算属性返回一个对象。

通过数组绑定

<h2 class="title" :class="[类名, 类名,···]">Hello World</h2>
<h2 class="title" :class="[active, line]">Hello World</h2>

类名可以是一个变量,常量,表达式,最终代表需要绑定的类名

v-bind绑定style

利用v-bind:style来绑定一些CSS内联样式。

通过对象绑定

<h1 :style="{属性名:属性值,属性名:属性值,···}">{{massage}}</h1>

<h1 :style="{color:colorStyle,'background-color':bkColorStyle,fontSize:fSize+'px'}">{{massage}}</h1>

属性名可以是小驼峰式,或者短横线分隔式(需单引号括起)

属性值可以是常量,变量,表达式

通过数组绑定

<div v-bind:style="[baseStyles, overridingStyles]"></div>
<script>
    const vm = new Vue({
        el: '#app',
        data: {
            //可以是驼峰式也可以短横线分隔式
            baseStyles: {color:'red','background-color':'gray'},
            overridingStyles: {fontSize:'20px'}
        }
    })
</script>

数组中放的是对象,每个对象代表一个css样式,本质上就是通过对象绑定

1.3方法与计算属性

**方法(methods):**类似于函数,只不过它属于指定的vue对象

**计算属性(computed):**本质上是属性,只是多了getter和setter方法(类似于bean),并且与方法methods相比,具备缓存功能,可以动态监听,当数据改变时才会调用getter

<div id="app">
    <h2>{{fullName}}</h2>
    <h2>{{fullName2}}</h2>
    <!--方法调用必须加上括号(在事件监听时不用)-->
    <h2>{{fullName3()} }</h2>
    <h2>{{fullName4()} }</h2>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script>
    const vm = new Vue({
        el: '#app',
        data: {
            firstName:'Alan',
            lastName:'Turing'
        },
        computed:{
            fullName: {
                // getter
                get: function () {
                    return this.firstName + ' ' + this.lastName
                },
                // setter
                // 当执行vm.fullName = 'John Doe'会被调用
                set: function (newValue) {
                    let names = newValue.split(' ')
                    this.firstName = names[0]
                    this.lastName = names[names.length - 1]
                }
            },
            //当没有set方法时,可简化为如下,并且可省略  :function
            fullName2:function() {
                return (this.firstName+' '+this.lastName).toUpperCase();
            }
        },
        methods:{
            fullName3:function(){
                return this.firstName+' '+this.lastName;
            },
            //可省略  :function
            fullName4(){
                return this.firstName+' '+this.lastName;
            }
        }
    })
</script>

1.4侦听器和滤波器

侦听器:侦听vue实例中的数据变化,一旦数据发生变化就会执行回调函数

<script>
    const vm = new Vue({
        el: '#app',
        data:{
            val=100;
        }
        watch:{
        //如果data中的val发生改变,就会执行下方函数
        val:function(newVal,oldVal){
            console.log(newVal+' '+oldVal);
        }
    })
</script>

滤波器:在输出内容时,给内容添加修饰。

<div id="app">
    <!-- 最终显示 ¥100.00 -->
    <span>总价:{{totalPrice |showPrice } }</span>
</div>
<script>
    const vm = new Vue({
        el: '#app',
        data:{
            totalPrice=100;
        }
        filters:{
        showPrice(totalPrice){
            return "¥"+totalPrice.toFixed(2);
        }
    })
</script>

1.5事件监听

v-on
  • 作用:绑定事件监听器
  • 缩写:@
  • 预期:Function | Inline Statement | Object
  • 参数:event

v-on:click="func1",引号内填写函数名,不带括号时,默认传入一个event,带括号时按正常情况传递参数,当需要传递事件对象时,参数为$event

<div id="app">
    <!-- 点击后会输出mouseEvent-->
    <button v-on:click="func1">按钮1</button>
    <!-- 点击后会输出123 abc-->
    <button @click="func2('123','abc')">按钮2</button>
    <!-- 点击后会输出mouseEvent undefine-->
    <button @click="func2">按钮3</button>
    <!-- 点击后会输出123 mouseEvent-->
    <button @click="func2('123',$event)">按钮4</button>
</div>
<script>
    const vm = new Vue({
        el: '#app',
        methods:{
            func1(param1){
                alert("This is btn1:"+param1) ;
            },
            func2(param1,param2){
                alert("This is btn2:"+param1+' '+param2) ;
            }
        }
    })
</script>
v-on修饰符
  • .stop - 调用 event.stopPropagation()。
  • .prevent - 调用 event.preventDefault()。
  • .{keyCode | keyAlias} - 只当事件是从特定键触发时才触发回调。
  • .native - 监听组件根元素的原生事件。
  • .once - 只触发一次回调。
	<!-- 阻止事件冒泡 -->
    <button @click.stop="doThis">button</button>
    <!-- 阻止默认行为发生,可省略doThis -->
    <form @submit.prevent="doThis" action="url">
        <input type="text">
        <input type="submit">
    </form>
    <!-- 串联修饰符 -->
    <button @click.stop.prevent="doThis">button</button>
    <!-- 键修饰符,指定别名或键代码 -->
    <input type="text"  @keyup.enter="doThis" @keydown.10="doThis" >
    <!-- 触发一次回调 -->
    <button @click.once="doThis">button</button>

关于修饰符的知识还很欠缺,例如不同修饰符顺序引发不同的结果

一些键修饰别名:

  • .enter
  • .tab
  • .delete (捕获 “删除” 和 “退格” 键)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right
  • .ctrl
  • .alt
  • .shift
  • .meta

1.6条件渲染

if、else if、else

这三个指令类似于if、else、else if。Vue的条件指令可以根据表达式的值在DOM中渲染或销毁元素或组件。

<div id="app">
    <h3 v-if="score>=90">Excellent</h3>
    <h3 v-else-if="score>=80">Good</h3>
    <h3 v-else-if="score>=60">Ok</h3>
    <h3 v-else>Fail</h3>
</div>

<script type="text/javascript" src="../js/vue.js"></script>
<script>
    const vm = new Vue({
        el: '#app',
        data:{
            score:90,
        }
    })
</script>
v-show

v-showv-if 的用法类似,都是决定一个页面是否被渲染。

区别:

v-if当条件为false时,压根不会有对应的元素在DOM中。

v-show当条件为false时,仅仅是将元素的display属性设置为none而已。

	当需要在显示与隐藏之间切片很频繁时,使用`v-show`。

	当只有一次切换时,通过使用`v-if`。

1.7列表渲染

v-for
<!--遍历数组-->
<li v-for="value in arr">{{value}}</li>
<li v-for="(value,index) in arr">{{value}}-{{index}}</li>

<!--遍历对象-->
<li v-for="value in obj">{{value}}</li>
<li v-for="(value,key) in obj">{{value}}-{{key}}</li>
<li v-for="(value,key,index) in obj">{{value}}-{{key}}-{{index}}</li>
数组响应式更新

Vue具有数据绑定的功能,因此当vue实例中的数据发生改变时,视图能做出改变响应。

对数组使用如下方法,都会使得视图发生更新

//函数的具体用法有待了解
let arr;
arr.push();
arr.pop();
arr.unshift();
arr.shift();
arr.splice();
arr.sort();
arr.reverse();

唯一需要注意的是使用如下方式1的数组下标赋值的方法,视图并不会发生更新

//方式1
let arr=[{key:value}];
arr[0]={key2:value2};	//视图并不更新
//方式2
let arr2={key:value};
arr2[0].key=value2;	//本质上是修改对象的的属性内容,视图发生更新

//解决方式1视图不更新的两种方式
//通过splice方法为数组赋值,具体用法有待了解
//通过vue自带的方法为数组赋值
Vue.set(this.arr,index,value);

1.8两个练手小案例:

点击绑定样式和购物车

1.9v-model表单绑定

你可以用 v-model 指令在表单 <input><textarea><select> 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。此外input中的value属性也支持v-bind动态绑定。

v-model原理

v-model其实是一个语法糖,它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。它的背后本质上是包含两个操作:

  • 1.v-bind绑定一个value属性
  • 2.v-on指令给当前元素绑定input事件

v-model忽略所有表单元素valuecheckedselected attribute 的初始值而总是将 Vue 实例的数据作为数据来源。你应该通过 JavaScript 在组件的 data 选项中声明初始值。

v-model 在内部为不同的输入元素使用不同的 property 并抛出不同的事件:

  • text 和 textarea 元素使用 value property 和 input 事件;
  • checkbox 和 radio 使用 checked property 和 change 事件;
  • select 字段将 value 作为 prop 并将 change 作为事件。

以下代码等价:

<input type="text" v-model="message">
<input type="text" v-bind:value="message" v-on:input="message = $event.target.value">
文本
<div id="app">
    
    <p>单行文本:Message is: { { message1 } }</p>
    <input v-model="message1" placeholder="edit me">
    <br>
    <hr>
    <span>多行文本: Multiline message is:</span>
    <p style="white-space: pre-line;">{{ message2 } }</p>
    <br>
    <textarea v-model="message2" placeholder="add multiple lines"></textarea>
</div>
<script>
    const vm = new Vue({
        el: '#app',
        data:{
            message1:'' ,
            message2:''
        }
    })
</script>
单选按钮
<div id="app">
    <input type="radio" id="one" value="One" v-model="picked">
    <label for="one">One</label>
    <br>
    <input type="radio" id="two" value="Two" v-model="picked">
    <label for="two">Two</label>
    <br>
    <span>Picked: { { picked } }</span>
</div>
<script>
    const vm = new Vue({
        el: '#app',
        data:{
            picked: '',
        }
    })
</script>

原生的单选按钮中,不同的按钮需要通过一个相同的name来实现互斥,当使用v-model时,可通过绑定同一个value来实现互斥。

复选框
<h3>单个复选框</h3>
<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{{ checked } }</label>

<h3>多个复选框</h3>
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mike</label>
<br>
<span>Checked names: { { checkedNames } }</span>
<script>
    const vm = new Vue({
        el: '#app',
        data:{
            checked:undefined,//初始化时给一个true则默认会被选中,false或其它非布尔值默认不选
            checkedNames: [],
        }
    })
</script>

选择框
   <h3>单个选择框</h3>
    <div>
        <select v-model="option">
            <option disabled value="">请选择</option>
            <option>A</option>
            <option>B</option>
            <option>C</option>
        </select>
        <span>Selected: { { option } }</span>
    </div>
    <h3>多个选择框</h3>
    <div>
        <select v-model="options" multiple style="width: 50px;">
            <option>A</option>
            <option>B</option>
            <option>C</option>
        </select>
        <br>
        <span>Selected: { { options } }</span>
    </div>
<script>
    const vm = new Vue({
        el: '#app',
        data:{
            option:'',
            options: [],
        }
    })
</script>
修饰符
lazy修饰符:
  • 默认情况下,v-model默认是在input事件中同步输入框的数据的。
  • 也就是说,一旦有数据发生改变对应的data中的数据就会自动发生改变。
  • lazy修饰符可以让数据在失去焦点或者回车时才会更新:
number修饰符:
  • 默认情况下,如果希望用户输入数字,原生的input提供了type="number"的用法,但是在输入框中无论我们输入的是字母还是数字,都会被当做字符串类型进行处理。
  • 因此可通过<input v-model.number="age" type="number">
  • v-model 添加 number 修饰符可以让在输入框中输入的内容自动转成数字类型:
trim修饰符:
  • 如果要自动过滤用户输入的首尾空白字符,可以给 v-model 添加 trim 修饰符:<input v-model.trim="msg">

2.组件化开发

组件是可复用的 Vue 实例,且带有一个名字,并且组件相对于Vue来说多了一些例如template模板等功能,template使得组件内部可封装某些标签数据。

2.1.组件使用流程

基本使用
  1. 创建组件对象(最新vue手册中已不使用Vue.extend()创建组件对象了)
  2. 调用Vue.component()方法注册组件
  3. 在Vue实例的作用范围内使用组件
<div id="app">
    <!-- 3.在Vue实例挂载的标签范围内使用组件-->
    <cpn></cpn><!-- 此标签最终会由cpnObj中的template进行渲染-->
</div>
<cpn></cpn>
<script>
    //1.创建组件对象
    //注意template最终必须由一个根标签包含,例如下方根标签为div
    //其中template代表该组件对象的模板,该对象还可有data,methods等属性
    //这是使用Vue.extend方式(过时)
    //通过构造器创建组件对象
	// const cpnObj = Vue.extend({
    //     template:`
    //             <div>
    //                 <h3>我是标题</h3>
    //                 <div>我是内容</div>
    //             </div>
    //     `
    // });
    
    //直接使用javascript对象
    const cpnObj = {
        template:`
                <div>
                    <h3>我是标题</h3>
                    <div>我是内容</div>
                </div>
        `
    };
    //2.将组件对象注册为组件(组件标签,组件对象)
    Vue.component('cpn',cpnObj);
    const vm = new Vue({
        el: '#app',
    });
</script>
语法糖

直接在注册时传入对象参数

<script>
    //将定义组件对象,并注册为组件(组件标签,组件对象)
    Vue.component('cpn',{
        template:`
                <div>
                    <h3>我是标题</h3>
                    <div>我是内容</div>
                </div>
        `
    });
</script>

2.2全局组件和局部组件

全局组件:

凡是以Vue.component()进行注册的都是全局组件,可以在任何挂载了Vue实例的标签内使用

局部组件:

在Vue实例中注册,或在组件中注册为子组件的组件都是局部组件,他们的作用范围限于各自注册的实例(组件)中。

一个组件对象可在不同的作用域中注册为不同的组件

代码实例:

<div id="app">
    <cpn2></cpn2>
    <cpn1></cpn1>
</div>
<script>
    //这是子组件对象,可(同时)在vue实例(或组件)中注册
    const cpnObj1 = {
        template:`
                <div>
                   <h3>标题1</h3>
                </div>
        `
    };
    //第一种:注册成为子组件:
    //1.构造组件2对象时,把组件对象cpnObj1代表的组件添加为组件2的子组件
    const cpnObj2 = {
        template:`
            <div style="color: #ff0000">
                <h3>标题2</h3>
                <cpn1></cpn1>
            </div>
        `,
        components:{
            //组件标签名:组件对象
            cpn1:cpnObj1    //作用域仅在该组件中,(可用语法糖)
        }
    };
    //2.将组件2对象注册为组件(组件标签,组件对象)
    Vue.component('cpn2',cpnObj2);  //全局组件:作用域在任何Vue实例中
	
    //第二种:在Vue实例中注册
    const vm = new Vue({
        el: '#app',
        components:{
            //组件标签名:组件对象
            cpn1:cpnObj1 //作用域仅在该Vue实例中(可用语法糖)
        }
    })
</script>

2.3分离模板

可将组件的template分离出来,单独写在一个标签中

使用script标签

使用script标签包裹template,并给定id,然后在组件对象中引用template的id即可

<script type="text/x-template" id="myCpn">
    <div>
        <h3>这是组件</h3>
    </div>
</script>
<script type="text/javascript" src="../js/vue.js"></script>
<script>
    const cpnObj = Vue.extend()

    const vm = new Vue({
        el: '#app',
        components:{
            cpn: {
              template:'#myCpn'	//引用script中的id
            }
        }
    })
</script>
使用template标签

与script标签相比,不用指定type=“text/x-template”,其余相同

<template id="myCpn">
    <div>
        <h3>这是组件</h3>
    </div>
</template>
<script>
    const cpnObj = Vue.extend()

    const vm = new Vue({
        el: '#app',
        components:{
            cpn: {
              template:'#myCpn'
            }
        }
    })
</script>

2.4组件data

问题引入:组件也是一个Vue实例,意味着组件也可以有自己的data,那么当组件标签使用多次时,每个组件标签引用的是同一个data,这样是明显不合理的,即在组件复用的时候,它们应该引用不同的data对象。

解决方法:Vue强制规定在组件中必须把data写成函数的形式,并且该函数返回一个对象来作为该组件的data,利用函数的作用域来让每个组件标签引用不同的数据对象。

每一次使用组件,function中都会有一个对象被创建并赋值给data

code

<div id="app">
    <cpn></cpn>
</div>
<template id="myCpn">
    <div>
        <h3>这是组件:{{msg}}</h3>
    </div>
</template>
<script>
    const vm = new Vue({
        el: '#app',
        components:{
            cpn:{
                //此处的组件对象中的data使用的是函数
                data(){
                    return {
                        msg:'message'
                    }
                },
                template: '#myCpn'
            }
        }
    })
</script>

2.5父子组件的数据传递

子组件是无法访问父组件或Vue实例中的数据的,而在实际的开发中,常常需要把父组件的数据传递给子组件使用,因此Vue提供了父子组件间传递数据的方法。

值得注意的是:当一个组件1在某个组件2内部注册为局部组件后不代表该组件1就是组件2的子组件了,只能说明组件1是作用在组件2内部的局部组件。

判断是否为一个组件的子组件看的是在template标签中是否嵌套使用了组件标签,例如在挂载了vue实例的div中使用组件标签cpn,此时cpn就是vue的子组件

父组件=>子组件 props

父组件(Vue实例)把数据传递给子组件中的props属性。

  1. 在子组件中的props中声明自己的属性(prop),用于接收父组件传递的数据

  2. 在使用该子组件标签时,为该子组件的prop属性赋值或动态绑定变量

<div id="app">
    <!-- 在使用组件时给attr1 prop赋值-->
    1:<cpn attr1="attribute1"></cpn>
    <!-- 在使用组件时给attr2 prop动态绑定为vue实例中的val-->
    2:<cpn :attr2="val"></cpn>
</div>
<template id="myCpn">
    <div>
        <h3>这是属性1:{{attr1}}</h3>
        <h3>这是属性2:{{attr2}}</h3>
    </div>
</template>
<script>
    const vm = new Vue({
        el: '#app',
        data:{
            val:'attribute2'
        },
        components:{
            cpn:{
                template: '#myCpn',
                //声明属性,有数组和对象两种形式,此处是数组
                props:['attr1','attr2'] //属性以字符串形式书写
            }
        }
    });
</script>

当需要对传入子组件中的prop进行类型验证或默认值等操作时,就需要采用对象语法,实例如下

<div id="app">
    <!-- 在使用组件时给attr1 prop赋值,类型必须是Number因此必须动态绑定-->
    1:<cpn :attr1="num"></cpn>
    <!-- 在使用组件时给attr2 prop动态绑定为vue实例中的val-->
    2:<cpn :attr2="val"></cpn>
</div>
<template id="myCpn">
    <div>
        <h3>这是属性1:{{attr1}}</h3>
        <h3>这是属性2:{{attr2}}</h3>
    </div>
</template>
<script>
    const vm = new Vue({
        el: '#app',
        data:{
            val:'DeliveredParameter',
            num:10
        },
        components:{
            cpn:{
                template: '#myCpn',
                //声明属性:对象形式
                props:{
                    attr1:{
                        type: Number,
                        //表示这个属性attr1在使用组件时必须传递参数
                        //required: true	
                    },
                    attr2:{
                        type: String,
                        default(){  //此处因该使用函数
                            return 'DefaultString';
                        }
                    }
                }
            }
        }
    });
</script>

支持的数据验证类型:验证都支持哪些数据类型呢?String,Number,Boolean,Array,Object,Date,Function,Symbol

子组件=>父组件 $emit

子组件通过触发自定义事件传递数据

父组件(Vue实例)则通过v-on监听子组件触发的事件,并从参数中获得数据。

<div id="app">
    <!--此处的自定义事件出来函数不应该加括号,vue会自动传递参数,只需在method中接收即可-->
    <cpn @my-event="handler"></cpn>
</div>
<template id="myCpn">
    <div>
        <!--此处是普通的v-on-->
        <button @click="BtnClick()">Click me!</button>
    </div>
</template>
<script>
    const vm = new Vue({
        el: '#app',
        data:{
            val:'DeliveredParameter',
        },
        methods:{
            handler(val){
                console.log('handler is done:'+val);
          }
        },
        components:{
            cpn:{
                template: '#myCpn',
                //声明属性:对象形式
                props:{
                    attr:{
                        type: String,
                        default(){  //此处因该使用函数
                            return 'DefaultString';
                        }
                    }
                },
                methods:{
                    BtnClick(){
                        //子组件通过$emit触发自定义事件myEvent,并传递参数attr
                        this.$emit('my-event',this.attr);
                    }
                }
            }
        }
    });
</script>

2.6父子组件的相互访问

有时候,在父组件内可能会出现引用子组件中某个函数或变量的情况,vue提供了三个变量来实现父子组件间的相互访问。

父组件访问子组件: c h i l d r e n 或 children或 childrenrefs

子组件访问父组件:$parent

子组件访问根组件:$root

代码示例:

<div id="app">
    <cpn></cpn>
    <cpn></cpn>
</div>
<template id="tem1">
    <div>
        <h3>I am son</h3>
        <ccpn></ccpn>
        <ccpn></ccpn>
    </div>
</template>
<template id="tem2">
    <div>
        <h3>I am grandson</h3>
    </div>
</template>
<script>
    const vm = new Vue({
        el: '#app',
        data:{
            val:'I am root',
        },
        methods:{
            func1(){
                //this.$children代表当前组件(Vue实例)下的所有子组件(Vue component)
                console.log(this.$children[0].val);
          }
        },
        components:{
            cpn:{
                template: '#tem1',
                data(){
                  return{
                      val: 'I am son'
                  }
                },
                methods:{
                    func1(){
                        //this.$parent代表当前组件的父组件Vue
                        console.log(this.$parent.val);
                    }
                },
                //声明属性:对象形式
                components: {
                    ccpn:{
                        template: '#tem2',
                        data() {
                            return {
                                val: 'I am grandson'
                            }
                        },
                        methods:{
                            func1(){
                                //this.$root代表当前组件的根组件Vue实例
                                console.log(this.$root.val);
                            }
                        }
                    },
                }
            },
        }
    });
</script>

采用$children形式得到的是包含所有子组件的数组,并且索引与顺序有关

由于组件标签中同一级别的标签数量和标签可能发生变化,因此这种方法显然在修改时不太容易。

r e f s 就 可 避 免 这 个 问 题 t h i s . refs就可避免这个问题this. refsthis.refs得到的是一个包含所有子组件的对象, r e f s 使 用 时 只 需 要 为 每 个 子 组 件 指 定 一 个 键 , r e f = " i d " , 然 后 父 组 件 再 引 用 时 采 用 t h i s . refs使用时只需要为每个子组件指定一个键,ref="id",然后父组件再引用时采用this. refs使ref="id"this.refs.id即可访问子组件

<div id="app">
 <cpn ref="first"></cpn>
 <cpn ref="second"></cpn>
</div>
<script>
	const vm = new Vue({
     el: '#app',
     data: {
         val: 'I am root',
     },
     methods: {
         func1() {
             console.log(this.$refs.first);
         }
     },
 }
</script>

2.7slot插槽

基本插槽

在编写组件模板的时候,会出现两个模板高度相似的情况,为了更好的复用模板,vue提出了在组件模板中引入插槽slot。slot标签内表示预留一个位置可供其它html代码或组件插入。提高了组件的复用性和可扩展性。

<div id="app">
    <cpn></cpn><!-- 插槽内容为默认的button -->
    <cpn><span>自定义内容1</span></cpn><!-- 插槽内容为自定义span -->
</div>

<template id="tem1">
    <div>
        <h3>我是组件</h3>
        <!-- slot标签内容为空,表示不提供默认内容 -->
        <slot><button>默认内容</button></slot>
    </div>
</template>

若组件cpn的template没有包含一个 <slot> 元素,则该组件起始标签和结束标签之间的任何内容都会被抛弃(即cpn标签内部内容无效)。

该插槽跟模板的其它地方一样可以访问相同的实例 property (也和vue组件拥有相同的“作用域”)

具名插槽

当一个模板中需要有多个插槽的时候,如果在使用的时候vue默认把cpn标签的内容区替换每个v-slot标签,这个时候就需要为每个插槽指定名称,并在使用时注明。

<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <!-- 一个不带name的<slot>出口会带有隐含的名字“default”-->
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>

在向具名插槽提供内容的时候,我们可以在一个 <template> 元素上使用 v-slot 指令,并以 v-slot 的参数的形式提供其名称:v-slot可缩写为#,使用缩写时必须带上插槽名,例如default

<base-layout>
  <template v-slot:header>
    <h1>Here might be a page title</h1>
  </template>
  <!-- 任何没有被包裹在带有 v-slot 的 <template> 中的内容都会被视为默认插槽的内容。 
	下面的两个p标签也可包裹在<template v-slot:default><template>标签里
-->
  <p>A paragraph for the main content.</p>
  <p>And another one.</p>

  <template #:footer>
    <p>Here's some contact info</p>
  </template>
</base-layout>
作用域插槽

由于组件的编译作用域原因,父组件中无法访问子组件的数据,意味着当父组件向子组件中的slot中插入内容时无法访问到子组件中的数据。

为了解决这一问题,vue提供了作用域插槽,即在为每个实例slot绑定一个function,在把子组件的数据传递到该function的作用域中,实现了每个插槽都有自己单独的作用域。

本质上是:为每个实例的slot标签提供一个作用域,子组件可把数据绑定到slot作用域里,然后父组件在往slot中插入东西时,可以访问slot作用域中的数据。

CODE

<div id="app">
    <!--  没有插入时 插槽显示默认内容-->
    <cpn></cpn>
    <!--  将template标签内容作为插槽内容插入 -->
    <cpn>
        <!--  此处为该slot命名一个作用域myScope,并根据作用域名访问v-bind:绑定的val(实际上是user的别名)-->
        <template v-slot:default="myScope"> 
            <span>自定义显示年龄:{{myScope.val.age}}</span>
        </template>
    </cpn>
</div>

<template id="tem1">
    <div>
        <h3>我是组件</h3>
        <!--  v-bind:此处把子组件data()中的user绑定到slot实例作用域,并取名为val-->
        <slot v-bind:val="user"><span>默认显示子组件data()中的user.name(姓名):{{user.name}}</span></slot>
    </div>
</template>

<script>
    const vm = new Vue({
        el: '#app',
        components:{
            cpn:{
                template: '#tem1',
                data(){
                  return{
                      user: {
                          name:'Qian',
                          age:21,
                      }
                  }
                },
            },
        }
    });
</script>
独占插槽

当被提供的内容只有默认插槽时,组件的标签才可以被当作插槽的模板来使用,不需要被template标签包裹。这样我们就可以把 v-slot 直接用在组件上:

<current-user v-slot:default="slotProps"> 
  { { slotProps.user.firstName } }
</current-user>
<!-- 其中的:default可以省略 -->

当组件内有多个插槽时,为所有的插槽使用完整的基于 <template> 的语法:即每个插槽内容均包裹于template,且指定v-slot:default(othername)

附(一):参考:

阿清博客:https://aqingya.cn/articl/92af846d.html

官网文档:https://cn.vuejs.org/v2/guide/

附(二)快捷键:

"string".log +tab = console.log("string")

div#a + tab = <div id="a"></div>
div.b + tab  = <div class="b"></div>
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值