一、组件的基本概念
1、组件是独立的、可以复用的一个个小模块;组件是声明式的,是语义化标签的一种扩展,使用标签<login/>在页面中使用,有模板的使用即是组件。
2、原则:独立性、复用性、可组装性。
3、组件化开发是web开发的基础;(asp.net)
4、组件的定义,结构:
(1)标签名
(2)组件的主体:a、html(view)+css+js(viewmodel);
b、必须有视图;
局部注册组件
选项对象的components属性注册局部组件,只能在所注册的作用域模板中使用;
{components:{组件id:实例构造器 | 对象 } }
局部组件就是在哪里定义,在哪里使用;

(function (){
    //局部组件(注册到new vue({components}))
    let hello = {
        template:"<h1>你好啊</h1>",

    };
    //全局组件
    Vue.component("world",{
        template:"<h1>hello</h1>",
        render(h){
            return h("h1",{},"world hello");
        }
    });
    //3.
    let hi = Vue.extend({
        template:"<h1>hi</h1>"
    });
    new Vue({
        el:"#app",
        data:{
            msg:"哈哈"
        },
        components:{
            hello,
            hi
        }
    })
})();

组件中data的注意
data必须是一个函数,函数中返回一个新对象,如果是对象形式会警告必须是函数;
这样做防止组件引用同一个对象,导致数据相互影响;
html模板
放在一对template标签中,在组件中使用标签的id
组件命名约定和模板
1.注册组件命名:
kebab-case (短横线分隔命名)
camelCase (驼峰式命名)
PascalCase (单词首字母大写命名)
2.不能使用html规定的标签名
使用组件命名:
kebab-case (短横线分隔命名)
组件的复用

(function (){
    //组件的服用,组件的内容是变化的
    //组件就是一个方法
    let hello ={
        name:"hello",
        template:"<div :style='innerStyle'><h1></h1>{{title}}<p>{{desc}}</p></div>",
        data(){ //组件内部的实例属性,对内提供数据
            return{
                msg:"hello world"
            }
        },
        props:{//组件的属性接口,用来获取外部数据的接口属性
            title:"",
            desc:"",
            innerStyle:""
        }
    };
    new Vue({
        el:"#app",
        data:{
            msg:"hello Vue"
        },
        components:{
            hello
        }
    })
})();

prop
prop上的属性都会放在当前组件的实例上面
props:['test'],可以是多个,也可以是对象形式的;
1.动态props传递

 (function (){
    let hello ={
       template:"<div>{{num | count}} {{n}}</div>",
       props: {
          num:{
               type: Number,
               default: 0,
               require:true,
               validator: function (v) {
                   return v > 0
               }
          },
           n:Number
       } ,
        filters:{
           count(v){
               return v+100;
           }
        }
    }
    let user ={
        template: "<div><h1>{{name}}</h1><p>{{age}}</p></div>",
        props:["name","age"]
    }

    new Vue({
        el:"#app",
        components:{
            hello,
            user
        },
        data:{
            n:0,
            userList:[
                {name:"张三",age:15},
                {name:"李小四",age:20}
            ]
        }
    })
})();

2.组件的设计(props小案例)

<body>
<div id="app">
    <ulogin istyle="color:red" title="用户登录" btitle="用户登录" :send="userSend"></ulogin>
    <alogin istyle="color:blue" title="管理员登录" btitle="管理员登录" :send="adminSend"></alogin>
   </div>
   </body>
   </html>
   <script src="bower_components/vue/dist/vue.js"></script>
   <script>
  (function (){

    //login组件可以放在不同的背景使用 user admin
    let login={
        template:`
                    <div :style="istyle">
                        <h1>{{title}}</h1>
                        <div>用户名: <input type="text"></div>
                        <hr>
                        <div>密码: <input type="password"></div>
                        <hr>
                        <button @click="send">{{btitle}}</button>
                    </div>
                `,
        props:["title","btitle","send","istyle"]
    }
    new Vue({
        el:"#app",
        data:{
            msg:"你好"
        },
        components:{
            "ulogin":login,
            "alogin":login
        },
        methods:{
            userSend(name,pwd){
                console.log("用户登录成功"+name);
            },
            adminSend(name,pwd){
                console.log("管理员登录成功"+name);
            }
        }
    })
})();
</script>

组件的插槽
1.单个插槽(无命名插槽)
如果子组件中没有一对slot标签,写在子组件标签对的内容会被丢弃;
子组件中有slot标签,子组件标签对的内容会整体替换在slot标签位置;
如:<slot></slot> //这个就是默认的插槽,只要组件标签中写内容都会替换slot标签中的内容
2.具名插槽(有命名的插槽)
可以使用name来配置如何分发内容;
没有name的slot被视为默认插槽;

<body>
<div id="app">
    <hello>
        <header slot="h">这是头部</header>
        <h1 slot="b">这是身体</h1>
        <footer>这是脚步</footer>
    </hello>
</div>
</body>
</html>
<script src="bower_components/vue/dist/vue.js"></script>
<script>
(function (){
    let hello= {
        template:"<div><slot name='h'></slot><h1>这是一个分割线</h1><slot name='b'></slot><h1>这也是一个分隔行</h1><slot></slot></div>"
    }
    new Vue({
        el:"#app",
        components:{
            hello
        }
    })
})();
</script>

