第一种方法:
第二种方法:
第三种方法:reduce
编程范式的分类有:命令式编程,声明式编程。
编程范式的分类有:面向对象编程(js当中多态体现太灵活,TypeScript跟java很像,也有接口),函数式编程。
面向对象编程的第一公民是对象。
函数式编程的第一公民是函数。
函数式编程的好处是可以进行很多的链式编程。
举个例子,下面的需求用传统的方法,就没有函数式编程简单。
像是上面的做法,传统的做法,是挺麻烦的。
有三个高阶函数:filter、map、reduce。
什么是高阶函数呢?就是函数的参数,也是一个函数,这种套路。
看一下reduce的源码:
我们看到源码当中定义了两个函数,源码是typescript的,d表示的是定义的意思,definition。
在js当中如果定义了两个函数,下面的函数,会把上面的函数覆盖掉。
但是它这里不会被覆盖。因为它是typescript。
定义两个函数,叫做函数的重载。
我们看上面的源码可以知道,reduce函数可以传入两个参数,一个是回调函数,一个是初始化值。
代码如下:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<script src="../js/vue.js">script>
<script>
const nums = [10, 20, 111, 222, 444, 40, 50];
/*
* filter函数是会自动遍历数组的
* filter函数的参数,要求传入一个回调函数。
* filter的回调函数必须返回一个布尔值。
* 如果返回的是true,函数内部会自动将这次回调的n,加入到新的数组中。
* 如果返回的是false,函数内部就会自动过滤掉n。
* 场景:如果你需要对一个数组进行过滤,就使用filter
* */
let newNums = nums.filter(function (n) {
return n < 100;
});
console.log(newNums); // [10. 20. 40, 50]
/*
* map函数是会自动遍历数组的。
* map函数的参数,要求传入一个回调函数
* 每个遍历的元素都会被回调函数处理成新的值,
* 然后新的值会组成新的数组。
* 场景:如果你需要对一个数组当中的每个元素做统一的操作,就使用map
* */
let new2Nums = newNums.map(function (n) {
return n * 2;
});
console.log(new2Nums); // [20, 40, 80, 100]
/*
* reduce函数是会自动遍历数组的。
* 源码中关于reduce有两个定义。
* 1、reduce函数的参数,要求传入1个参数,是回调函数
* 2、reduce函数的参数,要求传入2个参数,一个是回调函数,一个是初始化值。
* 这个回调函数有两个值,第一个参数上一次返回的值previousValue,第二个参数是当下的值currentValue。
* reduce函数的返回是一个值。
* 场景:如果你需要对数组中所有元素进行汇总,所有相乘,所有相加等场景。
* */
let new3Nums = new2Nums.reduce(function (preValue, n) {
return preValue + n
}, 0);
console.log(new3Nums); // 240
// 假设new2Nums = [20, 40, 80]
// 第一次:preValue - 0 , n - 20 return x
// 第二次:preValue - x ,n - 40 return y
// 第三次:preValue - y , n - 80 return z
script>
body>
html>
上面的代码,阅读性还是比较差的。
我们还可以这样写:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<script src="../js/vue.js">script>
<script>
const nums = [10, 20, 111, 222, 444, 40, 50];
let total = nums.filter(function (n) {
return n < 100;
}).map(function (n) {
return n * 2;
}).reduce(function (preValue, n) {
return preValue + n;
}, 0);
script>
body>
html>
这就叫做函数式编程。函数就是函数编程的第一公民。
用箭头函数的话,还能够简化上面的链式编程代码:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<script src="../js/vue.js">script>
<script>
const nums = [10, 20, 111, 222, 444, 40, 50];
let total = nums.filter(n => n < 100).map(n => n * 2).reduce((pre, n) => pre + n);
script>
body>
html>
问题:三个高阶函数,filter,map,reduce都是用在什么场景。
答案:在数组或对象遍历的场景,filter是对每个元素需要过滤的场景,map是对每个元素统一进行一个操作的场景,reduce是对每个元素进行汇总的场景。
数据已经被绑定到了input里面了。
之前我们是通过 mustache语法将data当中的数据,绑定到了某个元素的内容的位置。
现在我们是在表单元素的标签属性里面添加了v-model之后,就把data当中的数据绑定到了表单当中。
而且v-model是一种双向绑定。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
<input type="text" v-model="message">
{{message}}
div>
<script src="../js/vue.js">script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '张润'
},
})
script>
body>
html>
先自己手动来实现双向绑定。
第一步,先将data里面的message,绑定到input当中,这个要用到动态绑定属性。
第二步,我们需要把input当中用户输入的值,绑定到我们的message上。
input输入框是有一个默认的事件的,这个事件就叫做input。
就好像button按钮有一个事件叫做点击,叫做click是一样的。
我们可以在input输入框上面监听它的input事件,然后拿到用户输入的值。
监听它的input事件,我们可以通过v-on来实现,那么怎么拿到用户输入的值呢?
当页面上产生了事件的时候,浏览器会为我们生成一个事件对象event。
这个event当中的target中的value,这里就是保存着用户在input输入框中的输入。
具体的代码就如下所示:
具体的代码如下:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
<input type="text" :value="message" @input="valueChange">
<h2>{{message}}h2>
div>
<script src="../js/vue.js">script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '江疏影'
},
methods: {
valueChange(event) {
this.message = event.target.value;
}
}
});
script>
body>
html>
第一点:我们之前学过label和input的绑定。label标签的for属性和input标签的id属性设置为一个值,这样就可以将label和input进行绑定。
这样拿到的效果,就是点击label的文字,input自动获得聚焦。input的value属性就是显示的文本,input的placeholder就是没有输入的时候默认显示的文本。
第二点:input输入框是有一个对应的事件就是input,用户输入的值,就是浏览器event对象target的value属性值中保存。
下面的截图就是浏览器的input事件对象:
根据我的测试,现在浏览器当中,用户的输入产生的事件对象是InputEvent,数据是存放在event.data属性当中。
第三点:我们的v-bind到现在为止,遇到了这么几种情况。
第四点:我们的事件监听,现在也遇到了这么几种情况:
这给我提了个醒,需要好好研究一下浏览器事件对象
。
我们刚才通过了v-on事件监听input事件,通过v-bind绑定input的value属性。
通过这两个指令,实现了v-model的效果。
我们对上面的代码修改一下:
我们事件绑定的时候,不要用方法,我们直接用表达式:
问题:v-model的本质可以相当于哪两个指令的结合?
答案:v-bind和v-on
radio比较常见的就是让用户选择一下性别男女这种场景。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
<label for="male">
<input type="radio" id="male" name="sex" value="男" v-model="sex">男
label>
<label for="female">
<input type="radio" id="female" name="sex" value="女" v-model="sex">女
label>
<h2>您选择的性别是:{{sex}}h2>
div>
<script src="../js/vue.js">script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '',
sex: ''
},
})
script>
body>
html>
男
,这样男对应的radio,就是默认选中的。问题:input radio都有哪些常见的属性值?
答案:
checkbox是复选框,是比较特殊。
两种情况。
单个单选框和多选框。
单选框会在什么场景用到呢?
就是很多网站有:同意协议,这种地方用到。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
<label for="agree">
<input type="checkbox" id="agree" v-model="isAgree">同意协议
label>
<h2>您选择的是:{{userAgree}}h2>
<button :disabled="!isAgree">下一步button>
div>
<script src="../js/vue.js">script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '',
isAgree: false
},
computed: {
userAgree(){
if (this.isAgree){
return '同意协议'
}else{
return '不同意协议'
}
}
}
})
script>
body>
html>
效果图如下:
代码如下:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
<input type="checkbox" value="张润" v-model="hobbies">张润<br>
<input type="checkbox" value="王柯" v-model="hobbies">王珂<br>
<input type="checkbox" value="赵柯" v-model="hobbies">赵柯<br>
<input type="checkbox" value="梁缘" v-model="hobbies">梁缘<br>
<input type="checkbox" value="舒砚" v-model="hobbies">舒砚<br>
<input type="checkbox" value="于越" v-model="hobbies">于越<br>
<input type="checkbox" value="周放" v-model="hobbies">周放<br>
<h2>您喜欢的美女是:{{hobbies}}h2>
div>
<script src="../js/vue.js">script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '',
hobbies: []
},
})
script>
body>
html>
效果图如下:
问题:单选框,v-model对应的是data当中的什么类型的数据?多选框,v-model对应的是data当中的什么类型的数据?
答案:单选框是boolean值,多选框是数组。
select类型就是下拉框。
降到这里的时候,王红元开始闲聊。
说郭德纲相声当中,问了捧哏一个问题:你知道曹操的父亲是谁吗?
是曹香蕉。因为三国里面有一句话是我与你父相交甚好
。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
<select name="abc" id="" v-model="pretty">
<option value="张芷溪">张芷溪option>
<option value="唐艺昕">唐艺昕option>
<option value="孙嘉璐">孙嘉璐option>
<option value="谈莎莎">谈莎莎option>
<option value="张熙媛">张熙媛option>
<option value="郑罗茜">郑罗茜option>
<option value="王文娜">王文娜option>
select>
<h2>您选择的美女是:{{pretty}}h2>
div>
<script src="../js/vue.js">script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '',
pretty: '王文娜'
},
})
script>
body>
html>
按住ctrl键,选择多个
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
<select name="abc" v-model="pretty" multiple>
<option value="张芷溪">张芷溪option>
<option value="唐艺昕">唐艺昕option>
<option value="孙嘉璐">孙嘉璐option>
<option value="谈莎莎">谈莎莎option>
<option value="张熙媛">张熙媛option>
<option value="郑罗茜">郑罗茜option>
<option value="王文娜">王文娜option>
select>
<h2>您选择的美女是:{{pretty}}h2>
div>
<script src="../js/vue.js">script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '',
pretty: []
},
})
script>
body>
html>
问题:select怎么设置选择多个?
答案:在select标签当中添加multiple属性。
讲一个概念。
王红元看官方网站的时候,看到的值绑定
。
一开始,不知道值绑定什么意思?
后来发现,其实非常简单。
值绑定的意思就是从一个最开始的数据当中读取值,然后进行绑定,然后进行v-model的双向数据绑定。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
<label v-for="item in pretties" :for="item">
<input type="checkbox" :value="item" :id="item" v-model="pretty">{{item}}<br>
label>
<h2>您选择的美女是:{{pretty}}h2>
div>
<script src="../js/vue.js">script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '',
pretty: [],
pretties: ['张芷溪', '唐艺昕', '孙嘉璐', '谈莎莎', '张熙媛', '郑罗茜', '王文娜']
},
})
script>
body>
html>
问题:从以前到现在,王红元演示过哪些v-bind绑定属性的例子了
答案:img标签的src,a标签的href,button标签的disabled,input标签的value、id,label的for属性
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
<input type="text" v-model.lazy="message">
<h2>您的输入是:{{message}}h2>
<input type="number" v-model.number="age">
<h2>您的输入是:{{age}},数据类型是{{typeof age}}h2>
<input type="text" v-model.trim="person">
<h2>您的输入是:{{person}}h2>
div>
<script src="../js/vue.js">script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '孟子义',
age: 26,
person: '',
},
});
script>
body>
html>
到这里为止,基础语法的部分就讲解完成了:
问题:罗列三个v-model的修饰符
答案:lazy、number、trim。
二叉树
。任何的树结构都可以被抽象成为一个二叉树的。二叉树
当中,用得比较多的,就是二叉搜索树
。二叉搜索树
当中为了保障树的平衡的话,还有二三四树
、红黑树
。问题:组件化和模块化是一个东西吗?
答案:不是。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
<cpn>cpn>
div>
<script src="../js/vue.js">script>
<script>
// ES6语法
// 以前在es5当中定义字符串,可以使用单引号,也可以使用双引号。
// 这时候换行必须搞个+号
// const str = 'abc' +
// 'abc';
// const str2 = `abc
// cdefghjklmnopqrstuvwxyz`
// 在es6当中,可以使用反引号。``。 支持换行的。
//1、创建组件构造器对象
const cpnConstructor = Vue.extend({
template: `
我是孟子义
我是北京电影学院校花
我长得真漂亮
`
});
//2、注册组件
// Vue.component('组件的标签名',组件构造器)
Vue.component('cpn', cpnConstructor);
//3、使用组件
const app = new Vue({
el: '#app',
data: {
message: ''
},
});
script>
body>
html>
效果如下:
问题:注册组件的三个步骤是什么?
答案:第一步:创建组件构造器,Vue.extend(),传入一个参数就是对象,对象里面写template属性,属性值是html代码。
第二步:注册逐渐,使用Vue.components(),传入两个参数,第一个参数是自定义标签字符串,第二个组件构造器。
第三步:使用自定义组件标签在vue管理范围内,使用自定义组件。
讲一下全局组件和局部组件:talk is cheap,show me the code。
代码:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
<cpn>cpn>
<cpn>cpn>
<cpn>cpn>
div>
<div id="app2">
<cpn>cpn>
div>
<script src="../js/vue.js">script>
<script>
//1、创建组件构造器
const cpnC = Vue.extend({
template:`
我是孟子义
我是韫秋,哈哈哈哈哈哈
`
})
//2、注册组件(这种注册组件的方式,就是全局组件)
//全局组件意味着,可以在多个vue的实例当中使用。
Vue.component('cpn',cpnC)
const app = new Vue({
el: '#app',
data: {
message: ''
},
})
const app2 = new Vue({
el: '#app2'
})
script>
body>
html>
效果:
注册在vue的实例内部:
const app = new Vue({
el: '#app',
data: {
message: ''
},
components: {
//属性名cpn,就是使用组件时候的标签名
//属性值cpnC,
cpn: cpnC
}
})
问题:怎么注册局部组件
答案:在vue实例当中options对象中,使用components属性的对象值中,注册局部组件。开发当中,局部组件使用得最多。开发当中一般也就只有一个vue实例,很少有多个vue实例的。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
<cpn2>cpn2>
div>
<script src="../js/vue.js">script>
<script>
// 第一个组件构造器
const cpnC1 = Vue.extend({
template: `
我是儿子
哈哈哈哈哈
`
});
// 第二个组件构造器
const cpnC2 = Vue.extend({
template: `
我是父亲
哈哈哈哈哈
`,
components: {
cpn1: cpnC1
}
});
const app = new Vue({
el: '#app',
data: {
message: ''
},
components: {
cpn2: cpnC2
}
});
script>
body>
html>
【小知识点】上面的代码中,div#app中已经不可以使用cpn1了,因为cpn1没有在vue实例当中注册。
效果如下:
一个默认的说法是:Vue实例也可以看成是一个组件。Vue实例看成是最顶层的组件,就是root组件。
问题:一个组件1注册在组件2当中,组件2注册在vue实例当中,那么可以在vue实例当中使用组件1吗?
答案:不可以。因为组件1并没有在vue实例当中注册。vue实例使用组件2的时候,组件2已经编译好了。会解析组件2的模版,会发现里面有一个组件1,会优先去自己注册的components当中去找一下组件1的template,如果没有找到,就会去全局组件当中找,找到之后,就会编译。在vue实例当中使用组件2的时候,组件2的内容都已经编译完成了,vue实例根本就不知道有什么组件1的存在。
在本质上,vue会把组件的template都会渲染成render函数的。
全局组件注册和局部组件注册的语法糖的写法,请看下面的代码:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
<cpn1>cpn1>
<cpn2>cpn2>
div>
<script src="../js/vue.js">script>
<script>
// 全局组件注册的传统写法
// const cpnC1 = Vue.extend({
// template: `
//
// 我是标题
// 哈哈哈哈哈
//
// `
// })
// Vue.component('cpn1',cpnC1)
// 全局组件注册的语法糖写法
Vue.component('cpn1',{
template: `
我是标题1
哈哈哈哈哈
`
})
// 局部组件注册的语法糖写法
const app = new Vue({
el: '#app',
data: {
message: ''
},
components: {
'cpn2': {
template: `
我是标题2
呵呵呵呵呵
`
}
}
})
script>
body>
html>
问题:vue注册组件的语法糖,本质是什么?
答案:从写法上,省略了Vue.extend()这个步骤。直接把原来的Vue.extend()括号里面,需要传递的对象参数,
放在了Vue.component(自定义标签字符串,构造器)
构造器的位置。
之前注册组件的时候,感觉代码很乱,这是因为js代码当中包含了html代码。
之前jquery创建某个标签,再给标签里面塞进去各种属性,是一个情况和道理,看起来乱。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
<cpn>cpn>
div>
<script type="text/x-template" id="cpn">
<div>
<h2>我是标题</h2>
<p>我是内容,哈哈哈哈</p>
</div>
script>
<script src="../js/vue.js">script>
<script>
// 1 - 传统写法
// Vue.component('cpn',{
// template: `
//
// 我是标题
// 我是内容,哈哈哈哈
//
// `
// })
Vue.component('cpn',{
template: '#cpn'
})
const app = new Vue({
el: '#app',
data: {
message: ''
},
})
script>
body>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
<cpn>cpn>
div>
<template id="cpn">
<div>
<h2>我是标题h2>
<p>我是内容,哈哈哈哈p>
div>
template>
<script src="../js/vue.js">script>
<script>
// 1 - 传统写法
// Vue.component('cpn',{
// template: `
//
// 我是标题
// 我是内容,哈哈哈哈
//
// `
// })
Vue.component('cpn',{
template: '#cpn'
})
const app = new Vue({
el: '#app',
data: {
message: ''
},
})
script>
body>
html>
问题:组件注册时候,template分离写法有什么?
答案:在html部分,通过script标签或者template标签写template,内容放在标签内,然后给标签设置id属性,最后把id放在组件注册的template属性值中。
组件内部是不能够vue实例当中的数据的。
组件当中现在有了template属性,components属性,data属性,其实也有methods,也有生命周期函数,很像是一个vue实例,底层组件本身的原型,就是指向vue的。
先讲一个需求:把原来的计数器案例,封装成一个组件。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
<cpn>cpn>
<cpn>cpn>
<cpn>cpn>
div>
<template id="cpn">
<div>
<h2>当前计数为:{{counter}}h2>
<button @click="increment">+button>
<button @click="decrement">-button>
div>
template>
<script src="../js/vue.js">script>
<script>
Vue.component('cpn', {
template: '#cpn',
data() {
return {
counter: 0
};
},
methods: {
increment() {
return this.counter++
},
decrement(){
return this.counter--
}
}
});
const app = new Vue({
el: '#app',
data: {
message: ''
},
});
script>
body>
html>
效果如下:
我们在页面中调用了三次组件。这三个组件都是不同的data对象,这是因为data是一个函数,返回值是一个对象。
我们可以看下面的代码:
<script>
// 函数在执行的时候,都会在自己的栈空间,创建很多新的变量。
function abc() {
return {
name: '许晴',
age: 40
}
}
let obj1 = abc()
let obj2 = abc()
let obj3 = abc()
obj1.name = '王琳'
obj2.age = '39'
console.log(obj1);
console.log(obj2);
console.log(obj3);
</script>
从结果可以知道,这是三个不同的对象,虽然是一个函数调用了三次,但是是返回了三个对象。
如果我们把上面的代码修改成下面的样子:
<script>
const obj = {
name: '许晴',
age: 40
}
function abc() {
return obj
}
let obj1 = abc()
let obj2 = abc()
let obj3 = abc()
obj1.name = '王琳'
obj2.age = '39'
console.log(obj1);
console.log(obj2);
console.log(obj3);
</script>
执行的结果是:
上面的写法,函数调用了三次,返回的就是同一个对象。
我自己的总结:函数是具有隔离性的,对象是没有隔离性的。
问题:面试题,为什么组件的data属性必须是一个函数,不能是一个对象。
答案:因为组件是复用的,对象没有隔离性,会多个组件相互影响。
什么叫通信,就是传递数据。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
<cpn :childmovies="movies" :childmessage="message">cpn>
div>
<template id="cpn">
<div>
<h2>{{childmessage}}h2>
<ul>
<li v-for="item in childmovies">{{item}}li>
ul>
div>
template>
<script src="../js/vue.js">script>
<script>
const cpn = {
template: '#cpn',
data(){return {}},
methods: {},
props: ['childmovies','childmessage']
};
const app = new Vue({
el: '#app',
data: {
message: '王子文',
movies: ['海王', '海贼王', '海尔兄弟']
},
components: {
// 'cpn':cpn
cpn
}
});
script>
body>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
<cpn :childmovies="movies">cpn>
div>
<template id="cpn">
<div>
<h2>{{childmessage}}h2>
<ul>
<li v-for="item in childmovies">{{item}}li>
ul>
div>
template>
<script src="../js/vue.js">script>
<script>
const cpn = {
template: '#cpn',
data(){return {}},
methods: {},
props: {
//1. 类型的限制
// childmovies: Array,
// childmessage: String,
//2. 提供一些默认值
childmessage: {
type: String,
default: '乔欣',
required: false
},
//类型是对象或者数组的时候,默认值必须是一个函数
childmovies: {
type: Array,
// default: [],//这种写法在vue 2.5.3以下不会错,从2.5.17以上这样写会报错。
default(){
return []
},
required: false
}
}
};
const app = new Vue({
el: '#app',
data: {
// message: '王子文',
movies: ['海王', '海贼王', '海尔兄弟']
},
components: {
// 'cpn':cpn
cpn
}
});
script>
body>
html>
开发当中,很少用数组形式的写法,也就是很少用第一种,比较常见的是用对象形式的写法,也就是第二种。
问题:父子组件怎么通信
答案:父组件中调用子组件,通过给子组件动态绑定属性,传递父组件data当中的数据。子组件的属性,定义在props中,可以接收父组件绑定的数据。props有很多种写法,每个属性都可以设置type、default、required等。其中要注意属性type是数组或对象时候,default的写法。
父传子,通信的过程中,如果子组件的props对象中的元素,属性是驼峰标识。
在父组件调用子组件,进行动态属性绑定的时候,v-bind是不支持驼峰的。
这是关于props如果是驼峰属性,在父组件中动态绑定时候,怎么用的代码:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
<cpn :c-info="info" :child-my-message="message">cpn>
div>
<template id="cpn">
<div>
<ul>
<li v-for="(value,key) in cInfo">{{key}}-{{value}}li>
ul>
<h2>{{childMyMessage}}h2>
div>
template>
<script src="../js/vue.js">script>
<script>
// 注册局部子组件
const cpn = {
template: '#cpn',
methods: {},
data(){
return {}
},
props: {
cInfo: {
type: Object,
default(){
return {}
},
required: false
},
childMyMessage: {
type: String,
default: ''
}
}
}
const app = new Vue({
el: '#app',
data: {
message: '孟子义',
info: {
name: '乔欣',
age: 26,
height: 1.72
}
},
components: {
cpn
}
})
script>
body>
html>
第一,前面感觉比较乱的原因,是props的写法,介绍了两种,一种是数组写法,一种是对象写法。一般都是用对象写法。
第二,对象写法props对象中,属性是对象或数组的时候,需要写成一个函数,返回一个对象的形式。
第三,对象写法props中,属性对象可以有:type(可以自定义对象类型),default,required。属性可以是一个校验函数。
第四,子组件的template中必须包含一个根元素。
第五,子组件props中属性名是驼峰标识,可以在子组件的template中用,在v-bind进行动态绑定时候不支持,要转换。
第六,子组件的data属性必须是一个函数,不能是一个对象。
问题:子组件中props中的属性,使用驼峰标识,在template标签中可以使用吗?在父组件动态绑定属性时,可以使用吗?
答案:可以。不可以。
在这个瞬间,外面下着雨,我想你想得要死。
我现在心理强大了一些,我会去找你的。
分解-加工-记录-回顾。
代码如下:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
<cpn @itemclick="cpnClick">cpn>
div>
<template id="cpn">
<div>
<button v-for="item in categories" @click="btnClick(item)">
{{item.name}}
button>
div>
template>
<script src="../js/vue.js">script>
<script>
// 子组件
const cpn = {
template: '#cpn',
data(){
return {
categories: [
{id: 'aaa', name: '熟女'},
{id: 'bbb', name: '人妻'},
{id: 'ccc', name: '御姐'},
{id: 'ddd', name: '萝莉'}
]
}
},
methods: {
btnClick(item){
// 子组件发射自定义事件
this.$emit('itemclick',item)
}
}
}
// 父组件
const app = new Vue({
el: '#app',
data: {
message: ''
},
methods: {
cpnClick(item){
console.log('cpn组件内部发生了点击',item);
}
},
components: {
cpn
}
})
script>
body>
html>
效果如下:
问题:子组件发送自定义事件并且传递了参数,父组件监听自定义事件,监听时候不写参数可以吗?
答案:可以的。在button点击监听浏览器默认事件时候,不写参数,会默认传入浏览器默认事件。监听子组件自定义事件,不写参数,也会默认传入子组件自定义事件。
王红元的项目地址是HYMall。
项目效果,如下图所示: