vue-入门篇二

7.vue组件

7.1 什么是组件

组件 (Component)是 Vue.js 最强大的功能之一,组件是一个自定义元素或称为一个模块,包括所需的模板(HTML)、逻辑(JavaScript)和样式(CSS)。

组件化开发的特点:

  • 标准

  • 分治

  • 重用

  • 组合

组件也是有 全局(component) 与 局部(components) 之分。

7.2 组件的注册及其使用

在使用组件时需要注意以下几点:

  • 构造 Vue 实例时传入的各种选项大多数都可以在组件里使用,只有一个例外:data必须是函数,同时这个函数要求返回一个对象
data: function(){ 
  return { 
    msg: '你好世界' 
  } 
}
  • 组件模板 template

    • 必须是单个根元素
    <!-- 单个根元素 -->
    <div>
      <ul>
        <li></li> 
      </ul> 
      <ul>
        <li></li> 
      </ul> 
    </div> 
    <!-- 不符合单个根元素的情况 --> 
    <p></p> 
    <p></p>
    
    • 支持模板字符串形式
  • 组件名称命名方式

    • 短横线方式(推荐)
      • my-component
    • 大驼峰方式(只能在其他组件模板字符串中使用,不能在HTML模板中直接使用)
      • MyComponent

大驼峰式组件名不能在HTML模板中直接使用,如果需要在HTML模板中使用,需要将其进行特定规则转化:

  • 首字母从大写转为小写

  • 后续每遇到大写字母都要转化成小写并且在转化后的小写字母前加 -

例如, WoDeZuJian 这个大驼峰组件名在HTML中使用的时候需要写成 wo-de-zu-jian

7.2.1 全局组件

全局组件注册形式如下:

// 声明全局组件 
Vue.component(componentName,{ 
  data: '组件数据', 
  template: '组件模版内容' 
})

上述示例中, component() 的第一个参数是 组件名 (实则可以看作是HTML标签名称),第二个参数是一个对象形式的选项,里面存放组件的声明信息。全局组件注册后,任何Vue实例都可以使用。

例如,有以下代码:

// 声明一个全局的HelloWorld组件 
Vue.component('HelloWorld', { 
  data: function(){ 
    return { 
      msg: 'HelloWorld' 
    } 
  },
  template: '<div>{{msg}}</div>' 
});

实例:

<body>
    组件的最大的优势:可以复用
    <div id="app">
        <!--组件在引用时需要写双标记 ,单标签不管引用多少次只执行一次-->
        <btn-counter></btn-counter>
        <btn-counter></btn-counter>
    </div>
    <script src="../js/vue.js"></script>
    <script type="text/javascript">
        // 创建新的全局组件 
        // 全局注册的组件可以用在其被注册之后的任何 (通过 new Vue) 新创建的Vue根实例,也包括其组件树中的所有子组件的模板中。
        Vue.component("btn-counter", {
            data: function () { //组件中的数据,组件的data必须是一个函数
                return {
                    count: 0
                }
            },
            //组件的模板
            template: `<button @click="count++">点击了{{count}}次</button>`
        })

        var vm = new Vue({
            el: "#app",
            data: {
                msg: "hello"
            }
        })
		//注意当点击按钮时,每个组件都会各自独立维护它的 count。
		//因为你每用一次组件,就会有一个它的新实例被创建。
    </script>
</body>

7.2.2 局部组件

局部组件定义后只能在当前注册它的Vue实例中使用,其是通过某个 Vue 实例/组件的实例选项components 注册。

例如,有以下代码:

var Child = { 
  template: '<div>A custom component!</div>' 
}
new Vue({ 
  components: { 
    // <my-component> 将只在父组件模板中可用 
    'my-component': Child 
  } 
})
<body>
  <div id="app">
    <component-demo></component-demo>
  </div>
</body>
<script src="../js/vue.js"></script>
<script>
  new Vue({
    el: '#app',
    components: {
      'component-demo': {
        template: '<h1>局部注册组件{{ num }}</h1>',
        data () {
          return {
            num: 500
          }
        },
        computed: {},
        watch: {},
        mounted () {}
      }
    }
  })
