Blogger Information
Blog 32
fans 0
comment 0
visits 22276
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
vue学习之路(组件)
培(信仰)
Original
603 people have browsed it

vue学习之路(组件)

什么是组件

组件是可复用的 Vue 实例,且带有一个名字。我们可以在一个通过 new Vue 创建的 Vue 根实例中,把这个组件作为自定义元素来使用

组件与组件树

  1. <!-- 挂载点:是隐式声明根组件 -->
  2. <div id="root">
  3. <child-component></child-component>
  4. <child-component></child-component>
  5. <child-component></child-component>
  6. </div>
  7. <script>
  8. // 组件:从形式上看就是一个自定义html标签
  9. // 组件是可复用的vue实例,构造函数Vue的子类
  10. // 1. 创建
  11. // const childComponent = Vue.extend({
  12. // template: "<h2>hello world</h2>",
  13. // });
  14. // 2. 注册
  15. // 使用Vue.component()静态方法注册的是 全局组件
  16. // Vue.component(组件名,对象字面量表示的组件配置项)
  17. // 组件名:自定义的html标签
  18. // Vue.component("child-component", childComponent);
  19. Vue.component("child-component", {
  20. template: "<h2>hello world</h2>",
  21. });
  22. // 3. 挂载
  23. // 将标签添加到页面渲染
  24. const vm = new Vue({
  25. el: document.querySelector("#root"),
  26. });
  27. </script>

全局组件

全局组件:全局可见,声明在Vue实例外部

  1. <div id="root">
  2. <button-inc></button-inc>
  3. </div>
  4. <hr />
  5. <div id="app">
  6. <button-inc></button-inc>
  7. </div>
  8. <script>
  9. // 全局组件:全局可见,声明在Vue实例外部
  10. Vue.component("button-inc", {
  11. // 组件中的模板代码:允许存在数据占位符的html字符串
  12. // 模板内容必须写到一对父元素标签中
  13. template: `
  14. <div>
  15. <button @click="count++">点赞:+{{count}}</button>
  16. </div>
  17. `,
  18. data() {
  19. return {
  20. count: 0,
  21. };
  22. },
  23. });
  24. const vm = new Vue({
  25. el: document.querySelector("#root"),
  26. });
  27. const vm1 = new Vue({
  28. el: document.querySelector("#app"),
  29. });
  30. // 全局组件可以在多个Vue实例共享,通常一个项目只有一个vue实例,全局组件尽可能不用,使用局部组件。
  31. </script>

还可以将组件中的 template 提出去到html中。

  1. <div id="root">
  2. <button-inc></button-inc>
  3. </div>
  4. <hr />
  5. <div id="app">
  6. <button-inc></button-inc>
  7. </div>
  8. <!-- 模板开始 -->
  9. <template id="inc">
  10. <div>
  11. <button @click="count++">点赞:+{{count}}</button>
  12. </div>
  13. </template>
  14. <!-- 模板结束 -->
  15. <script>
  16. Vue.component("button-inc", {
  17. template: "#inc",
  18. // 组件中必须使用函数data()来声明组件变量
  19. data() {
  20. return {
  21. count: 0,
  22. };
  23. },
  24. });
  25. const vm = new Vue({
  26. el: document.querySelector("#root"),
  27. });
  28. const vm1 = new Vue({
  29. el: document.querySelector("#app"),
  30. });
  31. // 全局组件可以在多个Vue实例共享,通常一个项目只有一个vue实例,全局组件尽可能不用,使用局部组件。
  32. </script>

局部组件

局部组件是属于vue实例

  1. <div id="root">
  2. <my-child></my-child>
  3. </div>
  4. <template id="hello">
  5. <p>hello {{userName}}</p>
  6. </template>
  7. <script>
  8. const vm = new Vue({
  9. el: document.querySelector("#root"),
  10. // 局部组件是属于vue实例
  11. components: {
  12. "my-child": {
  13. template: "#hello",
  14. data() {
  15. return {
  16. userName: "TJ",
  17. };
  18. },
  19. },
  20. },
  21. });
  22. </script>

