Vue 组件

组件是可复用的 Vue 实例,且带有一个名字

  • 组件也是一个 vue 实例,可以传入和 vue 一样的属性
  • 实例一个组件,这里只是定义一个组件,还没有再全局或者 vue 实例中注册,还不能去使用它
       //1. 创建组件构造器
        let Profile = Vue.extend({
            //1.1 模板选项
            template : `
                <div>
                    <input type="date">
                    <p>今天心情不错!</p>
                </div>
            `
        });

或者在 html 页面中用 template 或者 script 便签定义一个模板

  <!-- 写在 vue 实例控制的区域外 -->
    <template id="myTemplate">
        <div>
            <h1>今天心情不错</h1>
            <p>出去走走</p>
        </div>
    </template>

  <!--这样也可以定义一个vue组件-->
    <script type="text/template" id="myTemplate">
        <div>
            <h1>今天心情不错</h1>
            <p>出去爬山</p>
        </div>
    </script>
  • 全局注册组件:这里全局注册的组件可以在页面上所有的vue实例中去使用
//  注册全局组件
Vue.component('mytemplate',Profile);

使用:以组件名称为一对标签的写入 vue 实例控制的界面即可

    <div id="app">
        <mytemplate></mytemplate>
    </div>
  • 局部注册组件:在 vue 实例的 components 属性中注册局部组件,局部组件只能在对应 vue 实例控制的区域内使用
 //1. 创建Vue的实例
    let vm = new Vue({
        el : '#app',
        data : {
            message : ''
        },
        methods : {
            //实例的所有函数实现
        },
        components : {
            //注册局部组件,只能在这个vue实例内部使用
            'mytemplate' : Profile
        }
    });
  • 父子组件间传值问题,通过一个 TodoList 案例来解释,要求:在文本框中输入 Todo 添加到 list 中,点击 list 删除对应项,涉及到子组件向父组件传值和父组件向子组件传值
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>TodoList</title>
    <script src="../../Vue/node_modules/vue/dist/vue.js"></script>
</head>

<body>
    <div id="app">
        <input type="text" v-model="inputValue">
        <button @click="addToList">提交</button>
        <ul>
            <todo-item v-for="(item, index) in list" :content="item" :index="index" @delete="deleteFromList">
            </todo-item>
        </ul>
    </div>
    <script>
        // 注册一个 TodoItem 的组件
        let todoItem = {
            template: `<li @click="deleteItem">{{ content }}</li>`,
            props: ['content', 'index'],
            methods: {
                deleteItem() {
                    this.$emit('delete', this.index);
                }
            }
        };
        let vm = new Vue({
            el: '#app',
            data: {
                list: [],
                inputValue: ''
            },
            methods: {
                addToList() {
                    this.list.push(this.inputValue);
                    this.inputValue = '';
                },
                deleteFromList(index) {
                    this.list.splice(index, 1);
                }
            },
            components: {
                todoItem
            }
        });
    </script>
</body>

</html>

子组件向父组件传值,用事件调用的方式,父组件向子组件传值用属性绑定的方式。

  • 属性绑定:可以实现父组件向子组件传值,在做属性绑定时,一定要在子组件中的 props中去定义这个属性,子组件才可以使用在子组件中,也可以对父组件传的值做一定的校验
// 可以将 props 属性写成一个对象
props:{
  // 属性名 
  content : {
    type: String, // 规定接收属性的类型,如果要接收多个属性,可以写成一个数组
    required : Boolean, // 是否为必填,如果为 true 并且父组件没有传值则会报一个警告,默认是 false 
    default : defaultValue, // 默认值
    validator : function (value) {
      // 接收 属性的 value 值,可以对 value 进行验证,放回 true 表示通过验证, false 表示验证失败
     } 
  }
}
  • 事件调用:在子组件中调用this.$emit('父组件自定义函数名',若干参数)的方式触发父组件自定义函数中对用的父级函数,来达到子组件向父组件传递值的目的(函数调用时的参数传递)
  • 非父子组件间传值
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>doucment</title>
</head>

