Vue - 6 组件与属性

Vue - 6 组件与属性


1.Vue组件

image-20230217145541570

在 Vue.js 中,组件是一种可复用的 Vue 实例,可以定义自己的模板、样式和逻辑,并且可以被其他 Vue 实例复用。使用组件可以将复杂的页面分解为多个独立的小组件,从而使代码更加简洁、可维护、可复用。

组件可以通过 Vue.component() 方法进行注册,也可以使用 .vue 文件进行定义。在注册组件时,需要指定组件的名称和组件选项。

组件选项包括组件的数据data【但是data需要写成函数的形式,并且将数据在return中返回】、模板template、方法methods、生命周期钩子函数等。定义好组件之后,就可以在其它 Vue 实例中使用该组件了。

(1)全局组件

通过Vue.component()方法进行注册的组件,被称之为全局组件

全局组件放在Vue实例【根组件】中

Vue.component('my-component', {
  data: function () {
    return {
      message: 'Hello Vue!'
    }
  },
  template: '<div>{{ message }}</div>'
})

(2)局部组件

在Vue实例中定义或者全局组件中定义的,以关键字components:{}中注册的组件,称之为局部组件。

局部组件常用的方式:是用一个变量名接收后,通过注册在不同的【全局组件】中或【根组件】中重复使用。

  • 案例
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!-- vue 文件 -->
    <script src="./js/vue.js"></script>
</head>
<body>
<div class="app">
    <my-component>
       
    </my-component>
  
  
</div>
</body>
<script>
    // 定义全局组件
    Vue.component('my-component', {
        // data需要以方法的形式出现,data中的数据可以重复使用
        data() {
            return {
                name: 'duoduo',
                show: false,
            }
        },
        // 在全局中设计局部组件
        template: `
          <div>
          <button @click="handleShow">展示名字</button>
               <sections></sections>
          <div v-if="show">名字{{ name }}</div>
          </div>`,
        methods: {
            handleShow() {
                this.show = !this.show
            }
        },
        // 局部组件
        components: {
            sections: {
                template: `
                   <div>

                  <div>年龄{{ age }}</div>  </div>
                  `,
                data() {
                    return {
                        age: 19
                    }
                },                                                            
            },


        }})

    let vm = new Vue({
        el: '.app',
        data: {},
        methods: {},
    })
</script>
</html>

2.组件注意

注意点:

(1)根组件

定义的组件(body中的位置)必须要放在Vue实例【这也是一个组件:根组件】中,new Vue()管理的div通常被称为根组件

(2)局部组件无法单独使用

必须放在全局组件/根组件中,无法单独使用

(3)定义的组件的位置

定义的组件必须放在Vue实例的上方,在渲染的时候,组件必须已经加载完毕

(4)组件中的配置项

  • 相同点:都有 数组、模版、方法等

组件选项包括组件的数据data【但是data需要写成函数的形式,并且将数据在return中返回】、模板template、方法methods、生命周期钩子函数等

①②③④⑤⑥⑦⑧

  • 不同点:

①data在组件中要写成函数的形式,数据在return中以返回值的形式返回

②在组件中this指代的不再是Vue实例,而是组件对象

③父子组件的data是无法共享的

(5)自定义组件需要有1个根标签

自定义组件需要有1个 root element,一般包裹在 1个div

3.组件间通信

组件间的数据是相互隔离的,无法共享。但是对于不同关系的组件间通信,Vue给出了不同的方法。

1.父传子:自定义属性

通过在子组件中【自定义属性】,就可以在子组件中通过【插值语法】来获得父组件的数据

(1)props关键字来声明需要通信的数据

  • props属性验证

通过给props传一个对象,键是变量,值是数据类型,则可以限制变量的类型

props:{age:Number}

(2)父传子:自定义属性

父传子使用自定义属性

  <child  :自定义属性="变量"></child>

1.自定义属性不可以使用驼峰体

2.父子组件之间,避免出现变量名冲突

  • 案例
<body>
<div class="app">

    <child :name1="name1"></child>

