三、组件化开发

  • 1.1 组件化的实现和使用步骤
    • 组件注册步骤解析
  • 1.2 全局组件和局部组件
  • 1.3 父组件和子组件
  • 1.4 注册组件语法糖
  • 1.5 组件模板抽离的写法
  • 1.6 组件数据存放
  • 1.7 父子组件通信
    • 父组件向子组件传递数据
    • 子组件向父组件传递数据
  • 1.8 组件访问
    • 父组件访问子组件
      • children
      • refs
    • 子组件访问父组件
  • 1.9 插槽
    • slot
    • 具名插槽
    • 作用域插槽

人面对复杂问题的处理方式:

  • 任何一个人处理信息的逻辑能力都是有限的
  • 所以,当面对一个非常复杂的问题时,我们不太可能—次性搞定一大堆的内容。
  • 但是,我们人有一种天生的能力,就是将问题进行拆解。如果将一个复杂的问题,拆分成很多个可以处理的小问题,再将其放在整体当中,你会发现大的问题也会迎刃而解。

组件化也是类似的思想:

  • 如果我们将一个页面中所有的处理逻辑全部放在一起,处理起来就会变得非常复杂,而且不利于后续的管理以及扩展。
  • 但如果,我们讲一个页面拆分成一个个小的功能块,每个功能块完成属于自己这部分独立的功能,那么之后整个页面的管理和维护就变得非常容易了。

组件化是Vue.js中的重要思想:

  • 它提供了一种抽象,让我们可以开发出一个个独立可复用的小组件来构造我们的应用。
  • 任何的应用都会被抽象成一颗组件树。


       组件化思想的应用:

  • 有了组件化的思想,我们在之后的开发中就要充分的利用它。
  • 尽可能的将页面拆分成一个个小的、可复用的组件。
  • 这样让我们的代码更加方便组织和管理,并且扩展性也更强。

1.1 组件化的实现和使用步骤

组件的使用分成三个步骤:

  1. 创建组件构造器
  2. 注册组件
  3. 使用组件

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><div id="app"><!-- 3、使用组件 --><my-cpn></my-cpn><my-cpn></my-cpn></div><script src="../js/vue.js"></script><script>// 1、创建组件构造器const cpnC = Vue.extend({template: `<div><h2>我是标题</h2><p>我是内容,哈哈哈哈</p><p>我是内容,呵呵呵呵</p></div>`,});// 2、注册组件Vue.component('my-cpn', cpnC);const app = new Vue({el: '#app', data: {    }})</script>
</body>
</html>

组件注册步骤解析

  1. Vue.extend():

    • 调用Vue.extend()创建的是一个组件构造器。
    • 通常在创建组件构造器时,传入template代表我们自定义组件的模板。该模板就是在使用到组件的地方,要显示的HTML代码。
    • 事实上,这种写法在Vue2.x的文档中几乎已经看不到了,它会直接使用下面我们会讲到的语法糖,但是在很多资料还是会提到这种方式,而且这种方式是学习后面方式的基础。
  2. Vue.component():

    • 调用Vue.component()是将刚才的组件构造器注册为一个组件,并且给它起一个组件的标签名称。
    • 所以需要传递两个参数:1、注册组件的标签名,2、组件构造器
  3. 组件必须挂在在某个Vue实例下,否则它不会生效

    • 下面的实例中,我们使用了三次<my-cpn></my-spn>
    • 但是第三次并没有生效

1.2 全局组件和局部组件

  • 全局组件:在注册之后可以用在任何新创建的 Vue 根实例 (new Vue) 的模板中。
  • 局部组件:局部组件只有在所注册的Vue实例中才能使用,并不能在其他未进行注册的Vue实例中使用。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><div id="app"><!-- 3、使用组件 --><my-cpn></my-cpn><cpn></cpn></div><hr><div id="app2"><my-cpn></my-cpn><cpn></cpn></div><script src="../js/vue.js"></script><script>// 1、创建组件构造器const cpnC = Vue.extend({template: `<div><h2>我是标题</h2><p>我是内容,哈哈哈哈</p><p>我是内容,呵呵呵呵</p></div>`,});// 2、注册组件(全局组件,意味着可以在多个 Vue 实例下面使用)Vue.component('my-cpn', cpnC);const app = new Vue({el: '#app', data: {    },// 局部组件components: {cpn: cpnC}})const app2 = new Vue({el: '#app2', data: {    }})</script>