</script>

7.2.3 组件的使用

在HTML模板中,组件以一个自定义标签的形式存在,起到占位符的功能。通过Vue.js的声明式渲染后,占位符将会被替换为实际的内容,下面是一个最简单的模块示例:

<div id="app"> 
  <my-component></my-component>
</div>

7.3 组件间传值

如前面介绍组件时所说,组件有 分治 的特点,每个组件之间具有一定的独立性,但是在实际工作中使用组件的时候有互相之间传递数据的需求,此时就得考虑如何进行 组件间传值 的问题了。

7.3.1 父->子传值

简单父传子:

<div id="app">
		<!--组件的调用,传的参数的名称 ,和子组件中 props所需要接收的名字要一致
			传参,如果传递的是 常量不需要冒号   ;如果 是 变量的话就需要冒号-->
		<ball value="足球" :test="num1"></ball>
		<ball value="篮球" :test="num2"></ball>
		<ball value="乒乓球" :test="num3"></ball>
	</div>
	<script type="text/javascript" src="../js/vue.js"></script>
	<script type="text/javascript">
		//这个代码会报错
		//因为组件只允许有一个根节点
		var ball = {
			//父组件传参给子组件时,使用 props接收
			props: ['value', 'test'],//接收的父组件的传参
			template: `<div>我喜欢:{{value}}</div><div>我进了 {{test}}个球</div>`
		};
		var vm = new Vue({
			el: "#app",
			data: {
				num1: 10,
				num2: 20,
				num3: 50
			},
			components: {
				ball
			}
		})
	</script>
  • 父组件以属性的形式绑定值到子组件身上

  • 子组件通过使用属性props接收

    • props是单向绑定的(只读属性):当父组件的属性变化时,将传导给子组件,但是反过来不会

    • props属性支持两种常见的写法形式

      • 数组

        • 优点:书写简单

        • 缺点:不能设置默认值、数据类型

      • 对象

        • 优点:可以设置数据默认值与数据类型
  • 缺点:写法复杂

单向数据流实例:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>单向数据流</title>
</head>

<body>
    <div id="app">
        <!-- 3.使用 -->
        <child :name="user"></child>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        //1.定义子组件
        //vue的组件传参是单向的,从父组件传过来的值,props接收后不能在子组件中进行修改
        var child = {
            props: ["name"],
            template: `<div>子组件, 从父组件传过来的name是:{{name}}
            <button @click="changeName">点击修改名字</button>
            </div>`,
            methods: {
                changeName() {
                    this.name = "laura";
                }
            }
        }

        /************************/
        var app = new Vue({
            el: "#app",
            data: {
                user: 'yyyy'
            },
            //2.注册
            components: {
                child
            }
        })
    </script>
</body>

</html>

使用computed来处理单向数据流:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>使用 计算属性解决问题</title>
</head>

<body>
    <div id="app">
        <!-- 3.使用 -->
        <child :name="user"></child>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        //1.定义子组件
        //vue的组件传参是单向的,从父组件传过来的值,props接收后不能在子组件中进行修改
        //将从父组件传过来的值重新赋值成组件本地变量
        var child = {
            props: ["name"],
            data: function () {
                return {
                    childname: this.name
                }
            },
            template: `<div>子组件, 从父组件传过来的name是:{{name}}
            将从父组件传过来的值转大写{{changeUser}}
            <button @click="changeN">修改子组件的名字</button>
            修改后的 值:{{childname}}
            </div>`,
            computed: {
                changeUser: function () {
                    return this.name.toUpperCase();
                }
            },
            methods: {
                changeN() {
                    this.childname = 'new name';
                }
            }
        }

        /************************/
        var app = new Vue({
            el: "#app",
            data: {
                user: 'yyyy'
            },
            //2.注册
            components: {
                child
            }
        })
    </script>
</body>

</html>

props数组、对象的写法:

