一、组件的基本概念
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
})();