vue2.x的组件

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>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值