</div>
</body>
<script>
    // 定义子组件
    let child = {
        data() {
            return {
                mymsg: '这里是子组件的msg'
            }
        },
        template: `
          <div style="background-color: cornflowerblue">
          <h2>我是子组件</h2>
          <p>父传子:{{ name1 }}</p>
          </div>
        `,
        // 通过props配置项来声明 父组件传给子组件的值,并且可以限定数据的类型
        props:{name1:String},
    }

    // vue实例
    let vm = new Vue({
        el: '.app',
        data: {
            name1:'我是根组件',
        },
        // 在父组件中注册子组件
        components:{
            child
        }
    })
</script>

2.子传父:自定义事件

(1)在子组件中自定义事件,但是该自定义事件绑定的函数写在父组件的methods方法

<父组件>	
<child @自定义事件="函数"></child>
</父组件>

(2)在子组件中,通过$emit方法触发一个自定义事件,会执行父组件自定义事件绑定的函数

// 定义局部组件
    var child = {

        ...

        // 子组件中的方法,通过$emit方法触发一个自定义事件,并传递数据。
        methods: {
            mySend(){
                this.$emit('myroot',this.msg)

            }
        },
    }

(3)在父组件的methods方法中,将子组件传过来的数据值赋值给父组件中对应的值

    var vm = new Vue({
        el: '.app',
        data: {
            name:'根组件',
           // 一定要定义一个变量来接受子组件传递过来的值
           msg:''
        },
        methods: {
            // 自定义事件,触发后,将子组件传过来的数据值赋值给父组件中对应的值
            // 即可完成子组件给父组件传值
            getMsg(msg){
                this.msg = msg
                console.log(msg)
            }
        },
        components: {
            child
        }
    })
  • 案例
<body>
<div class="app">

    <h4>这里是根组件:{{msg}}</h4>
    <h4>根组件:{{name}}</h4>
    // 在子组件中自定义事件,通过触发事件来传递数据
    <child @myroot="getMsg"></child>

</div>
</body>
<script>
    // 定义局部组件
    var child = {
        // 在模版中定义方法,通过点击事件来使用$emit方法触发一个自定义事件,并传递数据
        template: `
          <div>
          <h3>##-- {{ msg }}  --##</h3>
          <button @click="mySend">点击发送</button>
          </div>
        `,
        // 定义在子组件中需要传递的数据,必须要return出去数据
        data() {
            return {
                msg: '来自子组件'
            }
        },
        // 子组件中的方法,通过$emit方法触发一个自定义事件,并传递数据。
        methods: {
            mySend(){
                this.$emit('myroot',this.msg)

            }
        },

    }

    var vm = new Vue({
        el: '.app',
        data: {
            name:'根组件',
           msg:''
        },
        methods: {
            // 子定义事件,触发后,将子组件传过来的数据值赋值给父组件中对应的值
            // 即可完成子组件给父组件传值
            getMsg(msg){
                this.msg = msg
                console.log(msg)
            }
        },
        components: {
            child
        }
    })
</script>

3.ref属性

自定义属性和自定义事件可以实现父子传值,但是通过vue提供的ref属性,可以更方便的事项父子组件间的通信

因此不需要关注是子传父,还是父传子,直接通过ref属性获取组件对象即可

(1)ref属性放在普通标签上,拿到标签的dom对象

ref属性放在普通标签上,通过this.$refs可以拿到所有写了ref属性的标签

vue将其封装成了对象,keyref属性对应的变量名,value原生dom对象,则可以通过ref属性直接修改原生dom对象的属性

(2)ref属性放在组件上,拿到组件对象

通过this.$refs.组件名,拿到组件对象,既可以拿到组件的属性,也可以拿到组件的方法

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!-- vue 文件 -->
    <script src="./js/vue.js"></script>
</head>
<body>
<div class="app">

    <h3>根组件---{{msg}}</h3>
    根组件中的input框:<input type="text" ref="myinput">
    <button @click="mySend">【父传子】发送消息</button>

    <hr>
    <h3>根组件中的子组件</h3>
    <child ref="mychild"></child>
    <hr>