</body>
</html>

在上面的代码中,我们创建了两个Vue实例对象appapp2,同时我们使用注册了全局组件my-cpn以及在app内注册了局部组件cpn。我们在appapp2中使用上面的两个组件,可以看到局部组件cpn并没有在app2中生效,符合我们的预期。

1.3 父组件和子组件

在前面我们看到了组件树:

  • 组件和组件之间存在层级关系
  • 而其中一种非常重要的关系就是父子组件的关系

我们来通过代码看这种层级关系:


<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><div id="app"><cpn2></cpn2></div><script src="../js/vue.js"></script><script>// 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,},});const app = new Vue({el: '#app', data: {    },components: {cpn2: cpnC2,}})</script>
</body>
</html>


1.4 注册组件语法糖

通过语法糖的方式,我们可以跳过Vue.extend()方法,直接通过Vue.component()方法实现组件的注册。


<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><div id="app"><!-- 3、使用组件 --><cpn1></cpn1><cpn2></cpn2></div><script src="../js/vue.js"></script><script>// 1、全局组件注册语法糖//  1.1 创建组件构造器// const cpn1 = Vue.extend({//     template: `//         <div>//             <h2>我是标题</h2>//             <p>我是内容,哈哈哈哈</p>//             <p>我是内容,呵呵呵呵</p>//         </div>`,// });//  1.2 注册组件// Vue.component('cpn1', cpn1);Vue.component('cpn1', {template: `<div><h2>我是标题</h2><p>我是内容,哈哈哈哈</p><p>我是内容,呵呵呵呵</p></div>`,});const app = new Vue({el: '#app', data: {    },components: {cpn2: {template: `<div><h2>我是标题</h2><p>我是内容,哈哈哈哈</p><p>我是内容,呵呵呵呵</p></div>`,}}})</script>
</body>
</html>

1.5 组件模板抽离的写法

IDE中,写组件的template时,由于其是一个字符串,所以没有代码提示,写起来非常不方便。并且template的代码直接耦合在Vue的代码中,非常的凌乱。为此,我们可以将组件的模板抽离出来,有两种抽离的方式。


<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><div id="app"><cpn1></cpn1><hr><cpn2></cpn2></div><!-- 1、第一种写法 --><script type="text/x-template" id="cpn"><div><h2>我是标题</h2><p>我是内容,哈哈哈哈</p></div></script><!-- 2、第二种写法 --><template id="cpn2"><div><h2>我是标题</h2><p>我是内容,哈哈哈哈</p></div></template><script src="../js/vue.js"></script><script>Vue.component('cpn1', {template: '#cpn',});Vue.component('cpn2', {template: '#cpn2',});const app = new Vue({el: '#app', data: {    },})</script>
</body>
</html>


       通常,我们采用的是方式二。可以看到,组件模板抽离后的代码看起来非常简洁。

1.6 组件数据存放

组件是一个单独功能模块的封装:

这个模块有自己的 HTML 模板,也应该有属于自己的数据data

组件中的数据是保存在哪里呢?顶层的Vue实例中吗?

我们可以通过下面的代码测试,组件中能不能直接访问Vue实例中的data


<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><div id="app"><cpn></cpn></div><template id="a"><div><h2>{{ message}}</h2></div></template><script src="../js/vue.js"></script><script>Vue.component('cpn', {template: '#a',});const app = new Vue({el: '#app', data: {message: 'Hello'},})</script>
</body>
</html>


       我们发现并不能访问,而且即使可以访问,如果将所有的数据都放在Vue实例中,Vue实例会变的非常臃肿。

结论:Vue 组件应该有自己保存数据地方

组件自己的数据存放在哪里呢?

  • 组件对象也有一个data属性(也可以有methods属性)
  • 只是这个data属性必须是一个函数
  • 而且这个函数返回一个对象,对象内部保存着数据

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><div id="app"><cpn></cpn></div><template id="a"><div><h2>{{ title }}</h2><p>我是内容,哈哈哈哈</p></div></template><script src="../js/vue.js"></script><script>Vue.component('cpn', {template: '#a',data() {return {title: 'Hello'}}});const app = new Vue({el: '#app', data: {    },})</script>
</body>
</html>