<div id="app">
        <child :propb="num" propc="test" propf="success"></child>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        var child = {
            props: {
                //可以验证传过来的参数类型
                propb: [String, Number],
                //****
                propc: {
                    type: String,
                    required: true //参数是必填项
                },
                //****
                propd: {
                    type: Number,
                    default: 8000 //参数的默认值
                },
                //默认值可以返回函数
                prope: {
                    type: Object,
                    default: function () {
                        return { msg: 'hello' }
                    }
                },
                //自定义验证
                propf: {
                    validator: function (value) {
                        return ['success', 'warning', 'danger'].indexOf(value) !== -1
                    }
                }
            },
            template: `<div>我是子组件
            propb:{{propb}}
            propc:{{propc}}
            propd:{{propd}}
            prope:{{prope}}
            propf:{{propf}}
            
            </div>`
        }

        var app = new Vue({
            el: "#app",
            data: {
                type: true,
                num: 100
            },
            components: {
                child
            }
        })
    </script>

7.3.2 子->父传值

  • 子组件模版内容中用 $emit() 定义 自定义事件 , $emit() 方法有2个参数

    • 第一个参数为自定义的事件名称

    • 第二个参数为需要传递的数据(可选)

  • 父组件模板内容中的子组件占位标签上用v-on(或@)绑定子组件定义的自定义事件名,监听子组件的事件,实现通信

子传父实例:

	<div id="app">
        父组件的msg:{{msg}}
        <!--第二步 在父组件中使用 子组件的标签中 ,绑定在子组件中定义好的自定义事件 ,调用父组件的 parentFun-->
        <child :msg="msg" @myclick="parentFun"></child>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        //子组件
        var child = {
            props: ["msg"],
            template: `<div class="child">子组件
            从父组件传过来的参数是:{{msg}}
            <button @click="change">点击按钮改变父组件的值</button>
            </div>`,
            methods: {
                change() {
                    //第一步:使用 $emit 主动触发一个自定义事件
                    //参数:1.自定义的事件的名称,2.要传给父组件的参数
                    this.$emit("myclick", "newvalue");
                }
            }
        }
        /*****************/
        var app = new Vue({
            el: "#app",
            data: {
                msg: "hello"
            },
            components: {
                child
            },
            methods: {
                //第三步
                parentFun: function (value) {
                    console.log("从子组件传过来的值:", value);
                    this.msg = value;
                }
            }

        })
    </script>

自定义组件上使用 v-model:

<div id="app">
        <input type="text" v-model="message" />{{message}}
        <!-- 不可以 直接在子组件上绑定 v-model ,想要实现该效果,
            必须在子组件的里面使用 $emit 去主动触发自定义事件 -->
        <child v-model="msg"></child>{{msg}}
    </div>
    <script src="./js/vue.js"></script>
    <script>
        var child = {
            props: ['value'],
            template: `<div>
                子组件
                <input type="text" :value="value" @input="$emit('input',$event.target.value)"/>
            </div>`
        }

        var app = new Vue({
            el: "#app",
            data: {
                msg: "hello",
                message: "hi"
            },
            components: {
                child
            }
        })
    </script>

习题

要求:1.点击父组件按钮显示子组件,点击子组件隐藏本身,

​ 2.使用.native 给子组件绑定原生事件

<div id="app">
        <button @click="changeType">点击按钮显示子组件</button>
        <!-- 如果想要在子组件上绑定原生事件,必须使用 .native 的修饰符 -->
        <child v-show="type" @childclick="changeTT" @mouseover.native="test"></child>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        var child = {
            template: `<div class="child">
                我是子组件,我在蓝色的海洋里
                <button @click="childFun">点击按钮,隐藏子组件</button>
            </div>`,
            methods: {
                childFun() {
                    //需要点击按钮改变父组件的type状态值
                    this.$emit("childclick", false);
                }
            }
        }
        var app = new Vue({
            el: "#app",
            data: {
                type: false
            },
            components: {
                child
            },
            methods: {
                changeType() {
                    this.type = true;
                },
                // 接收子组件传过来的参数
                changeTT(value) {
                    this.type = value;
                },
                test() {
                    console.log("给子组件绑定的原生事件触发了");

                }
            }
        })
    </script>

.sync