</div>
</body>
<script>
    // 定义局部组件
    var child = {
        template: `
          <div>
          <p ref="childp">{{msg}}</p>
          <h3>子组件中的信息##-- {{ msg }}  --##</h3>
          <button @click="mySend">【子传父】发送消息</button>
          </div>
        `,
        data() {
            return {
                msg:"一条来自子组件的信息",
                name:'子组件的信息'
            }
        },
        methods: {
            mySend(){
                // alert(this.name)
                this.$emit('fu',this.msg)
                // this.msg=this.$refs..msg
            },

        },
    }

    var vm = new Vue({
        el: '.app',
        data: {
            msg: '来自根组件'
        },
        methods: {
            mySend() {
                console.log(this.$refs)
            },
            fu(msg){
                console.log(msg)
            }
        },
        // 在跟组件中注册子组件
        components: {
            child
        }
    })
</script>
</html>

4.动态组件

(1)原始

绑定点击事件,并且通过 v-if判断来显示不同的页面

<body>
<div class="app">
  
  <span @click="handleClick('home')">首页</span>| <span @click="handleClick('order')">订单</span> | <span
        @click="handleClick('goods')">商品</span>
  <home v-if="chooseType=='home'"></home>
  <order v-else-if="chooseType=='order'"></order>
  <goods v-else></goods>

</div>
</body>
<script>
  var home = {
    template: `
          <div>
          <h1>home页面</h1>
          </div>`,

  }
  var order = {
    template: `
          <div>
          <h1>order页面</h1>
          </div>`,

  }
  var goods = {
    template: `
          <div>
          <h1>商品页面</h1>
          </div>`,

  }

  var vm = new Vue({
    el: '.app',
    data: {
      chooseType: 'home'
    },
    methods: {
      handleClick(type) {
        this.chooseType = type
      }
    },
    components: {
      home,
      order, goods
    }
  })
</script>

(2)动态组件:component标签

通过component标签,绑定对应的数据值,根据组件对应的值不同来显示不同的组件

<body>
<div class="app">

    <span @click="handleClick('home')">首页</span>| <span @click="handleClick('order')">订单</span> | <span
        @click="handleClick('goods')">商品</span>

<!--   通过component标签,绑定is属性来动态判断-->
    <component :is="who"></component>
</div>
</body>
<script>
    var home = {
        template: `
          <div>
          <h1>home页面</h1>
          </div>`,

    }
    var order = {
        template: `
          <div>
          <h1>order页面</h1>
          </div>`,

    }
    var goods = {
        template: `
          <div>
          <h1>商品页面</h1>
          </div>`,

    }

    var vm = new Vue({
        el: '.app',
        data: {
            // data中绑定 component标签对应的value值,来通过value值的不同来显示不同页面
            who: 'home'
        },
        methods: {
            handleClick(type) {
                this.who = type
            }
        },
        components: {
            home,
            order,
            goods
        }
    })
</script>
</html>

(3)keep-alive:防止销毁组件

当组件部分的input框中,我们有输入的内容时,切换组件后,该内容会被销毁。而通过keep-alive标签,将component标签包裹起来后,key保持组件活跃状态不被销毁

<body>
<div class="app">

  <span @click="handleClick('home')">首页</span>| <span @click="handleClick('order')">订单</span> | <span
        @click="handleClick('goods')">商品</span>

  <!--   用keep-alive来包裹,保持组件活跃状态不被销毁-->
  <keep-alive>
  <component :is="who"></component>
  </keep-alive>
</div>
</body>
<script>
  var home = {
    template: `
          <div>
          <h1>home页面</h1>
          </div>`,

  }
  var order = {
    template: `
          <div>
          <h1>order页面</h1>
          <input type="text">输入的内容
          </div>`,

  }
  var goods = {
    template: `
          <div>
          <h1>商品页面</h1>
          </div>`,

  }

  var vm = new Vue({
    el: '.app',
    data: {
      // data中绑定 component标签对应的value值,来通过value值的不同来显示不同页面
      who: 'home'
    },
    methods: {
      handleClick(type) {
        this.who = type
      }
    },
    components: {
      home,
      order,
      goods
    }
  })
</script>

5.插槽

通过在组件内添加<slot></slot>标签,就可以在组件标签内添加不同的内容,并插在<slot></slot>标签的位置,增加组件的拓展性