1.7 父子组件通信

子组件是不能引用父组件或者Vue实例的数据的。

但是,在开发中,往往一些数据确实需要从上层产地到下层:

  • 比如在一个页面中,我们从服务器请求到了很多的数据
  • 其中一部分数据,并非是我们整个页面的大组件来展示的,而是需要下面的子组件进行展示
  • 这个时候,并不会让子组件再次发送要给网络请求,而是直接让大组件(父组件)将数据传递给小组件(子组件)。

如果进行父子组件间的通信呢?官方提到

  • 通过props向子组件传递数据
  • 通过事件向父组件发送消息

Vue实例同样是组件,所以Vue实例与子组件通信和父组件与子组件通信的过程是一样的。

父组件向子组件传递数据

在子组件中,使用选项props来声明需要从父组件接收到的数据。

props的值有两种方式:

  • 方式一:字符串数组,数组中的字符串就是传递时的名称。
  • 方式二:对象,对象可以设置传递时的类型,也可以设置默认值等。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><div id="app"><cpn :cmovies="movies" :cmessage="message"></cpn><!-- 如果要传递的是 data 属性,则必须用 v-bind --><cpn cmovies="movies" cmessage="message"></cpn></div><template id="a"><div>{{cmessage}}<ul><li v-for="movie in cmovies">{{movie}}</li></ul></div></template><script src="../js/vue.js"></script><script>const cpn = {template: '#a',props: ['cmovies', 'cmessage'],}const app = new Vue({el: '#app', data: {message: 'Hello',movies: ['a', 'b', 'c', 'd']   },components: {cpn}})</script>
</body>
</html>


       在上面,我们的props选项是使用一个数组。

我们说过,处理数组之外,我们也可以使用对象,当需要对props进行类型等验证时,就需要对象写法了。