在有些情况下,我们可能需要对一个 prop 进行“双向绑定”。不幸的是,真正的双向绑定会带来维护上的问题,因为子组件可以变更父组件,且在父组件和子组件都没有明显的变更来源。

这也是为什么我们推荐以 update:myPropName 的模式触发事件取而代之。举个例子,在一个包含 title prop 的假设的组件中,我们可以用以下方法表达对其赋新值的意图:

this.$emit(‘update:title’, newTitle)
然后父组件可以监听那个事件并根据需要更新一个本地的数据 property。例如:

<text-document
v-bind:title=“doc.title”
v-on:update:title=“doc.title = $event”

为了方便起见,我们为这种模式提供一个缩写,即 .sync 修饰符:

<div id="app">
        <button @click="changeType">点击按钮显示子组件</button>
        <!-- 如果想要在子组件上绑定原生事件,必须使用 .native 的修饰符 -->
        <!-- <child v-show="type" @childclick="changeTT"></child> -->
        <!-- <child v-show="type" @up-is-show="changeTT"></child> -->
        <!-- <child v-show="type" @update:is-show="changeTT"></child> -->
        <!-- <child v-show="isshow" @update:is-show="function(type){isshow = type}"></child> -->
        <child v-show="isshow" :is-show.sync="isshow"></child>
        <!--.sync 是一个语法糖  @update:is-show="function(type){isshow = type}"-->
    </div>
    <script src="./js/vue.js"></script>
    <script>
        var child = {
            template: `<div class="child">
                我是子组件,我在蓝色的海洋里
                <button @click="childFun">点击按钮,隐藏子组件</button>
            </div>`,
            methods: {
                childFun() {
                    //需要点击按钮改变父组件的type状态值
                    this.$emit("update:is-show", false);
                }
            }
        }
        var app = new Vue({
            el: "#app",
            data: {
                isshow: false
            },
            components: {
                child
            },
            methods: {
                changeType() {
                    this.isshow = true;
                },
                // 接收子组件传过来的参数
                // changeTT(value) {
                //     this.type = value;
                // }
            }
        })
    </script>

7.3.3 EventBus

EventBus又被称之为中央事件总线

在Vue中通过单独的 事件中心 来管理非 父子关系 组件(兄弟)间的通信:

公众号千千万,都得先关注公众号,一旦发送消息,就可以收到消息 - 专注交流一百年

核心步骤

  • 建立事件中心
const eventBus = new Vue()
  • 传递数据
eventBus.$emit('自定义事件名',传递的数据)
  • 接收数据
eventBus.$on('自定义事件名'[,callback])
  • 销毁事件中心
eventBus.$off('自定义事件名')

先建立事件中心 const bus = new Vue()

在需要接受数据的地方先监听自定义事件以及接受数据的回调函数bus.$on('my-event', (data) => {})

在需要传递数据的地方提交 自定义事件以及参数 bus.$emit('my-event', params)

 <div id="app">
        <mycontent></mycontent>
        <myfooter></myfooter>
    </div>
    <template id="footer">
        <ul class="nav">
            <li @click="goContent('home')">首页</li>
            <li @click="goContent('list')">分类</li>
            <li @click="goContent('cart')">购物车</li>
            <li @click="goContent('me')">我的</li>
        </ul>
    </template>
    <template id="content">
        <div class="con">我是内容页,显示的数据是:{{text}}</div>
    </template>
    <script src="./js/vue.js"></script>
    <script>
        //兄弟节点间传参 eventbus
        //1.创建bus
        var bus = new Vue();
        //子组件
        //底部导航组件
        var myfooter = {
            template: '#footer',
            methods: {
                goContent(type) {
                    //2.发送数据
                    //参数:1.自定义事件名;2.要传递的参数
                    bus.$emit('myevent', type);
                }
            }
        }
        //内容显示组件
        var mycontent = {
            data() {
                return {
                    text: ""
                }
            },
            template: '#content',
            //挂载后的钩子
            mounted() {
                //3. 接收数据
                bus.$on('myevent', (data) => {
                    console.log(data);
                    this.text = data;
                });
            }
        }
        /**************/
        var app = new Vue({
            el: "#app",
            components: {
                myfooter,
                mycontent
            }
        })
    </script>

