Vue学习笔记(三) – 组件的基本用法
Vue学习笔记
作者:黄志成
博客:地址
组件
组件是Vue最核心的功能,也是整个框架设计最精彩的地方。
组件就是将相同部分复用起来.
组件用法:注册组件 -> 挂载组件
注册有全局注册和局部注册两种方式.
// 全局注册
Vue.component('my-component', {
// option
})
// 局部注册
var child = {
// option
}
var app = new Vue({
el: '#app',
components: {
'my-component': child
}
})
下面来个demo 看看 什么是组件
这是一个计数器.
<!DOCTYPE html>
<html>
<head>
<title>Vue</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<my-count></my-count>
<my-count></my-count>
<my-count></my-count>
</div>
<script type="text/javascript">
Vue.component('my-count', {
template: '<div><h1>{{count}}</h1><button @click="addCount">点击我+1</button></div>',
data: function () {
return {
count: 0
}
},
methods: {
addCount: function () {
this.count++;
}
}
});
var app = new Vue({
el: "#app",
})
</script>
</body>
</html>
组件不仅要把模板内容进行复用,更重要的是组件之间要通信.父组件正确的向子组件传递数据,子组件根据传递的数据显示不同内容或者是操作.
在Vue组件中,用props接收父级的数据。下面看看如何使用props
<!DOCTYPE html>
<html>
<head>
<title>Vue</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<my-count init_num="1"></my-count>
<my-count init_num="2"></my-count>
<my-count init_num="1"></my-count>
</div>
<script type="text/javascript">
Vue.component('my-count', {
props: ['init_num'],
template: '<div><h1>{{count}}</h1><button @click="addCount">点击我+1</button></div>',
data: function () {
return {
count: this.init_num
}
},
methods: {
addCount: function () {
this.count++;
}
}
});
var app = new Vue({
el: "#app",
})
</script>
</body>
</html>
现在通过传入 init_num 来设置每个计数器的初始值。 当然你也可以动态的传递这些初始值 通过 v-bind:init_num 的方式
在Vue2中取消了双向数据流.采用单向数据流.只有父组件给子组件传递.之所以这样设计是尽可能的将父子组件解耦.
下面通过一个Demo 来看看
<!DOCTYPE html>
<html>
<head>
<title>Vue</title>
</head>
<body>
<div id="app">
<my-component :msg="nihao"></my-component>
<my-component :msg="buhao"></my-component>
</div>
</body>
<script src="vue.js"></script>
<script type="text/javascript">
Vue.component('my-component', {
props : ['msg'],
template: '<div> <h1>{{ msg }}</h1> <button @click="btnClick">点击</button> <br /> <input type="text" v-model="msg"> </div>',
data: function () {
return {
msgContent: this.msg
}
},
methods: {
btnClick: function () {
alert(this.msgContent);
}
}
});
var app = new Vue({
el: "#app",
data: {
nihao: '这是父组件的内容123',
buhao: '这是父组件2'
}
});
</script>
</html>
如果改变了子组件的数据会报一个错误.
解决方法就是子组件用data接收props传递过来的数据.在自己的作用域下可以随意修改.
Vue.component('my-component', {
props : ['msg'],
template: '<div> <h1>{{ msgContent }}</h1> <button @click="btnClick">点击</button> <br /> <input type="text" v-model="msgContent"> </div>',
data: function () {
return {
msgContent: this.msg
}
},
methods: {
btnClick: function () {
alert(this.msgContent);
}
}
});
改成这样.问题就解决了。
上面说完了父组件向子组件传递数据的方式,接着我们继续看看子组件向父组件传递数据的方式吧
<!DOCTYPE html>
<html>
<head>
<title>Vue</title>
</head>
<body>
<div id="app">
<my-con @a="getA"></my-con>
</div>
</body>
<script src="vue.js"></script>
<script type="text/javascript">
Vue.component('my-con', {
data :function () {
return {
count: 0,
aaa: 12344
}
},
template: '<div><h1>{{ count }}</h1><button @click="handerInc">+1</button></div>',
methods: {
handerInc: function () {
this.count++;
this.$emit('a', this.count,this.aaa);
}
}
});
var app = new Vue({
el: "#app",
data: {
count: 0
},
methods: {
getA: function (val,a) {
console.log("val is :" + val);
console.log("a is :" + a);
}
}
});
</script>
</html>
我们可以通过this.$emit向父组件传递数据
我们也可以使用 v-model 。
<!DOCTYPE html>
<html>
<head>
<title>Vue</title>
</head>
<body>
<div id="app">
<my-con v-model="getA"></my-con>
<h1>{{ getA }}</h1>
</div>
</body>
<script src="vue.js"></script>
<script type="text/javascript">
Vue.component('my-con', {
data :function () {
return {
count: 0,
}
},
template: '<div><h1>{{ count }}</h1><button @click="handerInc">+1</button></div>',
methods: {
handerInc: function () {
this.count++;
this.$emit('input', this.count);
}
}
});
var app = new Vue({
el: "#app",
data: {
getA: 0
},
});
</script>
</html>
使用V-model 的前提就是 this.$emit('input', this.count); 事件名必须是input
v-model 还可以用来创建自定义表单输入组件,进行数据双向绑定
<!DOCTYPE html>
<html>
<head>
<title>Vue</title>
</head>
<body>
<div id="app">
<my-con v-model="total"></my-con>
<button @click="inc">点击+1</button>
</div>
</body>
<script src="vue.js"></script>
<script type="text/javascript">
Vue.component('my-con', {
props: ['value'],
template: '<div><input type="number" :value="value" @input="updateValue" /></div>',
methods: {
updateValue: function (event) {
console.log(event)
this.$emit('input',event.target.value);
}
}
});
var app = new Vue({
el: "#app",
data: {
total: 0,
},
methods: {
inc: function () {
this.total++;
}
}
});
</script>
</html>
我们还推荐使用一个空的Vue实例来作为中央事件总线(BUS),也就是一个中介
<!DOCTYPE html>
<html>
<head>
<title>Vue</title>
</head>
<body>
<div id="app">
<my-con></my-con>
{{msg}}
</div>
</body>
<script src="vue.js"></script>
<script type="text/javascript">
const bus = new Vue();
Vue.component('my-con', {
template: '<button @click="btn_click">点击传递信息</button>',
methods: {
btn_click: function () {
bus.$emit('on-message','this is my-con');
}
}
});
var app = new Vue({
el: "#app",
data: {
msg: '',
},
mounted (){
bus.$on('on-message', (msg) => {
this.msg = msg;
});
}
});
</script>
</html>
除此之外还有父链和子组件索引.用来组件通信.
下面说说 使用slot分发内容
在子组件使用特殊的
<!DOCTYPE html>
<html>
<head>
<title>Vue</title>
</head>
<body>
<div id="app">
<my-con>{{msg}}</my-con>
</div>
</body>
<script src="vue.js"></script>
<script type="text/javascript">
Vue.component('my-con', {
template: '<div><slot>这是默认内容</slot></div>',
});
var app = new Vue({
el: "#app",
data: {
msg: '这是传入的内容',
}
});
</script>
</html>
还可以存在多个solt标签
<!DOCTYPE html>
<html>
<head>
<title>Vue</title>
</head>
<body>
<div id="app">
<my-con>
<div slot="header">
111
</div>
<div slot="footer">
{{msg}}
</div>
</my-con>
</div>
</body>
<script src="vue.js"></script>
<script type="text/javascript">
Vue.component('my-con', {
template: '<div><slot name="header">头部</slot><slot name="footer">底部</slot></div>',
});
var app = new Vue({
el: "#app",
data: {
msg: '这是传入的内容',
}
});
</script>
</html>
作用域插槽是一个特殊的slot,使用一个可复用的模板替换已渲染的元素。其实就是子组件与父组件的数据动态交互的一种常见案例
<!DOCTYPE html>
<html>
<head>
<title>Vue</title>
</head>
<body>
<div id="app">
<my-con>
<template slot="a" scope="props">
{{props.msg}}
</template>
</my-con>
</div>
</body>
<script src="vue.js"></script>
<script type="text/javascript">
Vue.component('my-con', {
template: '<div><slot name="a" msg="这是信息内容"></slot></div>',
});
var app = new Vue({
el: "#app",
data: {
msg: '这是传入的内容',
}
});
</script>
</html>
递归组件 - 顾名思义就是自己调用自己.需要注意的是给递归的组件设置name 名
,当然还需要限制递归数量,不然会溢出。
<!DOCTYPE html>
<html>
<head>
<title>Vue</title>
</head>
<body>
<div id="app">
<my-con :count="1">
</my-con>
</div>
</body>
<script src="vue.js"></script>
<script type="text/javascript">
Vue.component('my-con', {
name: 'my-con',
props: {
count: {
type: Number
}
},
data: function () {
return {
thisCount: this.count
}
},
template: '<div class="child"><my-con :count="count + 1" v-if="count < 3"></my-con>{{thisCount}}</div>'
});
var app = new Vue({
el: "#app"
});
</script>
</html>
还有内联模板,就是给组件标签加一个 inline-template ,组件就会把它的内容当做模板,而不会把它内容分发
<!DOCTYPE html>
<html>
<head>
<title>Vue</title>
</head>
<body>
<div id="app">
<my-con inline-template>
<div>
{{message}}
</div>
</my-con>
</div>
</body>
<script src="vue.js"></script>
<script type="text/javascript">
Vue.component('my-con', {
data: function () {
return {
message: "这是子组件内容"
}
},
template: '<div class="child"></div>'
});
var app = new Vue({
el: "#app",
data: {
message: "这是父组件内容"
}
});
</script>
</html>
需要注意的就是它的作用域.
最后结果是 “这是子组件内容”
动态组件 Vue 提供了一个
<!DOCTYPE html>
<html>
<head>
<title>Vue</title>
</head>
<body>
<div id="app">
<component :is="currentView"></component>
</div>
</body>
<script src="vue.js"></script>
<script type="text/javascript">
var app = new Vue({
el: "#app",
data: {
currentView: "comA"
},
components: {
comA: {
template: '<div>这是 comA </div>'
},
comB: {
template: '<div>这是 comB </div>'
},
comC: {
template: '<div>这是 comC </div>'
}
}
});
</script>
</html>
- 异步组件
<!DOCTYPE html>
<html>
<head>
<title>Vue</title>
</head>
<body>
<div id="app">
<my-con></my-con>
</div>
</body>
<script src="vue.js"></script>
<script type="text/javascript">
Vue.component('my-con', function (resolve, reject) {
window.setTimeout(function () {
resolve({
template: '<div>这是异步加载的内容</div>'
})
}, 2000)
});
var app = new Vue({
el: "#app"
});
</script>
</html>
- $nextTick
Vue 实现响应式并不是数据发生变化之后 DOM 立即变化,而是按一定的策略进行 DOM 的更新。
$nextTick 是在下次 DOM 更新循环结束之后执行延迟回调,在修改数据之后使用 $nextTick,则可以在回调中获取更新后的 DOM,API 文档中官方示例如下:
new Vue({
// ...
methods: {
// ...
example: function () {
// modify data
this.message = 'changed'
// DOM is not updated yet
this.$nextTick(function () {
// DOM is now updated
// `this` is bound to the current instance
this.doSomethingElse()
})
}
}
- X-Templates
在没有使用webpack的时候,组件的template属性会很长,效率低下
Vue 提倡的一种方式是 在
- 手动挂载实例
我们现在创建的实例都是通过 new Vue() 形式创建的.在一些非常特殊的情况下,要去动态创建vue实例,vue 提供了 Vue.extend 和 $mount 两个方法
<!DOCTYPE html>
<html>
<head>
<title>Vue</title>
</head>
<body>
<div id="app">
</div>
</body>
<script src="vue.js"></script>
<script type="text/javascript">
var MyComponent = Vue.extend({
template: '<div>这是动态加载的内容</div>'
})
new MyComponent().$mount("#app")
</script>
</html>
页面中会打印出 这是动态加载的内容
除了这种写法外,还有两种
new MyComponent({
el: "#app"
})
var component = new MyComponent().$mount();
document.getElementById('app').appendChild(component.$el);
手动挂载组件是一种高端的用法 在业务代码中几乎用不到.
上面就是组件所有的基础内容.
发表评论