Vue学习3 - 属性值的监控watch、组件的创建、组件间的通信、插槽
文章目录
1. 监听属性值的变化 - watch
语法要求:watch里面的函数名必须跟date里面属性名一致
<body>
<div id="vueBox">
<p>{{num}}</p>
<button v-on:click="add">添加</button>
</div>
</body>
<script type="text/javascript">
var vue = new Vue({
el: "#vueBox",
data: {
num: 0
},
methods: {
add: function() {
this.num++;
}
},
watch: {
num: function(newValue, oldValue) {
console.log("新值:"+newValue);
console.log("旧值:"+oldValue);
}
}
})
</script>
2. 组件创建 - component
作用: 相同的部分提取出来,通过包含技术,实现避免重复内容的编写 – 即共享代码
语法特点:
- 该vue对象的定义差不多,区别就是date属性变成函数date()
- 使用时直接<组件名></组件名>即可
- 组件名不可使用驼峰命名法,如果下划线_进行区分单词含义
- 注意:template里面的节点只能有一个祖宗,否则丢失一个祖宗(单个根元素)
不可写成template:"你好
按钮"- 语法:templates属性可以是字符串可以是模板内容
Vue.component("my-tag",{
template: "<div></div>" --字符串
template:`<div></div>` --模板字符串
})
2.1 全局组件
全局组件内部可以引用全局组件
<body>
<div id="vueBox">
<my_component></my_component>
<my_component></my_component>
</div>
</body>
<script type="text/javascript">
Vue.component("my_component", {
template: "<div><p>数字:{{num}}</p><button v-on:click='add'>添加</button></div>",
data() {
return {
num:0
}
},
methods: {
add: function() {
this.num++;
}
}
})
var vue = new Vue({
el: "#vueBox"
})
</script>
2.2 局部组件
局部组件内部不可以引用局部组件
特点: 对于不频繁使用的组件,则将其定义在Vue实例里面 - 成为Vue实例一个子集
<body>
<div id="vueBox">
<my_component></my_component>
<my_component></my_component>
</div>
</body>
<script type="text/javascript">
const myComponent = {
template: "<div><p>数字:{{num}}</p><button v-on:click='add'>添加</button></div>",
data() {
return {
num:0
}
},
methods: {
add: function() {
this.num++;
}
}
}
var vue = new Vue({
el: "#vueBox",
components: {
my_component: myComponent
}
})
</script>
3 组件间的通信
如果一个单页面以组件形式构成,则能刻画成一颗多节点的树
3.1 父向子组件传递数据 - props
3.1.1 动态绑定
注意父组件传递的值只会起效第一次,子组件改变属性值并不会影响父组件,父组件属性值改变并不影响子组件属性值
v-bind:子属性=“父属性” 等价于 :子属性="父属性"
<body>
<div id="vueBox">
<my_component v-bind:content="conten1"></my_component>
<my_component :content="content1"></my_component>
<button v-on:click="add">父组件按钮增加</button>
</div>
</body>
<script type="text/javascript">
Vue.component("my_component", {
template: "<div><p>数字:{{content}}</p><button v-on:click='chang'>字组件按钮增加</button></div>",
props: ["content"],
methods: {
chang: function() {
this.content++
}
}
})
var vue = new Vue({
el: "#vueBox",
data: {
content1: 10
},
methods: {
add: function(){
this.content1++
}
}
})
</script>
执行流程
语法注意
- $emit( 自定义事件名,传参 ) - 自定义组件的事件名
- @组件事件名=‘父组件的方法’ - 触发方法
- $event接收 $emit()的参数值
<body>
<div id="vueBox">
<p>{{num}}</p>
<my-tag @my-add-event="fatherAdd($event)"></my-tag>
</div>
</body>
<script type="text/javascript">
Vue.component("my-tag", {
template: "<p><button v-on:click='add'>数字增加</button></p>",
methods: {
add: function() {
this.$emit("my-add-event", 10)
}
}
})
var vue = new Vue({
el: "#vueBox",
data: {
num: 1
},
methods: {
fatherAdd: function(val) {
this.num = this.num +val;
}
}
})
</script>
3.1.2 静态绑定
<body>
<div id="vueBox">
<my-tag title="父组件传来的字面量"></my-tag>
<my-tag></my-tag>
</div>
</body>
<script type="text/javascript">
Vue.component("my-tag", {
template: "<p>{{msg}}--{{title}}</p>",
data: function(){
return {msg: '组件的内置数据'}
},
props: {
title: {
type: String,
default: "预设的值"
}
}
})
var vue = new Vue({
el: "#vueBox",
data: {
nums: [1,2,3,4]
}
})
</script>
注意:
- v-bind:props属性名:"" – 会自动转对应的数据类型
- props属性名:"" – 全局都为字符串String类型数据
<body>
<div id="vueBox">
<my-tag msg1="200" :msg2="200"></my-tag>
</div>
</body>
<script type="text/javascript">
Vue.component("my-tag", {
template: "<p>{{typeof msg1}} -- {{typeof msg2 }}</p>",
props: ["msg1", "msg2"]
})
var vue = new Vue({
el: "#vueBox",
data: {
}
})
</script>
3.2 子向父组件传递数据 - v-bind:属性绑定
数据传递原则: 单向数据流原则,尽量少的子组件改变父组件的数据
在组件改变父组件属性的时候,必须使用this.$emit(“自定义事件名”) - 发出一个事件出去
并且在绑定函数时 @事件名=“父组件处理函数名” – 父组件对事件相应的处理
<body>
<div id="vueBox">
<p>父组件num:{{num}}</p>
<my_component :num1="num" @add="add" @reduce="reduce" ></my_component>
</div>
</body>
<script type="text/javascript">
Vue.component("my_component", {
template: "<div><p>子组件num1:{{num1}}</p><button v-on:click='add'>增加</button><button v-on:click='reduce'>减少</button></div>",
props: ["num1"],
methods: {
add: function() {
this.$emit("add");
},
reduce: function() {
this.$emit("reduce");
}
}
})
var vue = new Vue({
el: "#vueBox",
data: {
num : 0
},
methods: {
add: function() {
this.num++;
},
reduce: function() {
this.num--;
}
}
})
</script>
3.3 非父子组件间的传递信息
利用中间媒介(事件中心)进行传递
利用一个Vue实例进行做组件间的信息传递
<div id="vueBox">
<button v-on:click="destoryMsg">销魂两兄弟组件的信息交互</button>
<my-tag1></my-tag1>
<my-tag2></my-tag2>
</div>
</body>
<script type="text/javascript">
// 信息中心 - 媒介
var msgCenter = new Vue();
Vue.component("my-tag1", {
template: "<div><p>tag1的num:{{num}}</p><button v-on:click='handle'>数字增加</button></div>",
data: function () {
return {
num: 0
}
},
methods: {
handle: function () {
// 向信息中心发送tag1-event事件
msgCenter.$emit("tag1-event", 20)
}
},
mounted: function () {
// 信息中心在这里进行执行监听tag2-event事件
msgCenter.$on("tag2-event", (val) => {
this.num = this.num + val;
})
}
})
Vue.component("my-tag2", {
template: "<div><p>tag2的num:{{num}}</p><button v-on:click='handle'>数字增加</button></div>",
data: function () {
return {
num: 0
}
},
methods: {
handle: function () {
msgCenter.$emit("tag2-event", 10)
}
},
mounted: function () {
msgCenter.$on("tag1-event", (val) => {
this.num = this.num + val;
})
}
})
var vue = new Vue({
el: "#vueBox",
methods: {
destoryMsg: function () {
msgCenter.$off("tag1-event");
msgCenter.$off("tag2-event");
}
}
})
</script>
4 组件的插槽 - slot
4.1 无名插槽
父组件向子组件传递内容
如果没有标签则自定义组件插入的内容不会显示出来
<head>
<meta charset="UTF-8">
<title>Vue测试</title>
<script src="./node_modules/vue/dist/vue.js"></script>
<style>
</style>
</head>
<body>
<div id="vueBox">
<my-component><a>你很丑</a></my-component>
<my-component><a>太矮了</a></my-component>
<my-component></my-component>
</div>
</body>
<script type="text/javascript">
Vue.component("my-component",{
template: `
<div>
<span style="color:red">错误提示:</span>
<slot><a>默认内容</a></slot>
</div>`,
})
var vue = new Vue({
el: "#vueBox"
})
</script>
4.2 有名插槽 - 意味一个组件可写多个插槽
4.2.1 不使用标签
模版上使用name进行插槽命名,使用slot进行标记插在哪一个槽上
<body>
<div id="vueBox">
<my-component>
<span>填入无名插槽</span>
<span slot="name1">填入name1插槽</span>
<span slot="name2">填入name2无名插槽</span>
</my-component>
</div>
</body>
<script type="text/javascript">
Vue.component("my-component",{
template: `
<div>
<span style="color:red">错误提示:</span><slot><a>默认内容无名插槽</a></slot>
<br/>
<span style="color:red">错误提示:</span><slot name="name1"></slot>
<br/>
<span style="color:red">错误提示:</span><slot name="name2"></slot>
<br/>
</div>`,
})
var vue = new Vue({
el: "#vueBox"
})
</script>
4.2.2 使用标签
<body>
<div id="vueBox">
<my-component>
<template>
<span>填入无名插槽</span>
</template>
<template slot="name1">
<span >填入name1插槽</span>
</template>
<template slot="name2">
<span >填入name2无名插槽</span>
</template>
</my-component>
</div>
</body>
<script type="text/javascript">
Vue.component("my-component",{
template: `
<div>
<span style="color:red">错误提示:</span><slot><a>默认内容无名插槽</a></slot>
<br/>
<span style="color:red">错误提示:</span><slot name="name1"></slot>
<br/>
<span style="color:red">错误提示:</span><slot name="name2"></slot>
<br/>
</div>`,
})
var vue = new Vue({
el: "#vueBox"
})
</script>
4.3 作用域插槽
父组件对子组件内容进行加工处理
下列示例的数据流动图片
<body>
<div id="vueBox" >
<my-component v-bind:students="students">
<template slot-scope="args">
<span v-if="args.msg.id == 2" style="color:red">{{args.msg.name}}</span>
<span v-else>{{args.msg.name}}</span>
</template>
</my-component>
</div>
</body>
<script type="text/javascript">
Vue.component("my-component",{
template: `
<ul>
<li v-for="student in students"><slot :msg="student"></slot></li>
</ul>
`,
props:["students"]
})
var vue = new Vue({
el: "#vueBox",
data: {
students: [{
id: 1,
name: 'lrc'
},{
id: 2,
name: 'lcj'
},{
id: 3,
name: 'yxx'
}]
}
})
</script>