欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

0602 vue2.x的组件

程序员文章站 2024-03-05 12:46:54
...

props

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>props</title>
  <script src="../../vue.js"></script>
</head>
<body>
  <div id="root">
    <child 
      :title-content="title"
      url="http://www.baidu.com"
      class="abc"
    ></child>
    <!-- <child></child> -->
    <!-- <div title-abc="msg"></div> -->
  </div>
  <script type="module">
    Vue.config.productionTip = false

    import Child from './Child.js'

    var vm = new Vue({
      el: '#root',
      data: {
        title: 'hello',
      },
      components: {
        child: Child
      },
      mounted() {
        setTimeout(() => {
          this.title = 'world'
        }, 1000)
      },
    })
  </script>
</body>
</html>

Child.js文件

const Child = {
  // props: ['titleContent'],
  props: {
    titleContent: {
      // type: Number
      // type: String
      // type: Boolean
      // type: Array,
      // type: Function,
      // type: Symbol,
      // type: [Number, String]
      type: String,
      // required: true
      // default: '标题'
      // default() {
      //   // 10000行的复杂逻辑
      //   return '标题一'
      // }
      validator(value) {
        // 返回值一定是个boolean
        return value.length >= 5
      }
    },
    // url: {
    //   type: String
    // }
  },
  inheritAttrs: false,
  template: `
    <div class="def">
      <h1>{{newTitle}}</h1>
      <div>{{title}}</div>
    </div>
  `,
  data() {
    return {
      // title: this.titleContent
      title2: ''
    }
  },
  beforeCreate() {
    // this.title = this.titleContent
  },
  computed: {
    newTitle() {
      return this.titleContent + 1
    },
    // title() {
    //   return this.titleContent + '!!!'
    // }
    title: {
      get() {
        return this.titleContent + '!!!'
      },
      set(value) {
        this.title2 = value
      }
    }
  },
  mounted() {
    this.title = 'world'
  },
}

export default Child

custom-event

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>custom events</title>
 <script src="../../vue.js"></script>
</head>
<body>
 <div id="root">
   <child
     @click.native="handleEvent"
   ></child>
    <!-- sync修饰符:相当于父组件授权给子组件,去修改父组件的状态 -->
   <child2
     :custom-event.sync="bar"
   ></child2>
   {{bar}}
 </div>
 <script>
   Vue.config.productionTip = false

   const Child = {
     template: `
       <div>
         <div>child</div>
         <button @click="handleClick">click</button>
       </div>
     `,
     methods: {
       handleClick() {
         // this.$emit('custom-event', 'hello')
       }
     },
     mounted() {
       // this.$emit('custom-event', 'hello')
     },
   }

   const Child2 = {
     template: `
       <div>
         <h1>header</h1>
         <button @click="handleClick">click</button>
       </div>
     `,

     methods: {
       handleClick() {
         // this.$emit('custom-event', { bar: 'hello' })
         this.$emit('update:custom-event', 'hello')
       }
     },
   }

   var vm = new Vue({
     el: '#root',
     data: {
       bar: 'aaa'
     },
     components: {
       child: Child,
       child2: Child2
     },
     methods: {
       handleEvent(msg) {
         console.log(msg)
       },
       // handleChild2Event(msg) {
       //   this.bar = msg.bar
       // }
     },
   })
 </script>
</body>
</html>

自定义组件

自定义组件只能用kebab-case的命名方法,大驼峰和小驼峰均不行

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>component advanced</title>
  <script src="../vue.js"></script>
</head>
<body>
  <div id="root">
    <my-component></my-component>
    <your-component></your-component>
  </div>
  <script type="module">
    import YourComponent from './YourComponent.js'

    Vue.config.productionTip = false

    // camelCase  小驼峰
    // ParscalCase 大驼峰
    // kebab-case 肉串
    Vue.component('my-component', {
      template: `
        <div>product</div>
      `
    })

    // 局部定义组件
    // const YourComponent = {
    //   template: `
    //     <div>cart</div>
    //   `
    // }

    var vm = new Vue({
      el: '#root',
      // template: `
      //   <my-component></my-component>
      // `,
      // title: 'hello',
      // handleClick() {
      //   console.log(100)
      //   console.log(this)
      // },
      mounted() {
        // this.$options.handleClick.call(this)
        // console.log(this.$options.title)
      },

      // 在这个组件上挂载其他的组件
      components: {
        'your-component': YourComponent
      }
    })
  </script>
