Vue系列笔记2

学习参考:coderwhy教学视频,整个系列可能会比较混乱,学到哪里觉得有需要的记录一下,可能和之前的java笔记类似。

  1. 如果将一个页面中所有的处理逻辑全部放到一起,处理起来就会变得非常复杂,而且不利于后续管理和扩展;但如果将一个页面拆分成一个个小的功能块,每个功能块完成属于自己这部分独立的功能,之后整个页面的管理和维护就变得容易许多;

  1. 组件化提供了一种抽象,可以开发出一个个独立可复用的小组件来构造应用,任何的应用都会被抽象成一颗组件树;

  1. 组件的使用可以分成三个步骤:创建组件构造器,注册组件,使用组件;

1570496438265

  1. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
       <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Document</title>
    </head>
    <body>
    <div id="app">
    <!-- 3.使用组件 -->
    <my-cpn></my-cpn>
    <my-cpn></my-cpn>
    <my-cpn></my-cpn>
    </div>
    <script src="../js/vue.js"></script>
    <script>
    //1.创建组件构造器对象
    const cpnContructor = Vue.extend({
    template: `
    <div>
    <h2>我是标题</h2>
    <p>我是内容,哈哈哈哈</p>
    <p>我是内容,呵呵呵呵</p>
    </div>`
    })
    //2.注册组件
    Vue.component('my-cpn', cpnContructor)

    const app = new Vue({
    el: '#app',
    data: {
    message: 'Hello!',
    },

    })
    </script>
    </body>
    </html>

    Vue.extend()创建的是一个组件构造器,通常在创建组件构造器时,传入template代表我们自定义组件的模板。该模板就是在使用到组件的地方,要显示的HTML代码,事实上,这种写法在Vue 2.x的文档中就几乎看不到了,它会直接使用下面的语法糖,但这种方式是基础。

    Vue.component()是将刚才的组件构造器注册为一个组件,并且给它起一个组件的标签名称。

    组件使用时必须挂载在某个Vue实例下,否则它不会生效。

  2. 全局组件和局部组件:上述方法构建的为全局组件。局部组件需要挂载到Vue实例下,只有该实例对应的app才可以使用。

    1
    2
    3
    4
    5
    6
    7
    const app = new Vue({
    el: '#app',
    //2.局部组件注册
    components: {
    cpn: cpnC
    }
    })
  3. 父组件和子组件:要求子组件在父组件中进行注册:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//1.创建第一个组件构造器(子组件)
const cpnC1 = Vue.extend({
template:`
<div>
<h2>我是标题1</h2>
<p>我是内容,哈哈哈哈</p>
</div>`
})

//2.创建第二个组件构造器(父组件)
const cpnC2 = Vue.extend({
template:`
<div>
<h2>我是标题2</h2>
<p>我是内容,呵呵呵呵</p>
<cpn1></cpn1>
</div>`
,
components: {
cpn1: cpnC1
}
})
  1. 组件注册的语法糖,将上述创建组件构造器和注册组件合并:
1
2
3
4
5
6
7
Vue.component('cpn1', {
template: `
<div>
<h2>我是标题1</h2>
<p>我是内容,哈哈哈哈</p>
</div>`
})
  1. 组件模板的抽离写法,可以看出来,上边的js代码中嵌套HTML,看起来比较乱,所以需要抽离,有两种写法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<body>
<div id="app">
<cpn1></cpn1>
<cpn2></cpn2>
</div>
<!-- 1.通过script标签,但是注意类型必须是text/x-template -->
<script type="text/x-template" id="cpn1">
<div>
<h2>我是标题1</h2>
<p>我是内容,哈哈哈哈</p>
</div>
</script>

<!-- 2.template标签 -->
<template id="cpn2">
<div>
<h2>我是标题2</h2>
<p>我是内容,呵呵呵呵</p>
</div>
</template>

