初识 Vue

一、安装

CDN

开发环境:<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
生产环境:<script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>

脚手架工具(vue-cli)

  1. 快速原型开发:npm install -g @vue/cli-service-global
  2. 创建一个项目:vue create hello-world (选择默认)
  3. 启动项目:npm run serve

二、相关概念区分(☆☆☆☆)

(一)createdmounted 的区别

created:在模板渲染成html前调用,即通常初始化某些属性值,然后在渲染成视图。
mounted:在模板渲染成html后调用,通常初始化页面完成后,再对 html 的 dom 节点进行一些需要的操作。

(二)computedmethods 的区别

  1. computed:只有在它的相关依赖发生改变时才会重新求值。哪一个改变哪一个渲染,其他的不受影响。
  2. methods:无论哪一个改变,methods 调用总会执行所有函数。

(三)watch 数据选项和 $watch 的区别

  1. $watch 有返回值,可以用于停止触发回调。
// $watch 会返回一个函数 , 调用该函数可以取消观察
const unwatch = vm.$watch('a', function (val, oldVal) {
      if (val === 10) {
            unwatch(); // 执行函数取消观察
       }
       this.message = 'a的旧值为' + oldVal + ',新值为' + val;
})
  1. watch 用于数据观察,观测数据的变化

(四)v-if 指令和 v-show 的区别

  1. 语法:v-if="completed"
  2. v-if:是真正的渲染,若数据 completed 是 false,则根本不会渲染到页面上。
  3. 语法:v-show="completed"
  4. v-show:无论怎样都会渲染到页面,只是数据 completed 为 false 时,该元素有个 display 属性的值为 none

三、Vue常用指令

  1. v-bind:动态绑定属性
 <!-- v-bind:属性名 的缩写方式为 :属性名 -->
<div v-bind:title="one" :class="two">动态绑定属性</div>
  1. v-once:控制数据只在第一次的时候渲染
  2. v-cloak
  3. v-on:绑定事件
    <div id="app">
     	<!-- v-on:属性名 的缩写方式为 @事件类型 -->
        <p v-on:click="one" @mouseenter="two">this is a test</p>
    </div>
  1. v-model:数据双向绑定

四、Vue

概念

Vue 是一套用于构建用户界面的渐进式框架。被设计为可以自底向上逐层应用,核心库只关注视图层。是一个MVVM 类型的框架

什么是渐进式框架?

Declarative Rendering(声明式的呈现) — Component System(构建系统) — Client-Side Routing(客户端路由) — Large Scale State Management(大规模状态管理) — Bulid System(建造系统)

模板插值

  1. 语法:{{message}} message 相当于一个变量或占位符,最后展示的是真正的文本内容。
  2. 方式
1)文本:最基本的渲染方式,数据是什么样,渲染到页面中就是什么样。

<body>
    <div id="app">
        my name is {{ name }}
    </div>
    <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
    <script>
        const vm = new Vue({
            el: '#app',
            data: {
                name: 'yangqian'
            }
        })
    </script>
</body>
2)v-once指令:数据只在第一次的时候被渲染,之后改变数据页面不会再重新渲染。

<body>
    <div id="app">
        <p>my name is {{ name }}</p>
        <p v-once>my name is {{ name }}</p>
    </div>
    <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                name: 'xiejie'
            }
        })
    </script>
</body>
3)原始HTML(v-html 指令):要渲染的数据含有 html 标签,在渲染的时候也会原样输出。如果要作为 html 代码进行渲染,可以添加指令 v-html

<body>
    <div id="app">
        <!-- 第一行会原样输出 , 第二行可以作为 HTML 渲染出来 -->
        <div>{{htmlCode}}</div>
        <div v-html="htmlCode"></div>
    </div>
    <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                htmlCode: '<span style="color:red">this is a test</span>'
            }
        })
    </script>
</body>
4)特性(v-bind指令)