</body>
</html>

YouComponent.js文件

// 局部定义组件
const YourComponent = {
  template: `
    <div>cart</div>
  `
}
export default YourComponent

动态组件

主要是keep-alive

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title></title>
  <script src="../../../vue.js"></script>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    #root {
      height: 100%;
    }
    html,body {
      height: 100%;
      overflow: hidden;
    }
    html {
      font-size: 100px;
    }
    body {
      font-size: 16px;
    }
    ul, li {
      list-style: none;
    }

    .container {
      height: 100%;
      display: flex;
      flex-direction: column;
    }

    main {
      flex: 1;
      overflow: hidden;
    }
    nav {
      height: .44rem;
      border-top: #eee solid 1px;
    }
    nav ul {
      height: 100%;
      display: flex;
    }
    nav ul li {
      flex: 1;
      text-align: center;
      line-height: .44rem;
    }
    li.active {
      background-color: #eee;
    }

    .home-tab {
      height: .44rem;
      display: flex;
      border-bottom: solid 1px #ccc;
    }

    .home-tab li {
      flex: 1;
      line-height: .44rem;
      text-align: center;
    }

    .list {
      height: 100%;
    }

    .main-box {
      height: 100%;
      display: flex;
      flex-direction: column;
    }

    .tab-box {
      overflow-y: scroll;
      flex: 1;
    }
  </style>
</head>
<body>
  <div id="root">
    <div class="container">
      <main>
        <keep-alive
          include="abc"
        >
          <component :is="currentComp"></component>
        </keep-alive>
      </main>
      <nav>
        <ul>
          <li
            v-for="tab in tabs"
            @click="handleClick(tab.component)"
            :class="{active: currentComp === tab.component}"
          >
            {{tab.title}}
          </li>
        </ul>
      </nav>
    </div>
  </div>
  <script type="module">
    Vue.config.productionTip = false

    const tab1 = {
      template: `
        <div class="list">
          童装列表<br />
          童装列表<br />  
          童装列表<br />  
          童装列表<br />  
          童装列表<br />  
          童装列表<br />  
          童装列表<br />  
          童装列表<br />  
          童装列表<br />  
          童装列表<br />  
          童装列表<br />  
          童装列表<br />
          童装列表<br />  
          童装列表<br />  
          童装列表<br />  
          童装列表<br />  
          童装列表<br />  
          童装列表<br />  
          童装列表<br />  
          童装列表<br />  
          童装列表<br />  
          童装列表<br />  
          童装列表<br />  
          童装列表<br />
          童装列表<br />  
          童装列表<br />  
          童装列表<br />  
          童装列表<br />  
          童装列表<br />  
          童装列表<br />  
          童装列表<br />  
          童装列表<br />  
          童装列表<br />  
          童装列表<br />  
          童装列表<br />
          童装列表<br />  
          童装列表<br />  
          童装列表<br />  
          童装列表<br />  
          童装列表<br />  
          童装列表<br />  
          童装列表<br />  
          童装列表<br />  
          童装列表<br />  
          童装列表2<br />  
        </div>
      `
    }

    const tab2 = {
      template: `
        <div>女装列表</div>
      `
    }

    Vue.component('m-home', {
      data() {
        return {
          tabs: [
            {
              id: '001',
              title: '童装',
              component: 'tab1'
            },
            {
              id: '002',
              title: '女装',
              component: 'tab2'
            }
          ],

          currentComp: 'tab1'
        }
      },

      components: {
        tab1,
        tab2
      },

      template: `
        <div class="main-box">
          <ul class="home-tab">
            <li
              v-for="tab in tabs"
              @click="handleClick(tab.component)"
              :class="{active: tab.component === currentComp}"
            >
              {{tab.title}}
            </li>
          </ul>  
          <div class="tab-box">
            <component :is="currentComp"></component>
          </div>
        </div>
      `,

      destroyed() {
        console.log('home')
      },

      methods: {
        handleClick(comp) {
          this.currentComp = comp
        }
      },
    })

    Vue.component('m-category', {
      name: 'abc',
      template: `
        <div class="main-box">category</div>
      `,
      destroyed() {
        console.log('m-category')
      },
      // mounted() {
      //   console.log(100)
      // },
      activated() {
        console.log(200)
      },
      deactivated() {
        console.log(300)
      },
    })

    Vue.component('m-profile', {
      template: `
        <div class="main-box">profile</div>
      `,
      destroyed() {
        console.log('m-profile')
      },
      mounted() {
        console.log(100)
      },
    })

    var vm = new Vue({
      el: '#root',
      data: {
        currentComp: 'm-home',
        tabs: [
          {
            id: '001',
            title: '首页',
            component: 'm-home'
          },
          {
            id: '002',
            title: '分类',
            component: 'm-category'
          },
          {
            id: '003',
            title: '我的',
            component: 'm-profile'
          }
        ]
      },

      computed: {
        
      },

      methods: {
        handleClick(comp) {
          this.currentComp = comp
        }
      },
    })
  </script>
