VUE深度解析
ES6语法-var-const-let用法详解
javascript作用域
javascript只有函数作用域,没有块级作用域。即在
dunction
里面定义的变量是有作用域的,if、for等代码块定义的变量是没有作用域的。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>ES6语法-var-const-let用法详解</title>
</head>
<body>
<div id="app">
<button>测试1</button>
<button>测试2</button>
<button>测试3</button>
</div>
<script>
//作用域代码
if(true){
//externalVal没有作用域
var externalVal = "externalVal";
}
function domainTest(){
var funVal ="funVal";
//这里可以访问到externalVal和funVal
console.log(externalVal + "----" + funVal);
}
domainTest()
if(true){
console.log(externalVal); //可以访问到externalVal
//console.log(funVal); 这一行访问不到变量,报错
}
//使用var定义变量的局限性
var btns = document.getElementsByTagName('button')
for(let i = 0;i < btns.length;i++){
btns[i].onclick = function(){
alert("点击了第" + (i+1) + "个按钮");
}
}
</script>
</body>
</html>
var局限性
在上面代码中添加三个button,然后定义监听
然后测试结果如下:
为什么会一直出现的是3呢?这是因为作用域,for代码块没有作用域,当循环for结束的时候,监听的i是几?肯定是3,那么当我们点击按钮的时候i就是3。所以打印出来的就是”点击了第三个按钮”
let用法
var作用域在js中存在的缺陷,在ES6版主中,使用新的定义变量let就可以解决。
//使用var定义变量的局限性
var btns = document.getElementsByTagName('button')
for(let i = 0;i < btns.length;i++){
btns[i].onclick = function(){
alert("点击了第" + (i+1) + "个按钮");
}
}
结果如下:
点击第1个按钮,打印“点击了第3个按钮”的情况就不会再出现。因为let定义的变量自带块级作用域。
const用法
当我们希望定义的变量不要被二次赋值的时候(也就是常量),使用const关键字来定义。
const c = 80;
c = 100;//报错
const c; //报错,常量定义的时候必须赋值
ES6语法-对象的增强写法
ES5对象定义语法
function Player(name,age){//定义对象
this.name = name;
this.age = age;
}
//定义对象的成员函数
Player.prototype.toPrint = function(){
alert(this.name + "---" + this.age)
}
var player1 = new Player("james",35);
var player2 = new Player("kobe",39);
player1.toPrint() //james---35 调用函数方法
player2.toPrint() //kobe---39
结果如下:
ES5中对象最令人觉得繁琐的就是构造函数、prototyp、依靠原型链实现继承。因为它使用的不是面向对象的语法,所以使用过程比较混乱。下面我们结束如何使用简介的ES6语法定义对象和继承的增强语法。
ES6定义对象语法
ES6语法中,js引入了传统的面向对象编程语法(和java相似)。新的写法比较符合面向对象思想,也比较容易理解。
//class定义对象
class Player{
//constructor 定义构造函数
constructor(name,age){
console.log(name + 'fdasfada' + age)
this.name = name;
this.age = age;
}
//定义方法
toPrint(){
console.log(this.name + "---" + this.age)
}
}
//使用对象
let player1 = new Player("james",35);
//使用对象方法
player1.toPrint() //james---35
- 引入class关键字,用于定义对象
- 构造函数方法名称固定,就叫做constructor。
- 在对象定义类中,this关键字代表当前实例对象
class BestPlayer extends Player{
constructor(){
super()
this.name = "jordan"
this.age = 49
}
}
let bestPlayer = new BestPlayer();
bestPlayer.toPrint() //jordan---49
- 通过class关键字实现了类的继承
- 通过super()关键字调用父类构造函数,如果不传参数,默认是undefined
- super()方法必须显示调用,否则子类找不到this指针。
ES6定义对象简写
let name = "curry"
let age = 33
let player3 = {
name :name,
age : age,
toPrint:function(){
console.log(player3) //{name: "curry", age: 33}
}
}
player3.toPrint() //{name: "curry", age: 33, toPrint: ƒ}
ES6语法-箭头函数与this指针
箭头函数简写形式
可以发现,箭头函数方法写的很简单,箭头左侧定义参数,右侧定义函数体。
对象中this指针
//class 定义对象
class Player{
//constructor 定义构造函数
constructor(nickname,age){
this.nickname = nickname;
this.age = age;
}
//定义成员方法
toPrint(){
console.log(this.nickname + "---" + this.age)
}
}
在对象中,this指针指向的就是对象本身。可以this可以引用对象的属性和方法。
VUE组件化
graph LR
调用Vue.extend定义组件 --> 调用Vue.component组测组件 --> 在vue实例试图范围内使用组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>嵌套组件</title>
</head>
<body>
<div>
<div id="app" style="background-color: aqua;">
<first-component></first-component>
</div>
<div id="app2" style="background-color: aquamarine;">
<second-component></second-component>
</div>
<div id="app3" style="background-color: blue;">
<third-component></third-component>
</div>
<!--父子组件的嵌套-->
<template id="child">
<p style="font-size: larger;">子组件</p>
</template>
<template id="parent">
<div>
<h2>父组件 template</h2>
<child></child>
<child></child>
</div>
</template>
<div id="app4" style="background-color: brown;">
<parent></parent>
</div>
</div>
<!--从CDN引入vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<script>
const firstComponent= Vue.extend({
template:`
<div>
<span>template用于定义组件试图</span>
<h3>测试组件</h3>
<h2>测试组件内容</h2>
</div>
`
});
//组测组件
Vue.component("firstComponent",firstComponent);
var app = new Vue({
el: '#app'
});
</script>
<script>
var app2 = new Vue({
el: '#app4',
components:{
parent:{
template: '#parent',
components: {
'child': {template: '#child'},
}
}
}
});
</script>
<script>
//组测组件
Vue.component("secondComponent",{
template:`
<div>
<span>template用于定义组件二合一试图</span>
<h3>测试组件二合一</h3>
<h2>测试组件二合一内容</h2>
</div>
`
});
var app = new Vue({
el: '#app2',
data: function(){
return {count: 0}
},
methods: {
incr(){
this.count ++
}
},
});
</script>
<script>
var app = new Vue({
el: '#app3',
components:{
thirdComponent:{
template:`
<div>
<span>template用于定义私有组件试图</span>
<h3>测试私有组件</h3>
<h2>测试私有组件内容2</h2>
</div>
`
}
}
});
</script>
</body>
</html>
- 全局组件要先定义vue.extend(),在注册vue.component(),任何再使用。
-
template
用于定义组件视图 - 如果用new VUE()定义多个vue实例,全局组件可以跨多个实例使用
- 通常组件定义的名称为首字母大写,驼峰标志。如:firstComponent
- 在dom中使用组件,通常遵循使用“-”分隔单词,小写规范。如:first-component
最终结果如下:
全局组件简写
使用Vue.component()方法 + template组件视图层模板一步完成全局组件的定义与注册
//组测组件
Vue.component("secondComponent",{
template:`
<div>
<span>template用于定义组件二合一试图</span>
<h3>测试组件二合一</h3>
<h2>测试组件二合一内容</h2>
</div>
`
});
局部私有组件
局部私有组件和全局组件的区别在于,私有组件只能在定义它的实例或者父组件里面使用。如下:定义的组件thirdComponent只能在
<div id="app3">
里面使用,其他vue实例无法使用该组件。
<script>
var app = new Vue({
el: '#app3',
components:{
thirdComponent:{
template:`
<div>
<span>template用于定义私有组件试图</span>
<h3>测试私有组件</h3>
<h2>测试私有组件内容2</h2>
</div>
`
}
}
});
</script>
父子组件嵌套
<!--父子组件的嵌套-->
<template id="child">
<p style="font-size: larger;">子组件</p>
</template>
<template id="parent">
<div>
<h2>父组件 template</h2>
<child></child>
<child></child>
</div>
</template>
<div id="app4" style="background-color: brown;">
<parent></parent>
</div>
一个父组件Parent里面包含两个子组件Child,并将父组件放在app2实例页面渲染范围内。下文中是使用私有局部组件的方式定义的。也就是Parent组件是app2实例的私有局部组件,Child是Parent组件的私有局部组件。
<script>
var app4 = new Vue({
el: '#app4',
components:{
parent:{
template: '#parent',
components: {
'child': {template: '#child'},
}
}
}
});
</script>
结果如下:
父子组件间数据定义和访问
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>父子组件间数据定义和访问</title>
</head>
<body>
<div>
<template id="secondComponent">
<div>
<span>{{count}}</span><br>
<button @click="incr">+</button>
</div>
</template>
<div id="app2" style="background-color:burlywood;">
<h2>secondComponent</h2><br>
<second-component></second-component>
</div>
</div>
<!--从CDN引入vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app2',
components:{
secondComponent:{
template:'#secondComponent',
data:function(){
return {count:0}
},
methods:{
incr(){
this.count++;
}
}
}
}
});
</script>
</body>
</html>
-
secondComponent
组件有自己的视图模板template#secondComponent -
secondComponent
组件有自己的数据定义,data()函数。这里定义的是一个函数,而不是对象,通过函数返回对象数据。 -
secondComponent
组件有自己的操作方法,定义在methods代码块中
父子组件的数据访问
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>父子组件的数据定义与访问</title>
</head>
<body>
<div>
<!--父子组件的嵌套-->
<!-- <template id="Child">
<div>
<p>{{childMessage}}</p>
<input type="text" v-model="childMessage"><br>
<button @click="parentInfo()">打印父组件信息</button>
</div>
</template> -->
<template id="Child">
<div style="background-color: brown;">
<p>{{childMsg}}</p>
<input type="text" v-model="childMsg"><br>
<button @click="parentInfo()">调用父组件信息</button>
<h2>{{txt}}</h2>
</div>
</template>
<template id="Parent">
<div>
<p>{{parentMsg}}</p>
<input type="text" v-model="parentMsg"><br>
<button @click="childInfo()">打印子组件信息</button>
<child ref="childRef"></child>
<h2>{{msgL}}</h2>
<!-- <child></child> -->
</div>
</template>
<div id="app">
<parent></parent>
</div>
</div>
<!--从CDN引入vue.js-->
<script src="vue.min.js"></script>
<script>
var app2 = new Vue({
el: '#app',
components:{
Parent:{
template: '#Parent',
data: function(){
return {
parentMsg: "父组件的数据",
msgL:""
}
},
methods: {
childInfo(){
// console.log(this.$children[0].childMsg)
this.msgL="msgL: "+this.$children[0].childMsg
// console.log(this.$refs.childRef.childMsg)
}
},
components: {
Child: {
template: '#Child',
data: function(){
return {
childMsg: "我是子组件的数据",
txt:""
}
},
methods: {
parentInfo(){
this.txt="txt: "+this.$parent.parentMsg
//console.log(this.$parent.parentMsg)
}
}
}
}
}
}
});
</script>
</body>
</html>
父组件是没有办法直接访问子组件的数据的,子组件也没有办法直接使用父组件的数据,那么就出现了
、children、$ref
我们希望在子组件中使用this.打印父组件信息,在父组件中调用children[0]打印子组件信息
上面的方法中,父组件使用this.$children[0]来获取多个子组件的数据。如果我们希望快速的,从父组件获取子组件的数据,还可以为子组件加上一个属性ref。相当于为子组件起了一个别名,便于查找。
然后父组件通过如下代码即可打印子组件的属性数据:
console.log(this.$refs.childRef.childMsg)
使用props父组件向子组件传递数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>使用props父组件向子组件传递数据</title>
</head>
<body>
<div id="app">
<child :child-msg="msg" :child-ary="ary"></child>
<example :prop-a="propA" :prop-c="propC" ></example>
</div>
<template id="child">
<div>
<h2>{{childMsg}}</h2>
<h2>{{childAry}}</h2>
</div>
</template>
<template id="example">
<div>
<span>"propA"</span> <h2>{{propA}}</h2><br>
<span>"propC"</span> <h2>{{propC}}</h2><br>
<span>"propD"</span> <h2>{{propD}}</h2><br>
<span>"propE"</span> <h2>{{propE}}</h2><br>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<script>
const child = {
template: '#child',
props: ['childMsg','childAry']
}
const example = {
template: '#example',
props: {
propA:{type: Number},
propC: {
type: String,
required: true
},
propD: {
type: Number,
default: 100
},
propE: {
type: Object,
default: function () {
return { message: 'hello' }
}
}
}
}
const app = new Vue({
el: '#app',
data: {
ary: {
name: '张三',age: 39,sex:"男"
},
msg: '父组件数据->子组件',
propA:10,
propC:"propC",
propD:40,
propF:5
},
components: {
child,
example
}
})
</script>
</body>
</html>
- 父实例将自己数据msg,传递给child
- 子组件通过绑定属性child-msg绑定父组件数据msg
- 子组件标签属性child-msg对应子组件模型定义属性props:childMsg
- childMsg属性可以使用插值表达式,显示template模板里面
props数据
通常我们定义一个组件是应该可以提供给其他模块或其他人使用的。使用者可能对该组件的用法并不熟悉,可能会导致错误。所以有必要在子组件内,对父组件传递过来数据进行校验。
子组件向父组件传播事件
父组件可以通过和ref的方式获取子组件的数据。但是在实际开发过程中,还有另外一种需求,即:子组件中发生了某些动作,从而改变了子组件的数据。那么父组件如何实时的监听到子组件数据的变化呢?那就是我们这一小节需要讲的核心内容
- 在子组件使用$emit(‘事件名称’,参数),触发并发送事件,并且可以通过参数传值
methods:{
incr(){
this.count++
this.$emit('increment',this.count)
},
decr(){
this.count--
this.$emit('decrement',this.count)
}
}
- 在父组件中嵌入子组件,并使用v-on指令(简写为@)监听事件,从而触发回调函数,回调函数接受子组件发送的参数。图中changePcounter就是针对increment事件和decrment事件监听的回调函数
<div id="app">
<child-cpn @increment="changePCounter" @decrement="changePCounter"></child-cpn>
<h2>PCounter: {{pCounter}}</h2>
</div>
- 父组件定义回调函数接收实践触发源传递的参数,即$emit的第二个参数
changePCounter(counter){
this.pCounter = counter
}
整体需求的实现
子组件与视图的定义。子组件点击加一按钮触发incr函数,incr函数触发increment事件,并将当前cCounter作为事件参数传递出去。父组件范围监听到increment事件,从而触发changePCounter方法,该方法接受cCounter作为参数。
父组件的定义
如果您觉得本文不错,欢迎关注,点赞,收藏支持,您的关注是我坚持的动力!
原创不易,转载请注明出处,感谢支持!如果本文对您有用,欢迎转发分享!
文章版权声明
1 原创文章作者:TT7,如若转载,请注明出处: https://www.52hwl.com/36149.html
2 温馨提示:软件侵权请联系469472785#qq.com(三天内删除相关链接)资源失效请留言反馈
3 下载提示:如遇蓝奏云无法访问,请修改lanzous(把s修改成x)
4 免责声明:本站为个人博客,所有软件信息均来自网络 修改版软件,加群广告提示为修改者自留,非本站信息,注意鉴别