13.vue组件
vue组件(一)
组件嵌套:
1.全局嵌套:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<script src="vue.js"></script>
<script>
Vue.component("aaa",{
template:`<div>组件A <bbb></bbb></div>`
});//子组件放在父组件的模板里
Vue.component("bbb",{
template:`<div>组件B</div>`
});
window.onload = function(){
let vm = new Vue({
el:"#app"
});
};
</script>
</head>
<body>
<div id="app">
<aaa></aaa>
</div>
</body>
</html>
res:
2.局部嵌套:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<script src="vue.js"></script>
<script>
window.onload = function(){
let vm = new Vue({
el:"#app",
components:{
"aaa":{
template:`<div>组件A<bbb></bbb></div>`,
//子组件必须放在父组件的属性里
components:{
"bbb":{
template:`<div>组件B</div>`
}
}
},
/*"bbb":{
template:`<div>组件B</div>`
} */ //错误
}
});
};
</script>
</head>
<body>
<div id="app">
<aaa></aaa>
</div>
</body>
</html>
res:
组件通信(重要)
1、props/$emit
1.数据的双向绑定:
v-model后的变量名相同
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<script src="vue.js"></script>
<script>
window.onload = function(){
let vm = new Vue({
el:"#app",
data:{
msg:"abc"
}
});
};
</script>
</head>
<body>
<div id="app">
<input v-model="msg" type="text" value=""/><br />
<input v-model="msg" type="text" value=""/><br />
{{msg}}<br />
</div>
</body>
</html>
res:
2.父传子,子传父props/$emit, 用ev.target.value或事件监听
(1)ev.target.value
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<script src="vue.js"></script>
<script>
Vue.component("mycomponent",{
props:["msg"],
template:`<div><input @input="show" type="text" :value="msg"/>{{msg}}</div>`,
methods:{
show(ev){
console.log(22222);
this.$emit("abc",ev.target.value);
//传子组件value值
}
}
});
window.onload = function(){
let vm = new Vue({
el:"#app",
data:{
msg:"abc"
},
methods:{
fn(data){
console.log(11111,data);
this.msg = data;
}
}
});
};
</script>
</head>
<body>
<div id="app">
<input v-model="msg" type="text" value=""/>{{msg}}<br />
<hr />
<mycomponent :msg="msg" @abc="fn"></mycomponent>
</div>
</body>
</html>
res:
(2)事件监听
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<script src="vue.js"></script>
<script>
Vue.component("mycomponent",{
props:["msg"],
template:`<div><input v-model="msg2" type="text" value=""/>{{msg}}</div>`,
data(){
return {msg2:this.msg}
},
watch:{
msg(){
this.msg2 = this.msg;
},
msg2(){
this.$emit("abc",this.msg2);
}
}
});
window.onload = function(){
let vm = new Vue({
el:"#app",
data:{
msg:"abc"
},
methods:{
fn(data){
console.log(11111,data);
this.msg = data;
}
}
});
};
</script>
</head>
<body>
<div id="app">
<input v-model="msg" type="text" value=""/>{{msg}}<br />
<hr />
<mycomponent :msg="msg" @abc="fn"></mycomponent>
</div>
</body>
</html>
res:
2.对象—— 引用
子与父操控同一个对象
1.父传子,子传父props,value
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<script src="vue.js"></script>
<script>
Vue.component("mycomponent",{
props:["msg"],
template:`<div><input v-model="msg.value" type="text" value=""/>{{msg.value}}</div>`
});
window.onload = function(){
let vm = new Vue({
el:"#app",
data:{
//msg:"abc"
msg:{value:"abc"}
//对象--msg.value引用
}
});
};
</script>
</head>
<body>
<div id="app">
<input v-model="msg.value" type="text" value=""/>{{msg.value}}<br />
<hr />
<mycomponent :msg="msg"></mycomponent>
</div>
</body>
</html>
res:
3.$children / $parent / $root
1. $children
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<script src="vue.js"></script>
<script>
Vue.component("aaa",{
template:`<div>组件A----{{a}}</div>` ,
data(){
return {a:"a"}
}
});
Vue.component("bbb",{
template:`<div>组件B</div>`
});
window.onload = function(){
let vm = new Vue({
el:"#app",
methods:{
show(){
//$children
console.log(this.$children);
this.$children[0].$el.style.background = "red"
this.$children[0].a = "abc"
}
}
});
};
</script>
</head>
<body>
<div id="app">
<input @click="show" type="button" value=" 按钮" />
<aaa></aaa>
<bbb></bbb>
</div>
</body>
</html>
res:
2.$parent
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<script src="vue.js"></script>
<script>
Vue.component("aaa",{
template:`<div @click="show">组件A----{{a}}</div>`,
data(){
return {a:"a"}
},
methods:{
show(){
//parent/root
console.log(this.$parent == this.$root);
//this.$parent.msg = "哈哈哈";
this.$root.msg = "哈哈哈";
}
}
});
Vue.component("bbb",{
template:`<div>组件B</div>`
});
window.onload = function(){
let vm = new Vue({
el:"#app",
data:{
msg:"Vue"
},
methods:{
show(){
}
}
});
};
</script>
</head>
<body>
<div id="app">
<input @click="show" type="button" value=" 按钮" />{{msg}}
<hr />
<aaa></aaa>
<bbb></bbb>
</div>
</body>
</html>
res:
3.$root
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<script src="vue.js"></script>
<script>
Vue.component("aaa",{
template:`<div @click="show">组件A----{{a}} <bbb></bbb></div>`,
data(){
return {a:"a"}
},
methods:{
show(){
//parent/root
console.log(this.$parent == this.$root);
//this.$parent.msg = "哈哈哈";
this.$root.msg = "哈哈哈";
}
}
});
Vue.component("bbb",{
template:`<div @click.stop="show">组件B</div>`,
methods:{
show(){
//parent/root
console.log(this.$parent == this.$root);
this.$parent.a = "aa";
this.$root.msg = "嘻嘻嘻";
}
}
});
window.onload = function(){
let vm = new Vue({
el:"#app",
data:{
msg:"Vue"
},
methods:{
show(){
}
}
});
};
</script>
</head>
<body>
<div id="app">
<input @click="show" type="button" value=" 按钮" />{{msg}}
<hr />
<aaa></aaa>
</div>
</body>
</html>
res:
4、ref/$refs
this.$refs以数组的形式获取全部的ref
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<script src="vue.js"></script>
<script>
//ref
Vue.component("aaa",{
template:`<div>组件A----{{a}} </div>`,
data(){
return {a:"a"}
}
});
Vue.component("bbb",{
template:`<div>组件B</div>`,
});
window.onload = function(){
let vm = new Vue({
el:"#app",
data:{
msg:"Vue"
},
methods:{
show(){
console.log(this.$refs);
//this.$refs以数组的形式获取全部的ref
this.$refs.aaa.$el.style.background = "pink";
this.$refs.aaa.a = "pink";
}
}
});
};
</script>
</head>
<body>
<div id="app">
<input @click="show" type="button" value=" 按钮" />{{msg}}
<hr />
<aaa ref="aaa"></aaa>
<bbb ref="bbb"></bbb>
</div>
</body>
</html>
res:
5、eventBus事件总线
let eventBus = new Vue();
eventBus.$emit(sEv,data);
eventBus.$on(sEv,data=>{})
exp:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<script src="vue.js"></script>
<script>
//事件总线——eventBus emit/on
Vue.component("aaa",{
template:`<div @click="show">组件A----{{a}} </div>`,
data(){
return {a:"a"}
},
created(){
eventBus.$on("chagnea",data=>{
this.a = data;
});
},
methods:{
show(){
eventBus.$emit("chagneb","我想你了");
}
}
});
Vue.component("bbb",{
template:`<div @click="show">组件B----{{b}}</div>`,
data(){
return {b:"b"}
},
created(){
eventBus.$on("chagneb",data=>{
this.b = data;
});
},
methods:{
show(){
eventBus.$emit("chagnea","我也想你了");
}
}
});
let eventBus = new Vue();
window.onload = function(){
let vm = new Vue({
el:"#app",
data:{
msg:"Vue"
},
methods:{
show(){
}
}
});
};
</script>
</head>
<body>
<div id="app">
<aaa></aaa>
<bbb></bbb>
</div>
</body>
</html>
res:
6、sync
sync --> this.$emit("updata:xxx",data);
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<script src="vue.js"></script>
<script>
//sync
Vue.component("mycomponent",{
props:["msg"],
template:`<div><input @input="show" v-model="msg2" type="text" value=""/>{{msg}}</div>`,
data(){
return {msg2:this.msg}
},
methods:{
show(){
this.$emit("update:msg",this.msg2);
}
}
});
window.onload = function(){
let vm = new Vue({
el:"#app",
data:{
msg:"abc"
},
methods:{
fn(data){
this.msg = data;
}
}
});
};
</script>
</head>
<body>
<div id="app">
<input v-model="msg" type="text" value=""/>{{msg}}<br />
<hr />
//@update:msg="fn",事件
<mycomponent :msg="msg" @update:msg="fn" ></mycomponent>
// :msg.sync="msg",固定写法
<mycomponent :msg.sync="msg" ></mycomponent>
</div>
</body>
</html>
res:
7、v-model
v-model --> this.$emit("input",data);
exp:自增
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<script src="vue.js"></script>
<script>
//sync
Vue.component("mycomponent",{
template:`<div><input @click="show" type="button" value="plus"/></div>`,
data(){
return {count:0}
},
methods:{
show(){
//"input"固定写法 this.$emit("input",++this.count);
}
}
});
window.onload = function(){
let vm = new Vue({
el:"#app",
data:{
count:0
},
methods:{
show(data){
console.log(1,data);
this.count = data;
}
}
});
};
</script>
</head>
<body>
<div id="app">
{{count}}
<hr />
<mycomponent v-model="count" ></mycomponent>
</div>
</body>
</html>
res:
vue组件(二)
1.创建组件
1、全局 Vue.component
2、局部 new Vue({components:{}});
3、Vue.extend
let VueComponent = Vue.extend(options);
Vue.component("名字",VueComponent);
返回值:Vue.extend、Vue.component 返回的都是VueComponent
new VueComponent().$mount("#app");
Vue.extend可以没有参数
let VueComponent = Vue.extend();
new VueComponent(options).$mount("#app");
获取模板元素:
let tmp = new VueComponent([options]).$mount().$el;
document.body.appendChild(tmp);
exp:
++Vue.extend++
全局组件:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<script src="vue.js"></script>
<script>
//Vue.extend
//VueComponent
let mycomponent = Vue.extend({
template:`<div>Vue.extend组件</div>`
});
Vue.component("mycomponent",mycomponent);//("组件名",VueComponent)
window.onload = function(){
let vm = new Vue({
el:"#app",
});
};
</script>
</head>
<body>
<div id="app">
<mycomponent></mycomponent>
</div>
</body>
</html>
局部组件:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<script src="vue.js"></script>
<script>
//Vue.extend
let mycomponent = Vue.extend({
template:`<div>Vue.extend组件</div>`
});
//new Vue({components:{}});
window.onload = function(){
let vm = new Vue({
el:"#app",
components:{mycomponent}
});
};
</script>
</head>
<body>
<div id="app">
<mycomponent></mycomponent>
</div>
</body>
</html>
//最大组件 Vue
let VueComponent = Vue.extend(options);//new时不带参数
let VueComponent = Vue.extend();//new时带参数
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<script src="vue.js"></script>
<script>
let Comp1 = Vue.extend({
template:`<div>Vue.extend组件</div>`
});
let Comp2 = Vue.extend();
console.log(1,Comp1);
console.log(2,Comp2);
window.onload = function(){
//let oDiv = new Comp1().$mount().$el;
//获取模板元素:
let oDiv = new Comp2({
template:`<div>new Comp2组件</div>`
}).$mount().$el;
console.log(3,oDiv);
document.body.appendChild(oDiv);
};
</script>
</head>
<body>
<div id="app">
</div>
</body>
</html>
静态组件 动态组件
必须有is
静态--> is="组件的名称"
动态--> :is="变量或者值 '组件的名称'"
<div is="组件的名称"></div>
<div :is="变量或者值 '组件的名称'"></div>
exp:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<script src="vue.js"></script>
<script>
Vue.component("aaa",{
template:`<div>组件A</div>`
});
Vue.component("bbb",{
template:`<div>组件B</div>`
});
window.onload = function(){
let vm = new Vue({
el:"#app",
data:{
comp:"aaa"
},
methods:{
toggle(){
this.comp = this.comp=="aaa"?"bbb":"aaa";
}
}
});
};
</script>
</head>
<body>
<div id="app">
<input @click="comp='aaa'" type="button" value="组件A"/>
<input @click="comp='bbb'" type="button" value="组件B"/>
<input @click="toggle" type="button" value="toggle"/>
<!-- 动态-->
<div :is="comp"></div>
</div>
</body>
</html>
3.异步组件
Vue.component(组件名称,(resolve,reject)=>{
axios.get(url).then(res=>{
resolve({
template:res.data
});
});
});
exp:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<script src="vue.js"></script>
<script src="axios.js"></script>
<script>
Vue.component("mycomp",(resolve,reject)=>{
axios.get("abc2.html").then(res=>{
setTimeout(()=>{
console.log(res.data);
let oDiv = document.createElement("div");
oDiv.innerHTML = res.data;
//读取成功放到template
resolve({
//template:res.data
//template:oDiv.children[0].innerHTML
template:oDiv.children[0]
});
},2000);
});
});
window.onload=function(){
let vm = new Vue({
el:"#app",
})
}
</script>
</head>
<body>
<div id="app">
<mycomp></mycomp>
</div>
</body>
</html>
4.组件的生命周期
activated //激活
deactivated //休眠
必须跟 keep-alive标签
<keep-alive>
<div :is="'组件名称'"></div>
</keep-alive>
exp:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<script src="vue.js"></script>
<script>
Vue.component("aaa",{
template:`<div>组件A</div>`,
activated(){
console.log("A-----activated");//激活
},
deactivated(){
console.log("A-----deactivated");//休眠
},
beforeDestroy(){
console.log("A-----beforeDestroy");
},
destroyed(){
console.log("A-----destroyed");
},
});
Vue.component("bbb",{
template:`<div>组件B</div>`,
activated(){
console.log("B-----activated");//激活
},
deactivated(){
console.log("B-----deactivated");//休眠
},
beforeDestroy(){
console.log("B-----beforeDestroy");
},
destroyed(){
console.log("B-----destroyed");
},
});
window.onload = function(){
vm = new Vue({
el:"#app",
data:{
a:"aaa"
},
methods:{
toggle(){
this.a = this.a == "aaa"?"bbb":"aaa";
}
}
});
};
</script>
</head>
<body>
<div id="app">
<input @click="toggle" type="button" value="toggle"/>
<keep-alive>
<div :is="a"></div>
</keep-alive>
</div>
</body>
</html>
res:
错误的生命周期
errorCaptured
执行条件:
只能捕获子组件的异常,无法捕获自己发生的错误!
异常会冒泡!
exp:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<script src="vue.js"></script>
<script>
//异常会冒泡
Vue.component("aaa",{
template:`<div>组件A <bbb></bbb></div>`,
errorCaptured(){//捕获异常
console.log("A-----errorCaptured");
},
});
Vue.component("bbb",{
template:`<div>组件B</div>`,
data(){
return {
a
//a is not defined
}
},
errorCaptured(){
console.log("B-----errorCaptured");
}
});
window.onload = function(){
vm = new Vue({
el:"#app",
data:{
//a
},
errorCaptured(){
console.log("Vue-----errorCaptured");
}
});
};
</script>
</head>
<body>
<div id="app">
<aaa></aaa>
</div>
</body>
</html>
冒泡:bbb-->aaa-->app
res:
5.组件渲染:
Vue 推荐在绝大多数情况下使用 template 来创建你的 HTML。然而在一些场景中,你真的需要 JavaScript 的完全编程的能力,这就是 render 函数,它比 template 更接近编译器。
render(createElement){
return createElement(
"h1", // tag name 标签名称
"标题" //内容: {属性:{属性值}}}
)
}
exp:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<script src="vue.js"></script>
<script>
window.onload = function(){
let vm = new Vue({
el:"#app",
render(createElement){
return createElement(
"ul", // tag name 标签名称
{
attrs: {
id: 'ul1'
},
'class': {
foo: true,
bar: false
},
style: {
color: 'red',
fontSize: '14px'
},
},
[
createElement("li","111"),
createElement("li","222"),
createElement("li","333"),
]
)
}
});
};
</script>
</head>
<body>
<div id="app">
<!--
<ul>
<li>111</li>
<li>222</li>
<li>333</li>
</ul>
-->
</div>
</body>
</html>
res:
6.混入
合并.
exp:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<script src="vue.js"></script>
<script>
let json1 = {
data:{
msg:"abc",
a:"a",
b:"b",
},
methods:{
fn(){
console.log("fn");
}
}
};
let json2 = {
data:{
c:"c",
},
computed:{
computedXXX(){
console.log("computedXXX");
}
} ,
watch:{
c(){
console.log("watch c");
}
}
}
window.onload = function(){
let vm = new Vue({
//mixins: [json],
el:"#app",
data:{
msg:"Vue",
},
methods:{
show(){
console.log("show");
}
},
mixins: [json1,json2],
});
console.log(vm);
};
</script>
</head>
<body>
<div id="app">
</div>
</body>
</html>
res:
对与父组件已存在的实例,不会被改变
7.自定义指令
v-xxx
Vue.directive("xxx", function (el, binding) {
console.log(el,binding);
el.style.color = "xxx";
})
v-red 字体变红
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<script src="vue.js"></script>
<script>
Vue.directive("red", function (el, binding) {
console.log(el,binding);
el.style.color = "red";
})
window.onload = function(){
let vm = new Vue({
el:"#app",
});
console.log(vm);
};
</script>
</head>
<body>
<div id="app">
<div v-red>自定义指令</div>
</div>
</body>
</html>
res:
v-color="'red'" 字体变红
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<script src="vue.js"></script>
<script>
Vue.directive("color", function (el, binding) {
console.log(el,binding);
el.style.color = binding.value;
})
window.onload = function(){
let vm = new Vue({
el:"#app",
});
};
</script>
</head>
<body>
<div id="app">
<div v-color="'red'">自定义指令</div>
</div>
</body>
</html>
res:
自定义样式style
v-style="{width:'200px',height:'200px',background:'green'}"
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<script src="vue.js"></script>
<script>
/*
Vue.directive("style", function (el, binding) {
console.log(el,binding);
for(let name in binding.value){
el.style[name] = binding.value[name];
}
})
*/
window.onload = function(){
let vm = new Vue({
el:"#app",
directives:{
style(el, binding){
console.log(el,binding);
for(let name in binding.value){
el.style[name] = binding.value[name];
}
}
}
});
};
</script>
</head>
<body>
<div id="app">
<div v-style="{width:'200px',height:'200px',background:'green'}">自定义指令</div>
</div>
</body>
</html>
res:
自定义拖拽:v-drag
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<script src="vue.js"></script>
<script>
Vue.directive("drag",{
bind(el, binding){
console.log("bind");
el.style.position = "absolute";
el.style.left = 0;
el.style.top = 0;
el.style.width = "100px";
el.style.height = "100px";
el.style.background = "red";
},
inserted(el, binding){
el.onmousedown = function(ev){
let disX = ev.clientX - el.offsetLeft;
let disY = ev.clientY - el.offsetTop;
document.onmousemove = function(ev){
el.style.left = ev.clientX - disX + "px";
el.style.top = ev.clientY - disY + "px";
};
document.onmouseup = function(){
document.onmousemove = null;
document.onmouseup = null;
};
return false;
};
},
update(el, binding){
console.log("update");
},
componentUpdated(el, binding){
console.log("componentUpdated");
},
unbind(el, binding){
console.log("unbind");
},
})
window.onload = function(){
let vm = new Vue({
el:"#app",
data:{
msg:"Vue",
a:true,
},
methods:{
show(){
this.a = false;
this.msg = Math.random();
}
}
});
};
</script>
</head>
<body>
<div id="app">
<div v-if="a" @click="show" v-drag>自定义指令 {{msg}}</div>
</div>
</body>
</html>
res:
v-if: 与unbind
8.过滤器
过滤器:
https://cn.vuejs.org/v2/api/?#Vue-filter
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<script src="vue.js"></script>
<script>
//首字母大写
Vue.filter("capitalize", function (str) {
return str.charAt(0).toUpperCase() + str.substring(1);
});
//字符串反转
/*Vue.filter("reverse", function (str) {
return str.split("").reverse().join("");
});*/
window.onload = function(){
let vm = new Vue({
el:"#app",
data:{
msg:"vue",
},
//字符串反转
filters:{
reverse(str){
return str.split("").reverse().join("");
}
}
});
};
</script>
</head>
<body>
<div id="app">
<input v-model="msg" type="text" value=""/><br />
{{msg}}<br />
{{msg|capitalize}}<br />
{{msg|reverse}}<br />
{{msg|reverse|capitalize}}<br />
{{msg|capitalize|reverse}}<br />
</div>
</body>
</html>
res:
9.nextTick
nextTick https://cn.vuejs.org/v2/api/#Vue-nextTick
将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。它跟全局方法 Vue.nextTick 一样,不同的是回调的 this 自动绑定到调用它的实例上。
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<script src="vue.js"></script>
<script>
window.onload = function(){
let vm = new Vue({
el:"#app",
data:{
msg:"vue",
},
methods:{
show(){
this.msg = Math.random();
this.$nextTick(function(){
let oSpan = document.getElementById("s1");
console.log(oSpan.innerHTML);
});
}
}
});
};
</script>
</head>
<body>
<div id="app">
<input @click="show" type="button" value="按钮"/><br />
<span id="s1">{{msg}}</span>
</div>
</body>
</html>
res:
++不加nextTick,console.log(oSpan.innerHTML)中的结果是上一次的内容.++