</body>
</html>

vue2的一些边缘问题

r o o t 类 似 , root 类似, rootparent property 可以用来从一个子组件访问父组件的实例。它提供了一种机会,可以在后期随时触达父级组件,以替代将数据以 prop 的方式传入子组件的方式
尽管存在 prop 和事件,有的时候你仍可能需要在 JavaScript 里直接访问一个子组件。为了达到这个目的,你可以通过 ref 这个 attribute 为子组件赋予一个 ID 引用

bus总线

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title></title>
  <script src="../../vue.js"></script>
</head>
<body>
  <script type="text/x-template" id="hello-world-template">
    <p>Hello hello hello {{title}}</p>
  </script>
  <div id="root">
    <child ref="child"></child>
    <test inline-template>
      <div>
        {{title}}
      </div>
    </test>
    <test2></test2>
    {{xx}}
  </div>
  <script type="module">
    Vue.config.productionTip = false
    import bus from './bus.js'

    const grandson = {
      inject: ['x', 'setX'],

      template: `
        <div>
          <h1>grandson {{x}}</h1>
          <h3>{{message}}</h3>
        </div>
      `,
      components: {

      },
      data() {
        return {
          bus,
          message: 100
        }
      },
      mounted() {
        // this.$root.x = 200
        // console.log(this.$parent.y)
        // this.x = 5000
        // this.setX(5000)
        // console.log(bus.x)
        // bus.$emit('setx', 'world')
        // this.$forceUpdate()
        bus.$on('changeMessage', (msg) => {
          this.message = msg
        })
      },
    }

    const child = {
      inject: ['x'],
      template: `
        <div>
          <h1>child</h1>
          <grandson></grandson>
          {{bus.x}}
          {{x}}
        </div>
      `,
      components: {
        grandson
      },
      data() {
        return {
          y: 1000,
          bus
        }
      },
      mounted() {
        bus.$emit('changeMessage', 999)
      },
    }

    const test = {
      data() {
        return {
          title: 'line'
        }
      }
    }

    const test2 = {
      template: '#hello-world-template',
      data() {
        return {
          title: 'line 2'
        }
      }
    }

    var vm = new Vue({
      el: '#root',
      components: {
        child,
        test,
        test2
      },
      data: {
        xx: 100
      },
      mounted() {
        console.log(this.$refs['child'].y)
      },

      provide: {
        x: 3000,
        setX(x) {
          // console.log(this)
          // this.x = x
        }
      }
    })
  </script>
</body>
</html>

slot

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>slots</title>
  <script src="../../vue.js"></script>