7.3.4 ref

ref 属性被用来给元素或子组件注册引用信息,引用信息将会注册在父组件的 $refs 对象上。

如果在普通的 DOM 元素上使用 ref 属性,则引用指向的就是 DOM 元素;

如果 ref 属性用在子组件上,引用就指向子组件实例

  • ref 放在标签上,拿到的是原生节点。

  • ref 放在组件上 拿到的是组件实例

  • 原理:在父组件中通过 ref 属性(会被注册到父组件的 $refs 对象上)拿到组件/DOM对象,从而得到组件/DOM中的所有的信息,也包括值

<div id="app">
        <div ref="oDiv">父组件的div{{message}}</div>
        <child ref="child"></child>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        //refs 使用 ,是在 js原生组件或 自定义组件上写 ref 属性
        //调用时,需要写成 this.$refs.ref的属性名.*****
        //尽量不使用refs,因为 他没有使用虚拟dom ,性能稍差
        //子组件
        var child = {
            data() {
                return {
                    msg: 'hello'
                }
            },
            template: `<div>我是子组件</div>`,
            methods: {
                test() {
                    console.log('子组件的函数被触发了');

                }
            }
        }

        var app = new Vue({
            el: "#app",
            data: {
                message: ""
            },
            components: {
                child
            },
            mounted() {
                console.log(this);

                console.log(this.$refs.oDiv);
                //普通的div的使用refs修改其属性
                this.$refs.oDiv.style.color = "green";
                //使用 refs获取子节点的属性
                console.log(this.$refs.child.msg);
                this.message = this.$refs.child.msg;
                this.$refs.child.test();

            }
        })
    </script>

注意:

ref 属性这种获取子元素/组件的方式虽然写法简单,容易上手,但是其由于权限过于开放,不推荐使用,有安全问题。(不仅可以获取值,还可以获取其他所有的元素/组件的数据,甚至可以修改这些数据。)

$nextTick

在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。

<div id="app">
        <input type="text" v-show="isShow" ref="myinput" />
    </div>
    <script src="./js/vue.js"></script>
    <script>
        var app = new Vue({
            el: "#app",
            data: {
                isShow: false
            },
            mounted: function () {
                this.isShow = true;
                //视图还没更新完,就获取到了dom节点的信息
                // this.$refs.myinput.focus();
                //这个问题可以使用 nextTick来解决
                //nextTick 有一个参数 ,是回调函数,作用是,等待 视图更新后,在执行 回调函数中的代码
                this.$nextTick(() => {
                    this.$refs.myinput.focus();
                })
            }
        })
    </script>

7.3.5 $root

可以用来从一个子组件访问父组件的实例,

在绝大多数情况下,触达父级组件会使得你的应用更难调试和理解,尤其是当你变更了父级组件的数据的时候。当我们稍后回看那个组件的时候,很难找出那个变更是从哪里发起的。

 <div id="app">
        <child></child>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        //$root  可以获取到根节点的所有属性
        //子组件
        var child = {
            data() {
                return {
                    mm: ""
                }
            },
            template: `<div>子组件{{mm}}</div>`,
            mounted() {
                this.$root.test();
                this.mm = this.$root.msg;
            }
        }

        var app = new Vue({
            el: "#app",
            data: {
                msg: "hello"
            },
            methods: {
                test() {
                    console.log("根节点的函数");

                }
            },
            computed: {
                bar() {
                    console.log("根节点的计算属性");

                }
            },
            components: {
                child
            }
        })
    </script>

7.3.6 parent、children

可以通过$parent直接获取到父组件的实例,可以通过 $children直接获取到子组件的实例

如果需要在组件的结构中访问父组件的属性和方法,不需要添加this,但是也可以添加

7.3.7 祖先组件传递后代组件

通过 provide + inject 完成传值

这对选项是一起使用的。以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。

provide:是一个对象,或者是一个返回对象的函数。里面包含要给子孙后代的东西,也就是属性和属性值。

inject:一个字符串数组,或者是一个对象。属性值可以是一个对象,包含from和default默认值。