验证都支持如下数据类型:

  • String
  • Number
  • Boolean
  • Array
  • Object
  • Date
  • Function
  • Symbol
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><div id="app"><cpn :cmovies="movies" ></cpn><!-- 错误语法:必须用 v-bind --><!-- <cpn cmovies="movies" cmessage="message"></cpn> --></div><template id="a"><div>{{cmessage}}<ul><li v-for="movie in cmovies">{{movie}}</li></ul></div></template><script src="../js/vue.js"></script><script>const cpn = {template: '#a',// props: ['cmovies', 'cmessage'],props: {// 1、类型检查// cmovies: Array,// cmessage: String// 2、提供一些默认值cmessage: {type: String,default: 'aaaa',required: false},cmovies: {type: Array,}}}const app = new Vue({el: '#app', data: {message: 'Hello',movies: ['a', 'b', 'c', 'd']   },components: {cpn}})</script>
</body>
</html>

子组件向父组件传递数据

props用于父组件向子组件传递数据,还有一种比较常见的是子组件传递数据或事件到父组件中。

我们应该如何处理呢?这个时候,我们需要使用自定义事件来完成。

什么时候需要自定义事件呢?

  • 当子组件需要向父组件传递数据时,就要用到自定义事件了。
  • 我们之前学习的v-on不仅仅可以用于监听DOM事件,也可以用于组件间的自定义事件。

自定义事件的流程︰

  • 在子组件中,通过$emit('事件名', [参数])来触发事件。
  • 在父组件中,通过v-on来监听子组件事件。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><!-- 父组件模板 --><div id="app"><cpn v-on:itemclick="cpnClick"></cpn></div><!-- 子组件模板 --><template id="a"><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: '#a',data() {return {categories: [{id: 1, name: '热门推荐'},{id: 2, name: '手机数码'},{id: 3, name: '家用家电'},{id: 4, name: '电脑办公'},]}},methods: {btnClick(item) {// 产生事件:自定义事件this.$emit('itemclick', item);}}}const app = new Vue({el: '#app', data: {},components: {cpn},methods: {cpnClick(item) {console.log(item)}}})</script>
</body>
</html>

上面代码的含义如下:

  1. 父组件监听itemclick事件,该事件产生时,执行cpnClick方法
  2. 点击子组件内部的按钮时,执行btnClick方法
  3. btnClick方法内部,产生itemclick事件
  4. 由此便完成了子组件向父组件的数据传递

1.8 组件访问

有时候,我们需要父组件直接访问子组件,子组件直接访问父组件,或者是子组件访问根组件。

  • 父组件访问子组件:使用$children$refs
  • 子组件访问父组件:使用$parent

父组件访问子组件

children

  • this.$children是一个数组类型,它包含所有子组件对象
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><div id="app"><cpn></cpn><button @click="btnClick">点击</button></div><template id="cpn"><div><h2>我是子组件</h2></div></template><script src="../js/vue.js"></script><script>const app = new Vue({el: '#app', data: {},methods: {btnClick() {console.log(this.$children);this.$children[0].showMessage();}},components: { cpn: {template: '#cpn',methods: {showMessage() {console.log("showMessage")}}}},})</script>
</body>
</html>


       可以看到,我们通过this.$children成功访问了cpn组件,并且调用了cpn所拥有的methods。当然也可以访问cpn的其他属性。

refs

通过this.$children存在这样一个问题,便是我们要访问一个组件时,可能并不知道其索引,需要进行遍历查找。

this.$refs的作用相当于给组件一个id,这样我们便能根据这个id直接找到对应的组件了。


<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><div id="app"><cpn ref="aaa"></cpn><button @click="btnClick">点击</button></div><template id="cpn"><div><h2>我是子组件</h2></div></template><script src="../js/vue.js"></script><script>const app = new Vue({el: '#app', data: {},methods: {btnClick() {console.log(this.$refs);console.log(this.$refs.aaa);this.$refs.aaa.showMessage();}},components: { cpn: {template: '#cpn',methods: {showMessage() {console.log("showMessage")}}}},})</script>
</body>
</html>

子组件访问父组件

  • this.$parent获得父组件
  • this.$root获得根组件

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><div id="app"><cpn></cpn></div><template id="cpn"><div><h2>我是子组件</h2><button @click="btnClick">点击</button></div></template><script src="../js/vue.js"></script><script>const app = new Vue({el: '#app', data: {},methods: {showMessage() {console.log("showMessage")}},components: { cpn: {template: '#cpn',methods: {btnClick() {console.log(this.$parent);this.$parent.showMessage();// 访问根组件console.log(this.$root);}}}},})</script>
</body>
</html>

1.9 插槽

slot翻译为插槽:

  • 在生活中很多地方都有插槽,电脑的USB插槽,插板当中的电源插槽。口插槽的目的是让我们原来的设备具备更多的扩展性。
  • 比如电脑的USB我们可以插入U盘、硬盘、手机、音响、键盘、鼠标等等。

组件的插槽︰

  • 组件的插槽也是为了让我们封装的组件更加具有扩展性。
  • 让使用者可以决定组件内部的一些内容到底展示什么。

例子∶移动网站中的导航栏。

  • 移动开发中,几乎每个页面都有导航栏。
  • 导航栏我们必然会封装成一个插件,比如nav-bar组件。一旦有了这个组件,我们就可以在多个页面中复用了。

如何去封装这类的组件呢?

  • 它们也很多区别,但是也有很多共性。
  • 如果,我们每一个单独去封装一个组件,显然不合适∶比如每个页面都返回,这部分内容我们就要重复去封装。
  • 但是,如果我们封装成一个,好像也不合理∶有些左侧是菜单,有些是返回,有些中间是搜索,有些是文字,等等。

如何封装合适呢?抽取共性,保留不同

  • 最好的封装方式就是将共性抽取到组件中,将不同暴露为插槽。
  • 一旦我们预留了插槽,就可以让使用者根据自己的需求,决定插槽中插入什么内容。
  • 是搜索框,还是文字,还是菜单。由调用者自己来决定。

这就是为什么我们要学习组件中的插槽slot的原因。

slot


<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><!-- 1、插槽的基本使用 <slot></slot>2、插槽的默认值 <slot>button</slot>3、如果有多个值,同时放入到组件进行替换时,一起作为替换元素--><div id="app"><cpn><button>按钮</button></cpn><cpn><div>哈哈哈</div></cpn><cpn><a href="">百度</a></cpn><cpn></cpn></div><template id="cpn"><div><h2>我是组件</h2><div>我是组件,哈哈哈</div><slot></slot><!-- 可以给 slot 默认值,如果父组件没有插入,则使用默认值 --><!-- <slot><button>按钮</button></slot> --></div></template><script src="../js/vue.js"></script><script>const app = new Vue({el: '#app', data: {},components: {cpn: {template: '#cpn',}}})</script>
</body>
</html>


       在上面的代码中,我们在组件中使用<slot></slot>创建插槽,当我们使用该组件时,组件标签内的内容会自动替换掉<slot></slot>

具名插槽

当子组件的功能复杂时,子组件的插槽可能并非是一个。

  • 比如我们封装一个导航栏的子组件,可能就需要三个插槽,分别代表左边、中间、右边。
  • 那么,外面在给插槽插入内容时,如何区分插入的是哪—个呢?
  • 这个时候,我们就需要给插槽起一个名字

如何使用具名插槽呢?

  • 非常简单,只要给slot元素一个name属性即可<slot name='myslot'> </slot>

我们来给出一个案例︰

  • 这里我们先不对导航组件做非常复杂的封装,先了解具名插槽的用法。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><div id="app"><cpn><span slot="center">标题</span></cpn></div><template id="cpn"><div><slot name="left"><span>左边</span></slot><slot name="center"><span>中间</span></slot><slot name="right"><span>右边</span></slot></div></template><script src="../js/vue.js"></script><script>const app = new Vue({el: '#app', data: {},components: {cpn: {template: '#cpn',}}})</script>
</body>
</html>


       在上面的代码中,我们在组件中创建了三个具名插槽,分别为leftcenterright.

我们使用该组件时,通过slot="center"指定要将内容插入到center的插槽。

作用域插槽

在了解作用域插槽之前,我们需要西安了解一个概念:编译作用域

官方对于编译的作用域解析比较简单,我们自己来通过一个例子来理解这个概念:

我们来考虑下面的代码是否最终是可以渲染出来的︰

  • <my-cpn v-show="isShow"></my-cpn>中,我们使用了isShow属性。
  • isShow属性包含在组件中,也包含在Vue实例中。

答案︰最终可以渲染出来,也就是使用的是Vue实例的属性。

为什么呢?

  • 官方给出了一条准则∶父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译
  • 而我们在使用<my-cpn v-show="isShow"></my-cpn>的时候,整个组件的使用过程是相当于在父组件中出现的。
  • 那么他的作用域就是父组件,使用的属性也是属于父组件的属性。
  • 因此,isShow使用的是Vue实例中的属性,而不是子组件的属性。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><div id="app"><cpn v-show="isShow"></cpn></div><template id="cpn"><div><h2>我是组件</h2><div>我是组件,哈哈哈</div><button v-show="isShow">按钮</button></div></template><script src="../js/vue.js"></script><script>const app = new Vue({el: '#app', data: {isShow: true},components: {cpn: {template: '#cpn',data() {return {isShow: false}}}}})</script>
</body>
</html>

作用域插槽是slot—个比较难理解的点,而且官方文档说的又有点不清晰。

这里,我们用一句话对其做一个总结,然后我们在后续的案例中来体会︰

  • 父组件替换插槽的标签,但是内容由子组件来提供

我们先提一个需求︰

  • 子组件中包括一组数据:比如: pLanguages: ['JavaScript', 'Python', 'Swift', 'Go','C++']
  • 需要在多个界面进行展示:
    • 某些界面是以水平方向展示的
    • 某些界面是以列表形式展示的
    • 某些界面直接展示一个数组
  • 内容在子组件,希望父组件告诉我们如何展示,怎么办呢?
  • 利用slot作用域插槽就可以了

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><div id="app"><cpn></cpn><cpn><!-- 目的是获取子组件中的 pLanguages --><template slot-scope="slot"><span v-for="item in slot.data">{{item}} - </span></template></cpn></div><template id="cpn"><div><h2>我是组件</h2><slot :data="pLanguages"><ul><li v-for="item in pLanguages">{{item}}</li></ul></slot></div></template><script src="../js/vue.js"></script><script>const app = new Vue({el: '#app', data: {},components: {cpn: {template: '#cpn',data() {return {pLanguages: ['Python', 'Java', 'Go', 'C++']}}}}})</script>
</body>
</html>

Vue.js 组件化开发相关推荐

  1. Vue.js组件化开发实践

    Vue.js组件化开发实践 前言 公司目前制作一个H5活动,特别是有一定统一结构的活动,都要码一个重复的轮子.后来接到一个基于模板的活动设计系统的需求,便有了一下的内容.首先会对使用Vue进行开发的一 ...

  2. VUE.JS 组件化开发实践

    前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家.点击跳转到教程. 前言 公司目前制作一个H5活动,特别是有一定统一结构的活动,都要码一个重复的轮子.后来接到一个基于模 ...

  3. React.js组件化开发第一步(框架搭建)

    开始前 安装 node.js; 安装 cnpm; 安装 yarn; 安装完成yarn后, 将镜像替换成国内的: $ yarn config set registry 'https://registry ...

  4. Vue/React组件化开发的一些思考

    组件化开发的优势 组件化开发利用了面向对象的威力,易于构建规模比较大的应用并且获得比较高的可维护性,可扩展性.Vue.React厂商及社区不但提供了组件化开发的框架,而且提供了易于起步并包含了从编码. ...

  5. html 组件化 编辑器,vue.js组件化使用百度富文本编辑器(一)

    注意: 本文采用的编辑器为:idea 1.下载百度富文本编辑器,地址:https://ueditor.baidu.com/website/download.html#ueditor 2.加入到stat ...

  6. Vue.js组件化笔记

    局部调用 <template><my-page></my-page> </template><script> import MyPage f ...

  7. Vue | Vue.js 组件化基础 - 脚手架

  8. 【Vue.js 知识量化】组件化开发 + 前端模块化

    Vue.js 组件化开发 组件化 认识组件化 注册组件 全局组件和局部组件 父子组件 组件数据 父子组件的通信 父->子:props 子->父:$emit() 父子组件的访问方式 $chi ...

  9. Vue.js教程-组件化开发

    Vue.js教程-组件化开发 前言 Vue组件化 什么是组件化 Vue单页面开发的解释 组件化思想 组件的使用 原理 实际开发中的使用-父子组件 父子组件传递数据 父传子-props用法 子传父-th ...

最新文章

  1. Go语言学习笔记 - PART11 - 面向对象
  2. [iOS] 在UIToolBar中增加UILabel等控件(xib/storyboard图形界面方式)
  3. 织梦防html5,最近织梦DEDECMS被注入漏洞,如何做好防护措施。
  4. 查看coo_matrix的shape
  5. “宝藏”大会NVIDIA GTC Digital来袭!这些AI前沿课程不容错过
  6. spring boot 跨域请求_SpringBoot 系列教程 web 篇之自定义请求匹配条件 RequestCondition...
  7. Angular自学笔记(?)结构型指令
  8. Django的各种初识
  9. vs2005新建类,自定义模板信息(转载)
  10. 软考系统架构师笔记-综合知识重点(二)
  11. 效果直逼flash的Div+Css+Js菜单
  12. Alpha版本冲刺(一)
  13. SQL Server数据库 - 安装教程
  14. 浏览器自定义横向滚动条_自定义滚动条–跨浏览器解决方案
  15. Bugku:杂项 一枝独秀
  16. 常用的四大绩效考核方法以及优缺点
  17. 微信小程序的版本更新机制是什么?
  18. Visual Studio2013 调试报错:该文件没有与之关联的程序来执行该操作。请安装应用,若已经安装应用,请在“默认应用设置...
  19. 腾讯视频显示网络连接服务器失败怎么办,腾讯视频不能投屏怎么回事 腾讯视频无法投屏的解决方法...
  20. 深度学习系列 -- 神经网络和深度学习(Neural Networks and Deep Learning)(一):深度学习引言以及神经网络编程基础

热门文章

  1. R语言 牛顿-拉夫森迭代法求方程组
  2. Abbkine ExKine 胞浆蛋白提取试剂盒
  3. 没用的大用_拔剑-浆糊的传说_新浪博客
  4. 2020-11-02 很多人比起穷,更受不了慢慢变富
  5. IT各大技术经典视频教程大全 一
  6. 某月某日前包括当天吗_几号之前包括当天吗
  7. 用c++实现AES基本算法
  8. Newton-Raphson法
  9. 如何获取input输入框中的值?
  10. 上古世纪美服服务器在哪个文件夹,美服《上古世纪》新的封闭测试将Leviathan更新带到中国服务器上...