</head>
<body>
  <div id="root">
    <child>
      <template
        #default="{string, url}"
      >
        <div slot="div1">{{url}}</div>
      </template>
      <template
        #div2="{url}"
      >
        <div slot="div2">{{url}}</div>
      </template>
      <!-- <div slot="div2">hello slot</div>
      <div>{{string}}</div>
      <div>{{string}}</div>
      <div>{{string}}</div> -->
    </child>
  </div>
  <script type="module">
    Vue.config.productionTip = false

    const Child = {
      template: `
        <div>
          <h1>child slot</h1>
          <h2>
            <slot name="div1" :string="string"></slot>
          </h2>
          <h3>
            <slot name="div2" url="abc.com"></slot>
          </h3>
          <h4>
            <slot :string="string" url="http://www.baidu.com">
              hello vue  
            </slot>
          </h4>
        </div>
      `,
      data() {
        return {
          string: 'hello child div'
        }
      }
    }

    var vm = new Vue({
      el: '#root',
      components: {
        child: Child
      },
      data: {
        string: 'hello div~'
      }
    })
  </script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title></title>
  <script src="../../vue.js"></script>
</head>
<body>
  <div id="root">
    <my-header
      :msg="msg"
    >
      <template #default="{title}">
        <h1>{{title}}</h1>
      </template>
    </my-header>
  </div>
  <script type="module">
    Vue.config.productionTip = false

    const Header = {
      props: {
        msg: {
          type: Object
        }
      },
      template: `
        <div>
          <slot :title="msg.title"></slot>  
        </div>
      `
    }

    var vm = new Vue({
      el: '#root',
      components: {
        'my-header': Header
      },
      data: {
        msg: {
          title: 'abc',
          content: 'aaabbbcc'
        }
      }
    })
  </script>
</body>
</html>

组件递归

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title></title>
  <script src="../../vue.js"></script>
</head>
<body>
  <div id="root">
    <tree-folder :folder="folder"></tree-folder>
  </div>
  <script type="module">
    Vue.config.productionTip = false

    Vue.component('tree-folder', {
      props: ['folder'],
      template: `
        <p>
          <span>{{ folder.name }}</span>
          <tree-folder-contents :children="folder.children"/>
        </p>
      `
    })

    Vue.component('tree-folder-contents', {
      props: ['children'],
      template: `
        <ul>
          <li v-for="child in children">
            <tree-folder v-if="child.children" :folder="child"/>
            <span v-else>{{ child.name }}</span>
          </li>
        </ul>
      `
    })

    var vm = new Vue({
      el: '#root',
      data: {
        folder: {
          name: 'folder1',
          children: {
            folder: {
              name: 'folder1-1',
              children: {
                folder: {
                  name: 'folder1-1-1'
                },
                folder2: {
                  name: 'folder1-1-2'
                }
              }
            },
            folder2: {
              name: 'folder2-1',
              children: {
                folder: {
                  name: 'folder2-1-1'
                },
                folder2: {
                  name: 'folder2-1-2'
                }
              }
            }
          }
        }
      }
    })
  </script>
</body>
</html>

混入(minxin)vue3已经去除

内部的data定义的数据优先级高于minxin的优先级

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>mixin</title>
  <script src="../vue.js"></script>
</head>
<body>
  <div id="root">
    <child></child>
    <h2>{{title}}</h2>
    <button @click="handleClick('haha')">click</button>
  </div>
  <script type="module">
    Vue.config.productionTip = false

    // Vue.mixin({
    //   data() {
    //     return {
    //       title: 'BALABALA.....'
    //     }
    //   },
    //   methods: {
    //     handleClick(title) {
    //       this.title = title
    //     }
    //   },
    //   mounted() {
    //     console.log('100')
    //   },
    // })

    // 局部混入
    const mixins = {
      data() {
        return {
          title: 'BALABALA.....'
        }
      },
      methods: {
        handleClick(title) {
          this.title = title
        }
      },
      mounted() {
        console.log('100')
      },
    }

    const child = {
      mixins: [mixins],
      data() {
        return {
          // title: 'hello'
        }
      },
      template: `
        <div>
          <h1>{{title}}</h1>  
          <button @click="handleClick('world')">click</button>
          <button @click="handleSubmit">submit</button>
        </div>
      `,
      methods: {
        handleSubmit() {
          console.log(100)
        }
      },
      mounted() {
        console.log('200')
      },
    }

    var vm = new Vue({
      mixins: [mixins],
      el: '#root',
      components: {
        child
      },
      data: {
        // title: 'hi'
      }
    })
  </script>
</body>
</html>
相关标签: vue