另一种简写方案

  1. <div id="root">
  2. <hello></hello>
  3. </div>
  4. <script>
  5. const hello={
  6. template: `<p>hello {{userName}}</p>`,
  7. data() {
  8. return {
  9. userName: "TJ",
  10. },
  11. }
  12. };
  13. const vm = new Vue({
  14. el: document.querySelector("#root"),
  15. // 局部组件是属于vue实例
  16. components: {hello},
  17. },
  18. });
  19. </script>

组件之间的传参:父组件向子组件传参

父组件是通过自定义属性的方式将参数传到子组件中的

  1. <div id="app">
  2. <!-- 父组件是通过自定义属性的方式将参数传到子组件中的 -->
  3. <btn-inc :username="username" :count="count"></btn-inc>
  4. </div>
  5. <script>
  6. const vm = new Vue({
  7. el: document.querySelector("#app"),
  8. data() {
  9. return {
  10. username: "TJ",
  11. count: 0,
  12. };
  13. },
  14. //局部组件
  15. components: {
  16. btnInc: {
  17. props: ["username","count"],
  18. // 报错原因,组件之间的数据传递是单向的,不允许在子组件中更新父组件的数据。
  19. template: `
  20. <div>
  21. <button @click="inc(1)">点赞:+{{num}}</button>
  22. <span>{{username}}</span>
  23. </div>
  24. `,
  25. data(){
  26. return {
  27. num:this.count,
  28. }
  29. },
  30. methods:{
  31. inc(n) {
  32. this.num += n;
  33. }
  34. }
  35. },
  36. },
  37. });
  38. </script>

组件之间的传参:子组件向父组件传参

  1. <div id="app">
  2. <!-- 子组件中的更新父组件数据是通过自定义同名事件完成的-->
  3. <btn-inc
  4. :username="username"
  5. :count="count"
  6. @click-count="handle"
  7. ></btn-inc>
  8. </div>
  9. <script>
  10. const vm = new Vue({
  11. // 子组件向父组件传参是通过声明同名事件来实现
  12. el: document.querySelector("#app"),
  13. data() {
  14. return {
  15. username: "TJ",
  16. count: 0,
  17. };
  18. },
  19. //局部组件
  20. components: {
  21. btnInc: {
  22. props: ["username", "count"],
  23. // 报错原因,组件之间的数据传递是单向的,不允许在子组件中更新父组件的数据。
  24. // $emit(父组件中要使用的方法名称,子组件要传给父组件的值)
  25. template: `
  26. <div>
  27. <button @click="$emit('click-count',10)">点赞:+{{count}}</button>
  28. <span>{{username}}</span>
  29. </div>
  30. `,
  31. methods: {
  32. inc(n) {
  33. this.num += n;
  34. },
  35. },
  36. },
  37. },
  38. // 父组件更新数据的方法
  39. methods: {
  40. handle(value) {
  41. this.count += value;
  42. this.username = "T.,j";
  43. console.log(vm.count);
  44. },
  45. },
  46. });
  47. // 总结:
  48. // 1. 父组件 向 子组件 传参: 自定义属性
  49. // 2. 子组件 向 父组件 传参: 自定义方法
  50. </script>

组件之间的双向传参

  1. <div id="demo">
  2. <input type="text" :value="value" @input="value = $event.target.value" />
  3. <p>{{value}}</p>
  4. </div>
  5. <script>
  6. new Vue({
  7. el: "#demo",
  8. data() {
  9. return {
  10. value: 123,
  11. };
  12. },
  13. });
  14. </script>
  15. <hr />
  16. <div id="app">
  17. <p>父组件 单价:{{price}} 元</p>
  18. <p>
  19. <span>子组件</span
  20. ><my-input :my-price="price" @input-text="handle"></my-input>
  21. </p>
  22. </div>
  23. <script>
  24. const vm = new Vue({
  25. // 子组件向父组件传参是通过声明同名事件来实现
  26. el: document.querySelector("#app"),
  27. data() {
  28. return {
  29. price: 4588,
  30. };
  31. },
  32. //局部组件
  33. components: {
  34. myInput: {
  35. props: ["my-price"],
  36. template: `
  37. <input type="text" :value="myPrice" @input="$emit('input-text',$event.target.value)" />
  38. `,
  39. },
  40. },
  41. methods: {
  42. handle(value) {
  43. this.price = value;
  44. },
  45. },
  46. });
  47. </script>