(1)匿名插槽

<body>
<div class="app">
    <home>
      <div>
        <h2>我是插槽!!!</h2>
      </div>
    </home>
</div>
</body>

<script>
  let home = {
    template: `
          <div>
          <h1>home页面开始</h1>
            <slot></slot>
            <slot></slot>
            <h1>home页面结束</h1>
          </div>`,
  }
  let vm = new Vue({
    el:'.app',
    data:{},
    components:{
      home
    }
  })
</script>

(2)具名插槽

通过在<slot name='xxx'></slot>标签中的name属性给插槽起名字,并在想要添加在插槽内的标签添加 slot="xxx",指定插入的标签,当存在多个插入的标签时,可以通过名字来管理

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!-- vue 文件 -->
    <script src="js/vue.js"></script>
</head>
<body>
<div class="app">
    <home>
      <div slot="a">
        <h2>我是插槽AAA</h2>
      </div>
      <div slot="b">
        <h2>我是插槽BBB</h2>
      </div>

    </home>
</div>
</body>

<script>
  let home = {
    template: `
          <div>
          <h1>home页面开始</h1>
            <slot name="a"></slot>
            <slot name="a"></slot>
            <h1>home页面结束</h1>
          </div>`,
  }
  let vm = new Vue({
    el:'.app',
    data:{},
    components:{
      home
    }
  })
</script>
</html>

6.计算属性

计算属性是一种特殊的属性,计算属性的值是基于现有的状态计算得出的,并且只有在其依赖的状态发生变化时才会重新计算

(1)特性

1.延缓计算,只有发生依赖关系也就是只有使用的变量发生变化时候,才重新计算

2.可以将方法当做属性来用

(2)定义方式

通过配置项的关键字computed来定义

computed: {
  // 计算属性的名称
  propertyName () {
    // 计算属性的计算逻辑
    // 可以使用 this 来访问组件的状态
    return computedValue;
  }
}

计算属性的值可以通过在模板中使用该属性来获取:

<p>{{ propertyName }}</p>
  • 案例
<body>
<div class="app">
    <h1>过滤案例</h1>
    <p>请输入要搜索的内容:<input type="text" v-model="searchText"></p>
    <ul>
        <li v-for="item in newList">{{item}}</li>
    </ul>

</div>

</body>
<script>
    let vm = new Vue({
        el: '.app',
        data: {
            searchText: '',
            dataList: ['a', 'at', 'atom', 'be', 'beyond', 'cs', 'csrf']
        },
        methods: {},
        // 通过计算属性 computed 将newList方法包装成一个属性,每当使用的变量发生变化的时候,才会重新计算
        computed: {
            newList() {
                return this.dataList.filter(item => item.indexOf(this.searchText) >= 0)
            }
        }
    })
</script>

7.监听属性

在data中定义的变量,只要变量发生变化,Vue实例就会自动调用指定的回调函数

定义

通过配置项的关键字watch来定义

watch: {
  // 被监听的状态
  propertyName(newValue, oldValue) {
    // 回调函数,newValue表示新的值,oldValue表示旧的值
    // 在这里可以进行一些响应式的逻辑处理
  }
}

注意

  • watch选项监听的状态必须是响应式的。也就是说,它必须是通过data选项或props属性定义的
  • watch选项不支持使用计算属性或方法
  • 案例
<body>
<div>
  <div class="app">


    <div @click="handleVar=1"><h3>变量111</h3></div>

    <div @click="handleVar=2"><h3>变量222</h3></div>

  </div>

</div>
</body>
<script>
  var vm = new Vue({
    el: '.app',
    data: {
      handleVar: '0'
    },
    created() {
      this.getData()
    },
    methods: {
      getData() {
        // 可以发送ajax,与后端交互,获取数据值,重新渲染页面
        console.log('与后端交互')
      },
    },
    watch: {
      handleVar() {
        console.log('点击了不同的标签,变量发生了变化')
        this.getData()
      }
    }
  })
</script>
posted @ 2023-02-17 21:53  Duosg  阅读(199)  评论(0编辑  收藏  举报