组件间通信
1、父与子通信 (props down

<body>
<div id="app">
    <father></father>
</div>
</body>
</html>
<script src="bower_components/vue/dist/vue.js"></script>
<script>
(function (){
    let grandson={
        template:"<h3>后代组件: {{title}}</h3>",
        props:["title"]
    };
    let son={
        template:"<div><h3>子组件</h3><grandson :title='title'> {{title}}</grandson></div>",
        props:["title"],
        components: {
            grandson
        }
    };
    let father={
        data(){
            return {
                title:"父传子标题"
            }
        },
        template:"<div><h1>父组件</h1><hr><son :title='title'></son></div>",
        components:{
            son
        }
    }
    new Vue({
        el:"#app",
        data:{
            msg:"hello"
        },
        components:{
            father
        }
    })
})();
</script>

2、子与父通信 (events up)

<body>
<div id="app">
    <news-list></news-list>
</div>
</body>
</html>
<script src="bower_components/vue/dist/vue.js"></script>
<script>
(function (){
    //木偶  无状态的组件:根据父组件的数据来显示

子传父就是通过给子元素添加一个事件来触发父元素中的监听,然后通过回调函数来重新渲染页面

    let NewsItem= {
        template:"<li><a>{{title}}</a> <a style='color: red' @click='del(index)'>X</a></li>",
        props:["title","index"],
        methods:{
            del(i){
                this.$emit("xx",i); //触发父组件中的监听事件
            }
        }
    }
    //智能组件:有状态的组件
    let NewsList ={
        data(){
            return {
                list:[
                    "我是第一条第一条记得这事第一条",
                    "我是第二条第二条记得这事第二条"
                ]
            }
        },//this.$on("xx",del)
        template: "<ul><news-item @xx='del' :title='n' :index='i' v-for='(n,i) in list'></news-item> 
       </ul>",
        components:{
            NewsItem
        },
        methods:{
            del(i){
                this.list.splice(i,1);
            }
        }
    }
    new Vue({
        el:"#app",
        components:{
            NewsList
        }
    })
})();
</script>

3、ref

<body>
<div id="app">
    <div ref="xx">aaaa</div>
    <div ref="yy">bbbbbb</div>
    <button @click="changeColor">变色</button>
    <one ref="o"></one>
    <button @click="update">+</button>
    <hr>

</div>
</body>
</html>
<script src="bower_components/vue/dist/vue.js"></script>
<script>
(function (){
    let one = {
        data(){
          return {
              num:0
          }
        },
        methods:{
            update(){
                this.num++
            }
        },
        template:"<div><h1>{{num}}</h1></div>"
    }
    new Vue({
        el:"#app",
        data:{
            msg:"hello vue"
        },
        methods:{
            changeColor(){
                console.log(this.$refs.xx.style.backgroundColor="red");
            },
            update(){
                this.$refs.o.num++;
            }
        },
        components:{
            one
        }
    })
})();
</script>

4、兄弟组件通信

<body>
<div id="app">
    <one></one>
    <hr>
    <two></two>
</div>
</body>
</html>
<script src="bower_components/vue/dist/vue.js"></script>
<script>
(function (){
    let one ={
        data(){
            return {
                msg:""
            }
        },
        template:"<div><h1>one组件:</h1><button>给组件two传数据</button><h1>收到two传的值是:{{msg}} 
      </h1></div>",
        mounted(){
            this.$eventBus.$on("xx",(a)=>{
                this.msg=a;
            })
        }
    }
    let two = {
        template: "<div><h1>two组件:</h1><button @click='send'>给组件one传数据</button><h1>收到one传的值 
   是:{{msg}}</h1></div>",
        methods:{
            send(){
                this.$eventBus.$emit("xx","hello one from two");
            }
        }
    }
    let eventBus = new Vue();
    Vue.prototype.$eventBus = eventBus;

    new Vue({
        el:"#app",
        data:{
            msg:"hello vue"
        },
        components:{
            one,
            two
        }
    })
})();
</script>

5、兄弟的缓存方式

 <body>
 <div id="app">
    <a @click="flag=true">第一步</a>|<a @click="flag=false">第二部</a>
    <hr>
    <keep-alive>
        <one v-if="flag"></one>
        <two v-else></two>
    </keep-alive>
  </div>
  <script src="bower_components/vue/dist/vue.js"></script>
  <script>
  (function (){
    let one ={
        data(){
            return {
                name:""
            }
        },
        template:"<div>用户名: <input type='text' v-model='name'>{{name}}</div>"
    }
    let two ={
        data(){
            return {
                pwd:""
            }
        },
        template:"<div>密码: <input type='text' v-model='pwd'>{{pwd}}</div>"
    }

    new Vue({
        el:"#app",
        data:{
            flag:""
        },
        components:{
            one,two
        }
    })
})();
</script>
</body>
</html>

6、动态组件的绑定(is)

<body>
<div id="app">
    <a @click="flag='one'">第一步</a><a @click="flag='two'">第二步</a>
    <keep-alive>
        <div :is="flag"></div>
    </keep-alive>

</div>
</body>
</html>
 <script src="bower_components/vue/dist/vue.js"></script>
<script>
(function (){
    let one ={
        data(){
            return {
                name:""
            }
        },
        template:"<div>用户名: <input type='text' v-model='name'>{{name}}</div>"
    };
    let two ={
        data(){
            return {
                pwd:""
            }
        },
        template:"<div>密码: <input type='text' v-model='pwd'>{{pwd}}</div>"
    };

    new Vue({
        el:"#app",
        data:{
            flag:"one"
        },
        components:{
            one,two
        }
    })
})();
</script>

补充
1.vue中的自定义事件

(function (){
    let vm = new Vue({
        el:"#app",
        data:{
            msg:"hello vue"
        }
    })

    //绑定一个事件 @xx='del'
    vm.$on("xx",(a,b)=>{
        console.log(a);
    })
    vm.$emit("xx",1,2);
    //自定义时间 on emit
})();
Last modification:October 30th, 2019 at 12:40 am
来杯coffee吧