from表示在可用的注入内容中搜索用的 key,default当然就是默认值。

provideinject 主要在开发高阶插件/组件库时使用。并不推荐用于普通应用程序代码中。

传参方式总结,以下几种方式都可以用来组件间传参:

  • props 父传子 ***
  • $refs ***
  • $emit 子传父 ***
  • eventBus 兄弟传参 ***
  • provide 和 inject 跨级传参
  • $root 获取根节点数据, $parent $children 父子
  • vuex 传参 项目中经常使用 ****
  • localStorage / sessionStorage 使用缓存传参
  • v-model 可以父子通信的 v-bind v-on 原理: $emit
  • 作用域插槽 v-slot 子组件的数据传递给父组件使用

7.4 动态组件

通过分支条件判断实现选项卡切换

<div id="app">
        <home v-if="type == 'home'"></home>
        <list v-else-if="type=='list'"></list>
        <cart v-else-if="type=='cart'"></cart>
        <me v-else></me>
        <ul>
            <li @click="goCon('home')">首页</li>
            <li @click="goCon('list')">列表</li>
            <li @click="goCon('cart')">购物车</li>
            <li @click="goCon('me')">我的</li>

        </ul>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        var home = {
            template: `<div>首页</div>`
        }
        var list = {
            template: `<div>列表</div>`
        }
        var cart = {
            template: `<div>购物车</div>`
        }
        var me = {
            template: `<div>我的</div>`
        }

        var app = new Vue({
            el: "#app",
            data: {
                type: 'home'
            },
            methods: {
                goCon(type) {
                    this.type = type;
                }
            },
            components: {
                home,
                list,
                cart,
                me
            }
        })
    </script>

通过使用保留的 元素,动态地绑定到它的 is 特性,我们让多个组件可以使用同一个挂载点,并动态切换。

<div id="app">
        <!-- <home v-if="type == 'home'"></home>
        <list v-else-if="type=='list'"></list>
        <cart v-else-if="type=='cart'"></cart>
        <me v-else></me> -->
        <!-- 动态组件, 有一个 is 属性,is的值是什么名称就调用什么组件 -->
        <component :is="type"></component>
        <ul>
            <li @click="goCon('home')">首页</li>
            <li @click="goCon('list')">列表</li>
            <li @click="goCon('cart')">购物车</li>
            <li @click="goCon('me')">我的</li>

        </ul>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        var home = {
            template: `<div>首页</div>`
        }
        var list = {
            template: `<div>列表</div>`
        }
        var cart = {
            template: `<div>购物车</div>`
        }
        var me = {
            template: `<div>我的</div>`
        }

        var app = new Vue({
            el: "#app",
            data: {
                type: 'home'
            },
            methods: {
                goCon(type) {
                    this.type = type;
                }
            },
            components: {
                home,
                list,
                cart,
                me
            }
        })
    </script>

思考:如果每个组件中都有一个输入框,点击切换时输入不同的内容,然后再切换,查看效果

keep-alive的作用:

keep-alive 可以将已经切换出去的非活跃组件保留在内存中。如果把切换出去的组件保留在内存中,可以保留它的状态,避免重新渲染。


思考:使用keep-alive 看似保留了所有的状态,但是如果某一个组件不要保留状态呢

 <keep-alive include="list,cart">
            <component :is="type"></component>
        </keep-alive>


//路由中可以配置组件缓存
<template>
      <div id="app">
        <keep-alive >
          <router-view v-if="$route.meta.keepAlive"></router-view>   //放需要缓存的组件
        </keep-alive>
        <router-view v-if="!$route.meta.keepAlive"></router-view>  //放不需要缓存的组件
      </div>
    </template>
//路由配置文件router.js文件中,给需要缓存的路由加上meta属性,并设置值。

{
      path: '/usermanage',
      name: 'usermanage',
      meta: {
        keepAlive: true, //该字段表示该页面需要缓存
      },
      component: resolve => require(['@/views/userManage/userManage'], resolve) // 路由懒加载
    },

使用keep-alive之后会触发什么钩子函数

 activated() {
console.log("keep-alive 组件进入时执行的钩子");

},
deactivated() {
console.log("keep-alive组件离开时执行的钩子");
}