<body>
    <div id="app">
        <mytemplate :content="'one'"></mytemplate>
        <mytemplate :content="'two'"></mytemplate>
    </div>
    <script src="../../Vue/node_modules/vue/dist/vue.js"></script>
    <script>
        /* 
        组件间不可以直接传值,
        我们可以将这个值放在一个公共的地方,
        然后组件去拿,这个地方就是 Vue 的原型上 

        1. 我们在Vue构造函数原型上定义一个属性,职为一个vue实例
        2. 在一个组件中用这个公共实例去触发一个自定义事件
          this.bus.$emit('fnName', args)
        3. 在另一个组件中去接收这个函数的触发,
          通过回调函数的参数接收触发时传递的参数
           this.bus.$on('fnName', function(args){
              //   handler
          });
    */
        Vue.prototype.bus = new Vue();




        //1. 创建组件构造器
        let Profile = {
            //1.1 模板选项
            template: `<div @click="clickHandler">{{ selfContent }}</div>`,
            props: ['content'],
            data() {
                return {
                    /* 
                     这里接收 content ,
                    因为我们需要去修改父组件的 content  的值,
                    如果是一 个引用类型,可能会造成问题 ,
                    影响别的组件对content的引用
                    需要先接收一下再修改
                    */
                    selfContent: this.content
                }
            },
            methods: {
                clickHandler() {
                    // 让原型上的 bus 实例去触发事件一个事件
                    this.bus.$emit('change', this.selfContent);
                }
            },
            mounted() {
                this.bus.$on('change', msg => {
                    this.selfContent = msg;
                });
            },
        };

        // 2. 注册全局组件
        Vue.component('mytemplate', Profile);

        //1. 创建Vue的实例
        let vm = new Vue({
            el: '#app',
            data: {
                message: ''
            },
            methods: {
                //实例的所有函数实现
            }
        });
    </script>
</body>

</html>
  • 如果我们在组件标签上想去触发一个原生 DOM 事件,直接写是不生效的
<div id="app">
  <myComponent @click="clickHandler></myComponent>
</div>

我们原本的目的是想直接点击这个组件就可以触发原生的 click事件,但是事与愿违,他会将我们写的 click当成一个自定义事件去解析,如果需要作为一个原生的 DOM 事件去触发,我们可以添加一个修饰符即可
<myComponent @click.native="clickHandler></myComponent>

  • 假如涉及到了复杂的组件间的传值问题,可以考虑使用 vuex
  • 插槽的使用:如果我们需要由父组件向子组件里面传一段 html 代码,显然是不好取用属性绑定的方式,这里我们用插槽
<div id="app">
        <my-slot>
            <!--组件中写入的html代码为插槽部分的代码-->
            <!--用slot给插槽命名,只会显示到组件中 name 属性为该名称的插槽中-->
            <div slot="panel-body">
              <img src="image.jpg" alt="">
              <p>鞠婧炜</p>
            </div>
        </my-slot>
    </div>
    <template id="my-slot">
        <div class="panel">
            <h1 class="panel-heading">头部</h1>
            <slot name="panel-body">默认显示!!!</slot>
            <footer>尾部</footer>
        </div>
    </template>
  • 组件向插槽传值,也是通过属性绑定的方式
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="../../Vue/node_modules/vue/dist/vue.js"></script>
</head>

<body>
    <div id="app">
        <component>
            <template slot-scope="props">
                <p>this is a slot DOM</p>
                <p>{{ props.msg }}</p>
            </template>
        </component>
    </div>
    <script>
        let component = {
            data() {
                return {
                    msg: 'this is the component msg'
                }
            },
            template: `<div>
                        <p>conponent DOM</p>
                        <slot :msg="msg"></slot>
                       </div>`
        };

        let vm = new Vue({
            el: '#app',
            components: {
                component
            }
        });
    </script>
</body>

</html>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,287评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,346评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,277评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,132评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,147评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,106评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,019评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,862评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,301评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,521评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,682评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,405评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,996评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,651评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,803评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,674评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,563评论 2 352

推荐阅读更多精彩内容