Vue.js 组件化开发

三、组件化开发

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

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

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

       组件化也是类似的思想:

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

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

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

Vue.js 组件化开发_第1张图片
       组件化思想的应用:

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

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

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

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

Vue.js 组件化开发_第2张图片


<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>Documenttitle>
head>
<body>
    
    <div id="app">
        
        <my-cpn>my-cpn>
        <my-cpn>my-cpn>
    div>
    <script src="../js/vue.js">script>
    <script>
        // 1、创建组件构造器
        const cpnC = Vue.extend({
      
            template: `
                

我是标题

我是内容,哈哈哈哈

我是内容,呵呵呵呵

`
, }); // 2、注册组件 Vue.component('my-cpn', cpnC); const app = new Vue({ el: '#app', data: { } })
script> body> html>

Vue.js 组件化开发_第3张图片

组件注册步骤解析

  1. Vue.extend():

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

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

    • 下面的实例中,我们使用了三次
    • 但是第三次并没有生效

Vue.js 组件化开发_第4张图片

1.2 全局组件和局部组件

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


<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>Documenttitle>
head>
<body>
    
    <div id="app">
        
        <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: `
                

我是标题

我是内容,哈哈哈哈

我是内容,呵呵呵呵

`
, }); // 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中生效,符合我们的预期。

Vue.js 组件化开发_第5张图片

1.3 父组件和子组件

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

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

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



<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>Documenttitle>
head>
<body>
    
    <div id="app">
        <cpn2>cpn2>
    div>
    <script src="../js/vue.js">script>
    <script>
        // 1、创建第一个组件构造器(子组件)
        const cpnC1 = Vue.extend({
      
            template: `
                

我是标题1

我是内容,哈哈哈哈

`
, }); // 2、创建第二个组件构造器(父组件) const cpnC2 = Vue.extend({ template: `

我是标题2

我是内容,呵呵呵呵

`
, components: { cpn1: cpnC1, }, }); const app = new Vue({ el: '#app', data: { }, components: { cpn2: cpnC2, } })
script> body> html>

Vue.js 组件化开发_第6张图片
Vue.js 组件化开发_第7张图片

1.4 注册组件语法糖

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



<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>Documenttitle>
head>
<body>
    
    <div id="app">
        
        <cpn1>cpn1>
        <cpn2>cpn2>
    div>
    <script src="../js/vue.js">script>
    <script>
        // 1、全局组件注册语法糖
        //  1.1 创建组件构造器
        // const cpn1 = Vue.extend({
      
        //     template: `
        //         
//

我是标题

//

我是内容,哈哈哈哈

//

我是内容,呵呵呵呵

//
`,
// }); // 1.2 注册组件 // Vue.component('cpn1', cpn1); Vue.component('cpn1', { template: `

我是标题

我是内容,哈哈哈哈

我是内容,呵呵呵呵

`
, }); const app = new Vue({ el: '#app', data: { }, components: { cpn2: { template: `

我是标题

我是内容,哈哈哈哈

我是内容,呵呵呵呵

`
, } } })
script> body> html>

Vue.js 组件化开发_第8张图片

1.5 组件模板抽离的写法

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



<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>Documenttitle>
head>
<body>
    
    <div id="app">
        <cpn1>cpn1>
        <hr>
        <cpn2>cpn2>
    div>
    
    <script type="text/x-template" id="cpn">
        <div>
            <h2>我是标题</h2>
            <p>我是内容,哈哈哈哈</p>
        </div>
    script>
    
    <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>


Vue.js 组件化开发_第9张图片
       通常,我们采用的是方式二。可以看到,组件模板抽离后的代码看起来非常简洁。

1.6 组件数据存放

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

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

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

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



<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>Documenttitle>
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.js 组件化开发_第10张图片
       我们发现并不能访问,而且即使可以访问,如果将所有的数据都放在Vue实例中,Vue实例会变的非常臃肿。

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

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

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


<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>Documenttitle>
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>


Vue.js 组件化开发_第11张图片

1.7 父子组件通信

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

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

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

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

  • 通过props向子组件传递数据
  • 通过事件向父组件发送消息
    Vue.js 组件化开发_第12张图片

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

父组件向子组件传递数据

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

       props的值有两种方式:

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


<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>Documenttitle>
head>
<body>
    
    <div id="app">
       <cpn :cmovies="movies" :cmessage="message">cpn>
       
       <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>


Vue.js 组件化开发_第13张图片
       在上面,我们的props选项是使用一个数组。

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

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

  • String
  • Number
  • Boolean
  • Array
  • Object
  • Date
  • Function
  • Symbol

<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>Documenttitle>
head>
<body>
    
    <div id="app">
       <cpn :cmovies="movies" >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来监听子组件事件。

<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>Documenttitle>
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. 由此便完成了子组件向父组件的数据传递

Vue.js 组件化开发_第14张图片

1.8 组件访问

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

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

父组件访问子组件

children

  • this.$children是一个数组类型,它包含所有子组件对象

<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>Documenttitle>
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>

Vue.js 组件化开发_第15张图片
       可以看到,我们通过this.$children成功访问了cpn组件,并且调用了cpn所拥有的methods。当然也可以访问cpn的其他属性。

refs

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

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



<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>Documenttitle>
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>


Vue.js 组件化开发_第16张图片

子组件访问父组件

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


<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>Documenttitle>
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>


Vue.js 组件化开发_第17张图片

1.9 插槽

       slot翻译为插槽:

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

       组件的插槽︰

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

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

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

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

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

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

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

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

slot



<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>Documenttitle>
head>
<body>
    
    
    <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>
            
            
        div>
    template>
    <script src="../js/vue.js">script>
    <script>
        const app = new Vue({
      
            el: '#app', 
            data: {
      
            },
            components: {
      
                cpn: {
      
                    template: '#cpn',
                }
            }
        })
    script>
body>
html>


Vue.js 组件化开发_第18张图片
       在上面的代码中,我们在组件中使用创建插槽,当我们使用该组件时,组件标签内的内容会自动替换掉

具名插槽

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

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

       如何使用具名插槽呢?

  • 非常简单,只要给slot元素一个name属性即可

       我们来给出一个案例︰

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


<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>Documenttitle>
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>


Vue.js 组件化开发_第19张图片
       在上面的代码中,我们在组件中创建了三个具名插槽,分别为leftcenterright.

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

作用域插槽

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

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

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

  • 中,我们使用了isShow属性。
  • isShow属性包含在组件中,也包含在Vue实例中。

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

       为什么呢?

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


<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>Documenttitle>
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>


Vue.js 组件化开发_第20张图片

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

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

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

       我们先提一个需求︰

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


<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>Documenttitle>
head>
<body>
    <div id="app">
        <cpn>cpn>
        <cpn>
            
            <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 组件化开发_第21张图片

你可能感兴趣的:(Vue,vue)