<body>
    <div id="app">
        <div v-bind:title="one" v-bind:class="two">动态绑定属性</div>
    </div>
    <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                one: 'this is a title',
                two: 'topContent abc'
            }
        })
    </script>
</body>
5)动态参数:用方括号括起来的 JavaScript 表达式作为一个动态参数,增大了属性或事件的灵活性。

<body>
    <div id="app">
        <!-- 这里为 span 绑定了一个动态事件 , 具体是什么事件取决于 abc 的值 -->
        <span v-on:[abc]="test2">动态参数</span>
    </div>
    <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                abc: 'mouseenter'
            }
        })
    </script>
</body>

<!-- 动态参数 abc 的值决定了绑定的事件的类型 -->
6)JavaScript表达式:需要注意的是模板中每个绑定的占位符都只能包含单个表达式

<body>
    <div id="app">
        <p>{{ number + 1 }}</p>
        <p>{{ ok ? 'YES' : 'NO' }}</p>
        <p>{{ message.split('').reverse().join('') }}</p>
        <div v-bind:id="'list-' + id"></div>
    </div>
    <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                number: 1,
                ok: true,
                message: 'this is a test',
                id: 1
            }
        })
    </script>
</body>

构造器

1.每个 Vue 应用都是通过构造函数 Vue 来创建一个 Vue 根实例。
2.实例化 Vue 时,传入的选项对象可以包含 数据、模板、挂载元素、方法、生命周期 等选项。