<script src="../js/vue.js"></script>
<script>
Vue.component('cpn1', {
template: '#cpn1',
})
Vue.component('cpn2', {
template: '#cpn2',
})
const app = new Vue({
el: '#app',
})
</script>
</body>
  1. 组件中的数据不应该也不能放在全局的data中,应该放在自己的data中,但是需要注意组件的data属性必须是一个函数,且要求返回一个实例对象,对象内部保存着数据。

  2. 在开发中,往往一些数据确实需要从上层传到下层,例如在一个页面中,从服务器请求了许多数据,其中一部分数据并非整个页面的大组件来展示,而是需要下面的小组件来展示,这时,并不会让小组件再发一次网络请求,而是让大组件将数据传给小组件,这是就涉及到父子组件之间的通信,有两种方式:通过props向子组件传递数据和通过事件向父组件发送消息。

  1. 在组件中,使用选项props来声明需要从父级接受的数据。

props的值有两种方式:

1)字符串数组,数组中的字符串就是传递时的名称;

2)对象,对象可以设置传递时的类型,也可以设置默认值等;

  1. 子组件向父组件发送数据:子组件内部先通过&emit()定义发射事件,父组件中监听(类似于系统自带的click等监听),监听到后执行相应的响应函数即可。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//子组件
methods: {
btnClick(item) {
//发射事件(自定义事件)
this.$emit('item-click', item)
}
}
//监听
<div id="app">
<!-- 监听事件 -->
<cpn @item-click="cpnClick"></cpn>
</div>
//父组件
methods: {
cpnClick(item) {
console.log(item);
}
}
  1. 父子组件的访问:父组件访问子组件使用$children或者$refs;子组件访问父组件使用$parent;子组件访问根组件使用$root

  2. 在实际开发中,refs用的比较多一些,因为使用children需要使用下标,但是组件顺序可能会有更改,不利于维护

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<div id="app">
<button @click="btnClick">按钮</button>
<cpn></cpn>
<cpn></cpn>
<cpn ref="aaa"></cpn>
</div>
………………
methods: {
btnClick() {
// 1.$children
// console.log(this.$children);
// this.$children[0].showMessage();
// console.log(this.$children[1].name);

//2.$refs
this.$refs.aaa.showMessage();
console.log(this.$refs.aaa.name);
}
………………
components: {
cpn: {
template: '#cpn',
data() {
return {
name: '我是子组件的name'
}
},
methods: {
showMessage() {
console.log('aaaaaaaa');

}
}
}
}
  1. $parent在实际开发中应用不多,因为组件强调的是复用性,在组件中使用$parent可能会导致其和父组件的耦合度太高。

  2. 组件的插槽slot是为了让组件有更强的扩展性,往往需要的一些组件之间有很多区别,但也有很多共性,每个都封装成一个单独的不太合理,将所有的都封装成一个也不合理,这里就需要用到slot,slot就是占位,具体占好位置放什么可以由调用者决定;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div id="app">
<cpn><button>按钮</button></cpn>
<cpn><span>哈哈哈</span></cpn>
<cpn>
<p>哦哦哦</p>
<i>呵呵呵</i>
</cpn>
</div>

<template id="cpn">
<div>
<h2>我是组件</h2>
<p>我是组件,嘿嘿嘿</p>
<slot></slot>
</div>
</template>
  1. 作用域插槽:举例:子组件中包含一组数据,pLanguages: [‘JavaScript’,’Python’,’Java’,’C++’],要求进行不同的展示效果,例如以列表形式展示,以水平方向展示等等
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<div id="app">
<!-- 默认以列表进行展示 -->
<cpn></cpn>
<!-- 以水平方式进行展示 -->
<cpn>
<!-- 目的是获取子组件的pLanguages -->
<template slot-scope="slot">
<!-- <span v-for="item in slot.data">{{item}} ** </span> -->
<span>{{slot.data.join(' * ')}}</span>
</template>
</cpn>

</div>

<template id="cpn">
<div>
<slot :data="pLanguages">
<ul>
<li v-for="item in pLanguages">{{item}}</li>
</ul>
</slot>
</div>
</template>

:转载文章请注明出处,谢谢~