案例:使用动态组件实现简易的步骤向导效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0UjiT9lu-1617193637113)(img/33.png)]


7.5 组件插槽

组件的最大特性就是 重用 ,而用好插槽能大大提高组件的可重用能力。

**插槽的作用:**父组件向子组件传递内容。

通俗的来讲,插槽无非就是在 子组件 中挖个坑,坑里面放什么东西由 父组件 决定。

插槽类型有:

  • 单个(匿名)插槽

  • 具名插槽

  • 作用域插槽

7.5.1 匿名插槽

匿名插槽一般就是使用单个插槽


注意:子组件的 slot 标签中允许书写内容,当父组件不往子组件传递内容时, slot 中的内容才会被展示出来。

7.5.2 具名插槽

slot 元素可以用一个特殊的特性 name 来进一步配置如何分发内容。多个插槽可以有不同的名字,具名插槽将匹配内容片段中有对应 slot 特性的元素。

上中下 形式网页布局示例代码

	

具名插槽存在的意义就是为了解决在单个页面中同时使用多个插槽。

7.5.3 作用域插槽

**应用场景:**父组件对子组件的内容进行加工处理

作用域插槽是一种特殊类型的插槽,作用域插槽会绑定了一套数据,父组件可以拿这些数据来用,于是,情况就变成了这样:样式父组件说了算,但父组件中内容可以显示子组件插槽绑定的数据。


插槽实例,模拟element-ui封装弹窗ui组件:


7.6 插件

插件通常用来为 Vue 添加全局功能。插件的功能范围没有严格的限制——一般有下面几种:

  1. 添加全局方法或者 property。如:vue-custom-element
  2. 添加全局资源:指令/过滤器/过渡等。如 vue-touch
  3. 通过全局混入来添加一些组件选项。如 vue-router
  4. 添加 Vue 实例方法,通过把它们添加到 Vue.prototype 上实现。
  5. 一个库,提供自己的 API,同时提供上面提到的一个或多个功能。如 vue-router

使用插件

通过全局方法 Vue.use() 使用插件。它需要在你调用 new Vue() 启动应用之前完成:

// 调用 `MyPlugin.install(Vue)`
Vue.use(MyPlugin)

new Vue({
  // ...组件选项
})

也可以传入一个可选的选项对象:

Vue.use(MyPlugin, { someOption: true })

Vue.use 会自动阻止多次注册相同插件,届时即使多次调用也只会注册一次该插件。

Vue.js 官方提供的一些插件 (例如 vue-router) 在检测到 Vue 是可访问的全局变量时会自动调用 Vue.use()。然而在像 CommonJS 这样的模块环境中,你应该始终显式地调用 Vue.use()

// 用 Browserify 或 webpack 提供的 CommonJS 模块环境时
var Vue = require('vue')
var VueRouter = require('vue-router')

// 不要忘了调用此方法
Vue.use(VueRouter)

开发插件

Vue.js 的插件应该暴露一个 install 方法。这个方法的第一个参数是 Vue 构造器,第二个参数是一个可选的选项对象:

MyPlugin.install = function (Vue, options) {
  // 1. 添加全局方法或 property
  Vue.myGlobalMethod = function () {
    // 逻辑...
  }

  // 2. 添加全局资源
  Vue.directive('my-directive', {
    bind (el, binding, vnode, oldVnode) {
      // 逻辑...
    }
    ...
  })

  // 3. 注入组件选项
  Vue.mixin({
    created: function () {
      // 逻辑...
    }
    ...
  })

  // 4. 添加实例方法
  Vue.prototype.$myMethod = function (methodOptions) {
    // 逻辑...
  }
}

实例:

	

7.7 过渡效果和动画效果

单元素/组件的过渡

Vue 提供了 transition 的封装组件,在下列情形中,可以给任何元素和组件添加进入/离开过渡

  • 条件渲染 (使用 v-if)
  • 条件展示 (使用 v-show)
  • 动态组件
  • 组件根节点

实例:



使用 animate.css 完成动画

实例:


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值