Vue的实例属性($el)与方法($watch

$el:表示被挂载的元素
$watch:监听数据的变化

Vue的生命周期(☆☆☆☆)

  1. 概念
    每个Vue 实例在被创建时都要经过一系列的初始化过程。在这个过程中也会运行一些叫做生命周期的钩子函数
  2. 生命周期的钩子函数
    (1)beforeCreate:实例开始初始化时同步调用
    (2)created:实例创建之后调用
    (3)beforeMount:mounted 之前运行
    (4)mounted:编译结束时调用
    (5)beforeUpdate:实例挂载之后,再次更新实例时
    (6)updated:实例挂载之后,再次更新实例并更新完DOM结构后
    (7)beforeDestroy:开始销毁实例时
    (8)destroyed:实例销毁之后

计算属性和方法

(一)computed

  1. 计算属性对应的数据选项为 computed,类似于 datadata 对应的是一个值,而计算属性对应的是一个方法。在方法里面可以进行复杂的计算,然后将结果返回。
  2. 计算属性的值依赖于数据,如果数据发生变化,计算属性也会发生变化。
  3. 计算属性可对数据进行二次处理。

(二)方法

Vue实例中的 数据选项 methods,用来书写方法(鼠标事件、自定义事件等)

数据观察

语法:watch{key:function(){}}
:需要观察的 data 数据。:对应的一个回调函数

修饰符

(一)事件修饰符

  1. Vue 为 v-on 提供了事件修饰符。通过由点 . 表示的指令后缀来调用修饰符。
  2. 常见的事件修饰符
    (1).stop:阻止冒泡。
    (2).prevent:阻止默认事件。
    (3).capture:使用事件捕获模式。
    (4).self:只在当前元素本身触发。
    (5).once:只触发一次。
    (6).passive:默认行为将会立即触发。
<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a>

<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>

<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>

<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>

<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即元素自身触发的事件先在此处理,然后才交由内部元素进行处理 -->
<div v-on:click.capture="doThis">...</div>

<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>

<!-- 点击事件将只会触发一次 -->
<a v-on:click.once="doThis"></a>

注意:使用修饰符是需要考虑到顺序的,相应的代码会以同样的顺序产生。

(二)鼠标修饰符和按键修饰符

<!-- 鼠标修饰符 -->
.left 左键
.right 右键
.middle 滚轮

<!-- 按键修饰符 -->
<!-- 只有在 keyCode 是 13 时调用 vm.submit() -->
<input v-on:keyup.13="submit">

<!-- 记住所有的 keyCode 比较困难,所以 Vue 为最常用的按键提供了别名 -->
.enter 回车
.tab 制表键
.delete(捕获 “删除” 和 “退格” 键)
.esc 返回
.space 空格
.up 上
.down 下
.left 左
.right 右

<!-- 修饰键 -->
.ctrl
.alt
.shift
.meta
<!-- Alt + C -->
<input @keyup.alt.67="clear">
<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">Do something</div>

(三)表单修饰符

  1. .lazy:文本框失去焦点时渲染
  2. .number:将文本框中所输入的内容转换为number类型
  3. .trim:可以自动过滤输入首尾的空格

类(class)和内嵌样式(style)绑定

(一)class

  1. 绑对象
    (1)给 v-bind:class传递一个对象,通过改变对象的值从而动态改变 class 的值

    <div id="app">
    <!-- 可以为 class 属性绑定一个对象 , 这样更加灵活 -->
    <div v-bind:class="test"></div>
    </div>
    <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
    <script>
        new Vue({
            el: '#app',
            data: {
                // 根据 test 对象的属性决定有哪些值
                test: {
                    abc: true,
                    def: true,
                    ghi: false
                }
            }
        });
    </script>
    

    (2)可以为 class 绑定一个返回对象的计算属性

    <div id="app">
    <!-- 可以为 class 属性绑定一个对象 , 这样更加灵活 -->
    <div v-bind:class="test"></div>
    </div>
    <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
    <script>
        new Vue({
            el: '#app',
            // 通过计算属性来返回一个对象
            computed: {
                test() {
                    return {
                        abc: true,
                        def: false,
                        ghi: true
                    }
                }
            }
        });
    </script>
    
  2. 绑数组
    (1)常规绑定数组

    <div id="app">
        <!-- 可以为 class 属性绑定一个数组
    	数组中的每一项表示 data 数据的键 , 每一个键所对应的值为挂上去的样式 -->
    	<div v-bind:class="[a,b,c]"></div>
    </div>
    <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
    <script>
        new Vue({
            el: '#app',
            data: {
                a: 'abc',
                b: 'def',
                c: 'ghi'
            }
        });
    </script>
    

    (2)根据条件切换列表中的 class,可以使用三元表达式。

    <div id="app">
    <div v-bind:class="[a ? b : '',c]"></div>
    </div>
    <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
    <script>
        const vm = new Vue({
            el: '#app',
            data: {
                a: true,
                b: 'def',
                c: 'ghi'
            }
        });
    </script>
    

(二)style

  1. 绑对象
    属性名可以用驼峰式(camelCase)或短横线分隔(kebab-case)来命名。

    <div id="app">
        <div v-bind:style="test">Lorem ipsum dolor sit amet.</div>
    </div>
    <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
    <script>
        const vm = new Vue({
            el: '#app',
            data: {
                test : {
                    color : 'red',
                    fontSize : '30px'
                }
            }
        });
    </script>
    
  2. 绑数组
    v-bind:style 的数组语法可以将多个样式对象应用到同一个元素上。

<div id="app">
    <!-- 同样绑定 2 套样式 -->
    <div v-bind:style="[style1, style2]">Lorem ipsum dolor sit amet.</div>
</div>
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<script>
    const vm = new Vue({
        el: '#app',
        data: {
            style1: {
                color: 'red'
            },
            style2: {
                textDecoration: 'underline'
            }
        }
    });
</script>

条件渲染

(一)v-if、v-else-if、v-else

有条件的渲染某一部分指定的内容。这部分内容只有在指令的表达式返回值为真的时候才被渲染

(二)key 属性

  1. 使元素之间独立开来,不进行复用。即添加一个具有谓一致的 key 属性。
  2. 注意:如果不添加key,则在一个元素输入了内容那么切换之后,原来输入的内容会保留。

列表渲染(循环 — v-for)

(一)迭代数组

语法:v-for(item,index) in items
items:源数据数组 item:数组元素迭代的别名 index:某一项的索引

<div id="app">
    <p v-for="(item,index) in items">my name is {{ item.name }}I'm {{ item.age }} years old.{{index}}</p>
</div>
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<script>
    const vm = new Vue({
        el: '#app',
        data: {
            items: [
                {'name' : 'yangqian','age' : 23},
                {'name' : 'liuxin','age' : 21},
                {'name' : 'limin','age' : 22}
            ]
        }
    });
</script>

(二)迭代对象

<div id="app">
    <ul>
        <!--1 个参数为值 ,2 个参数为键 ,3 个参数为索引 -->
        <li v-for="(value,key,index) in stu">{{ index+1 }}. {{ key }} : {{ value }}</li>
    </ul>
</div>
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<script>
    const vm = new Vue({
        el: '#app',
        data: {
            stu: {
                name: 'yangqian',
                age: 23,
                gender: 'female',
                score: 100
            }
        }
    });
</script>

(三)利用带有 v-fortemplate 渲染多个元素。

<div id="app">
    <ul>
        <template v-for="item in items">
            <li>name:{{ item.name }}</li>
            <li>age:{{ item.age }}</li>
            <li>gender:{{ item.female }}</li>
            <hr>
        </template>
    </ul>
</div>
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<script>
    const vm = new Vue({
        el: '#app',
        data : {
            items : [
                {'name':'yangqian','age':23,'gender':'femalefemale'},
                {'name':'liuxin','age':21,'gender':'female'},
                {'name':'limin','age':22,'gender':'female'},
            ]
        }
    });
</script>

(四)使用 key

为了能够跟踪到每个节点的身份,从而重用和重新排序现有元素,可以为每项提供一个唯一的 key 属性。

<div v-for="item in items" :key="item.id">
    <!-- 内容 -->
</div>

五、Vue 组件注册

(一)组件命名(全局注册)

  1. 短横线分隔命名

    Vue.component('my-component-name', { /* ... */ });
    
  2. 首字母大写命名

    Vue.component('MyComponentName', { /* ... */ });
    

(二)注册组件的形式

  1. 全局注册

    语法:

    Vue.component(tagName, options);
    
  2. 局部注册

    语法:

    new Vue({
        el: '#app',
        components: {
        'component-a': ComponentA,
        'component-b': ComponentB
        }
    })
    

六、Vue 组件通信

(一)props

  1. 父组件通过 props 向下传递数据给子组件,子组件通过 events 给父组件发送消息。

  2. 通过 props 选项,可以向子组件传递内容,所以即使是同一个组件,根据 props 的值也可以渲染出不同的内容。

     <div id="app">
        <input type="text" name="content" id="content" v-model="inputContent">
        <!-- title 是一个静态数据 , 传递固定的值
    content 是一个动态的数据 , 内容取决于 inputContent 数据 -->
        <com title="这是组件1的标题" :content="inputContent"></com>
        <com title="这是组件2的标题" :content="inputContent"></com>
    </div>
    <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
    <script>
        Vue.component('com', {
            props: ['title', 'content'],
            template: `
    <div>
    <h2>{{ title }}</h2>
    <p>{{ content }}</p>
        </div>
    `
        });
        new Vue({
            el: '#app',
            data: {
                inputContent: ''
            }
        });
    </script>
    
  3. 传递各种类型的值
    如果我们想要向子组件传递数字、布尔值、数组、对象,需要使用 v-bind 指令,否则传递过去的只是单纯的字符串。

     <div id="app">
        <!-- 如果不使用 v-bind 指令 , 传递到子组件的内容就是单纯的字符串 -->
        <com content='[1,2,3,4,5]'></com>
        <com :content='[1,2,3,4,5]'></com>
    </div>
    <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
    <script>
        Vue.component('com', {
            props: ['content'],
            template: `
    <div>
    <p>接收到的数据为{{ content }},其数据类型为{{ typeof content }}</p>
        </div>
    `
        });
        new Vue({
            el: '#app'
        });
    </script>
    

(二)父子组件通信

  1. 通信方式

    (1)自定义事件

    <div id="app">
           <parentcom></parentcom>
       </div>
       <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
       <script>
           // 创建父组件(注意:组件名不支持驼峰命名法)
           Vue.component('parentcom', {
               template: `
                   <div>
                   <p>父组件</p>
                   <childcom myname='yangqian' @test="testHandle"></childcom>      
                       </div>
                   `,
               // 事件
               methods: {
                   testHandle(childAge) {
                       console.log('关联子组件后打印:', 2222);
                       console.log('关联子组件后传过来的年龄:',childAge);
                   }
               }
           })
           // 创建子组件
           Vue.component('childcom', {
               props: ['myname'],
               template: `
               <div>
               <p>子组件{{myname}},类型是:{{typeof myname}}</p>
               <button @click="clickHandle">click</button>
                   </div>
               `,
               // 子组件的数据选项
               data() {
                   return {
                       'age': 18
                   }
               },
               methods: {
                   clickHandle() {
                       console.log('子组件');
                       // 方式一:关联父组件。关联成功后会打印父组件事件中的语句
                       /* 
                               参数一:自定义组件名
                               参数二:子组向父组件传的数据
                           */
                       this.$emit('test',this.age);
                   }
               }
           })
           // new 一个 Vue 实例对象
           const vm = new Vue({
               el: '#app'    // 绑定app
           });
       </script>
    

    (2)v-model 指令(需求:点击子组件的按钮让父组件的数字自增)

    <div id="app">
        <parentcom></parentcom>
    </div>
    <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
    <script>
        // 创建父组件(注意:组件名不支持驼峰命名法)
        Vue.component('parentcom', {
            template: `
    <div>
    <p>父组件:{{counter}}</p>
    <childcom myname='yangqian' v-model="counter"></childcom>      
        </div>
    `,
            data() {
                return {
                    counter: 1
                }
            },
        })
        // 创建子组件
        Vue.component('childcom', {
            props: ['myname'],
            template: `
    <div>
    <p>子组件{{myname}},类型是:{{typeof myname}}</p>
    <button @click="clickHandle">+1</button>
        </div>
    `,
            data() {
                return {
                    counter1: 1
                }
            },
            methods: {
                clickHandle() {
                    console.log('子组件', this.counter1++);
                    this.counter1++
                    this.$emit('input',this.counter1);
                }
            }
        })
        // new 一个 Vue 实例对象
        const vm = new Vue({
            el: '#app'
        });
    </script>
    

    注意:通过 v-model 这种方式我们也实现了数据的双向绑定

    (3).sync 修饰符(也可实现数据的双向绑定

    <div id="app">
        <parentcom></parentcom>
    </div>
    <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
    <script>
        // 创建父组件(注意:组件名不支持驼峰命名法)
        Vue.component('parentcom', {
            // <comp :foo.sync="bar"></comp>
            // <comp :foo="bar" @update:foo="val => bar = val"></comp>
            template: `
    <div>
    <p>【父组件】接收的来自子组件的改变:{{counter}}</p>
    <childcom :foo.sync="counter"></childcom>      
        </div>
    `,
            data() {
                return {
                    counter: 1
                }
            },
        })
        // 创建子组件
        Vue.component('childcom', {
            template: `
    <div>
    <p>子组件</p>
    <button @click="clickHandle">+1</button>
        </div>
    `,
            data() {
                return {
                    counter1: 1
                }
            },
            methods: {
                clickHandle() {
                    // console.log('子组件', this.counter1++);
                    this.counter1++
                    this.$emit('update:foo', this.counter1);
                }
            }
        })
        // new 一个 Vue 实例对象
        const vm = new Vue({
            el: '#app'
        });
    </script>
    

(三)非父子组件通信

  1. 概念

    对于非父子组件之间的通行,可以使用一个空的 Vue 实例作为中央事件总线(bus),也就是一个中介。

  2. 实例

    <div id="app">
        <com-1></com-1>
        <com-2></com-2>
    </div>
    <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
    <script>
        const bus = new Vue(); // 中间商
        Vue.component('com-1', {
            template: `
    <div>
    <p @click='test1'>这是组件1</p>
        </div>
    `,
            methods: {
                test1() {
                    // 中间商触发 test 事件 , 并传递数据
                    bus.$emit('test', '这是来自组件1的数据');
                }
            }
        });
        Vue.component('com-2', {
            template: `
    <div>
    <p>这是组件2,当前数据为:{{ name }}</p>
        </div>
    `,
            data: function () {
                return {
                    name: 'yangqian'
                }
            },
            mounted() {
                // 如果使用一般的函数 , this 的指向为全局对象
                // 所以使用箭头函数来指向当前的组件
                // 中间商监听 test 事件 并将接收到的数据赋值给 data 数据
                bus.$on('test', (value) => {
                    this.name = value;
                })
            },
        });
        new Vue({
            el: '#app'
        });
    </script>
    
  3. 使用

    实现了任何组件间的通信,包括父子、兄弟、跨级。如果项目比较大,有更多的人参与开发时,也可以选择更好的状态管理。

(四)父链

  1. 语法

    this.$parent

  2. 在子组件中使用 this.$parent,可以直接访问该组件的父实例或组件。并且以递归向上或向下无限访问,直到根实例或最内层的组件。

  3. 父组件也能用 this.$children 访问它所有的子组件。

  4. 实例

    <div id='app'>
        <p>当前父组件的数据为:{{ message }}</p>
        <com></com>
    </div>
    <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
    <script>
        Vue.component('com', {
            template: '<button @click="handleEvent">通过父链直接修改数据</button>',
            methods: {
                handleEvent: function () {
                    // 访问到父链后 , 可以做任何操作 , 比如直接修改数据 
                    this.$parent.message = '来自组件 com 的内容';
                }
            }
        });
        const app = new Vue({
            el: '#app',
            data: {
                message: 'this is a test'
            }
        });
    </script>
    

(五)子组件索引

  1. 理解

    主要是当子组件较多的时候,我们一个一个去访问是比较困难的,所以可以采用子组件索引的方法,用特殊的属性 ref 来为子组件指定一个索引名称。

  2. 实例

    <div id='app'>
        <p>当前数据为:{{ name }}</p>
        <button @click='getComValue'>获取子组件的数据</button>
        <!-- 为每个子组件设置 ref 属性 , 相当于给了一个别名 -->
        <com1 ref='c1'></com1>
        <com2 ref='c2'></com2>
    </div>
    <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
    <script>
        // 组件1
        Vue.component('com1', {
            template: `
    <p>{{ message }}</p>
    `,
            data: function () {
                return {
                    message: '这是子组件1的数据'
                }
            }
        });
        // 组件2
        Vue.component('com2', {
            template: `
    <p>{{ message }}</p>
    `,
            data: function () {
                return {
                    message: '这是子组件2的数据'
                }
            }
        });
        const app = new Vue({
            el: '#app',
            data: {
                name: 'this is a test'
            },
            methods: {
                getComValue() {
                    // 直接通过(this.$refs.组件别名.数据)来获取组件的数据信息
                    this.name = this.$refs.c1.message + this.$refs.c2.message;
                }
            }
        });
    </script>
    

七、插槽

(一)什么是slot?

简单的讲,就是当我们创建了多个组件后,组件内部可以书写视图,数据、方法等,当我们在HTML中引入自定义组件标签的时候,想要在组件标签内书写内容,理论上是不会显示的,此时就需要我们在组件的视图中加入一个插槽,这样组件标签中的内容就可以显示了。

(二)内容分发

  1. 当需要让组件组合使用,混合父组件的内容与子组件的模版时,就会用到 slot,这个过程叫做内容分发(transclution)。
  2. props 传递数据、events 触发事件和 slot 内容分发就构成了 Vue 组件的 3API 来源,再复杂的组件也是由这 3 个部分构成的。

(三)编译的作用域

父组件模版的内容是在父组件作用域内编译,子组件模版内容是在子组件作用域内编译。

(四)slot 的使用

  1. 单个slot

    <div id='app'>
        <com>Here is a slot</com>
    </div>
    <script src="./vue.js"></script>
    <script>
        Vue.component('com', {
            template: `
    <div>
    <p>this is a test</p>
    <!-- 设置一个插槽-->
    <slot></slot>
        </div>
    `
        });
        new Vue({
            el: '#app'
        })
    </script>
    <!-- 
    1.可以看到我们在组件之间书写了内容,但在页面上渲染不出来,于是需要我们在组件的模板视图中加入插槽,这样才能成功显示在页面中
    2.我们还可以为插槽设置默认内容,如果组件之间没有内容,页面就显示插槽的默认内容。
    -->
    
  2. 具名 slot

    (1)概念

    所谓具名slot,是指当我们有多个组件的时候,可以给 slot 元素指定一个 name 分发多个内容。具名 slot 可以和单个 slot 共存。

    (2)语法:v-slot:slot元素的name属性值

    在向具名插槽提供内容的时候,我们可以在一个 template 元素上使用 v-slot 指令,并以 v-slot 的参数的形式提供其名称。

    <com>
        <template v-slot:header>
            <h2>标题</h2>
        </template>
        <p>Here is a slot</p>
        <template v-slot:footer>
            <div>底部信息</div>
        </template>
    </com>
    
    Vue.component('com', {
    template: `
    <div>
        <p>this is a test</p>
        <slot name='header'></slot>
        <slot></slot>
        <slot name='footer'></slot>
        <p>this is a test,too</p>
    </div>
    `
    });
    
  3. 缩写形式:v-slot:slot元素的name属性值 <=> #slot元素的name属性值

(五)访问slot

  1. 方法:$slot

  2. 实例

    <div id='app'>
        <com>
            <template #header>
                <h2>标题</h2>
            </template>
            <p>Here is a slot</p>
            <template #footer>
                <div>底部信息</div>
            </template>
        </com>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script>
        Vue.component('com', {
            template: `
    <div>
    <p>this is a test<p>
    <slot name='header'>这是头部默认内容</slot>
    <slot>这是插槽默认内容</slot>
    <slot name='footer'>这是底部默认内容</slot>
    <p>this is a test,too</p>
        </div>
    `,
            mounted() {
                const header = this.$slots.header; // 获取头部的插槽
                const main = this.$slots.default; // 获取内容插槽(包括了所有没有被包含在具名slot中的节点)
                const footer = this.$slots.footer; // 获取底部插槽
                console.log('header:', header);
                console.log('main:', main);
                console.log('footer:', footer);
                console.log(footer[0].children[0].text);
            },
        });
        new Vue({
            el: '#app'
        })
    </script>
    

八、动态组件

(一)特性

​ 使用is特性,挂载不同的组件

(二)实例

<!-- 如果有多个组件,可以根据 is 的值来决定渲染哪一个组件 -->
<div id="app">
    <button @click='changeCom'>切换组件</button>
    <component :is='comName'></component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue">
<script>
    Vue.component('com1', {
        template: `<p>this is component1</p>`
    });
    Vue.component('com2', {
        template: `<p>this is component2</p>`
    });
    const vm = new Vue({
        el: '#app',
        data: {
            comName: 'com1'
        },
        methods: {
            changeCom() {
                this.comName === 'com1' ? this.comName = 'com2' : this.comName = 'com1'
            }
        },
    });
</script>

(三)keep-alive

  1. 当我们在两个组件之间进行切换的时候,我们想要实现切换回来时原来的组件的状态可以保持。

  2. 使用到标签 keep-alive标签将动态组件包裹起来

  3. 语法

    <keep-alive>
        <component :is="whichCom"></component>
    </keep-alive>
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值