另一种简化方案:将$emit()提出去,写到methods里

  1. <div id="app">
  2. <p>父组件 单价:{{price}} 元</p>
  3. <p>
  4. <span>子组件</span
  5. ><my-input :my-price="price" @input-text="handle"></my-input>
  6. </p>
  7. </div>
  8. <script>
  9. const vm = new Vue({
  10. // 子组件向父组件传参是通过声明同名事件来实现
  11. el: document.querySelector("#app"),
  12. data() {
  13. return {
  14. price: 4588,
  15. };
  16. },
  17. //局部组件
  18. components: {
  19. myInput: {
  20. props: ["my-price"],
  21. template: `
  22. <input type="text" :value="myPrice" @input="foo" />
  23. `,
  24. methods:{
  25. foo(ev){
  26. this.$emit('input-text',ev.target.value)
  27. }
  28. }
  29. },
  30. },
  31. methods: {
  32. handle(value) {
  33. this.price = value;
  34. },
  35. },
  36. });
  37. </script>

插槽:组件内容分发

  1. <div id="app">
  2. <my-comp>world</my-comp>
  3. </div>
  4. <script>
  5. new Vue({
  6. el: "#app",
  7. components: {
  8. myComp: {
  9. template: `
  10. <div>
  11. <h2>Hello <slot>user</slot></h2>
  12. </div>
  13. `,
  14. },
  15. },
  16. });
  17. </script>

注意:
难点是子组件向父组件传参通过同名事件完成 $emit(同名事件名,参数),如果把此处提出写到methods中要使用this.$emit(),因为是要指定是子组件
在手册中提到在组件中使用v-model

自定义事件也可以用于创建支持 v-model 的自定义输入组件。

  1. <input v-model="searchText">

等价于:

  1. <input
  2. v-bind:value="searchText"
  3. v-on:input="searchText = $event.target.value"
  4. >

当用在组件上时,v-model 则会这样:

  1. <custom-input
  2. v-bind:value="searchText"
  3. v-on:input="searchText = $event"
  4. ></custom-input>

为了让它正常工作,这个组件内的 <input> 必须:

将其 value attribute 绑定到一个名叫 value 的 prop 上
在其 input 事件被触发时,将新的值通过自定义的 input 事件抛出

写成代码之后是这样的:

  1. Vue.component('custom-input', {
  2. props: ['value'],
  3. template: `
  4. <input
  5. v-bind:value="value"
  6. v-on:input="$emit('input', $event.target.value)"
  7. >
  8. `
  9. })

现在 v-model 就应该可以在这个组件上完美地工作起来了:

  1. <custom-input v-model="searchText"></custom-input>

完整代码

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  7. <title>组件使用v-model</title>
  8. <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  9. </head>
  10. <body>
  11. <div id="app">
  12. <p>父组件:{{searchText}}</p>
  13. <custom-input v-model="searchText"></custom-input>
  14. </div>
  15. <script>
  16. new Vue({
  17. el: "#app",
  18. data() {
  19. return {
  20. searchText: "test",
  21. };
  22. },
  23. components: {
  24. "custom-input": {
  25. props: ["value"],
  26. template: `
  27. <input
  28. v-bind:value="value"
  29. v-on:input="$emit('input', $event.target.value)"
  30. >
  31. `,
  32. },
  33. },
  34. });
  35. </script>
  36. </body>
  37. </html>

感觉组件使用v-model不是很灵活的样子

Correcting teacher:天蓬老师天蓬老师

Correction status:qualified

Teacher's comments:
Statement of this Website
The copyright of this blog article belongs to the blogger. Please specify the address when reprinting! If there is any infringement or violation of the law, please contact admin@php.cn Report processing!
All comments Speak rationally on civilized internet, please comply with News Comment Service Agreement
0 comments
Author's latest blog post