Vue2 Vue3对比

先上一个Vue3组件实例

<div id="root">
    {{counter}}
  </div>
<script type="module">
 const Counter = {
      data() {
        return {
          counter: 0
        }
      }
    }
    const app = Vue.createApp(Counter)
    app.mount('#root')
  </script>

组件Counter挂载在根组件root节点上,你发现了什么?
根组件的data也变成了一个函数,通过return 返回一个变量定义状态值,vue2根组件是一个对象;vue3通过暴露createApp方法,便于我们创建根组件
接着往下看:

const TodoItem = {
      props: ['todo'],
      template: `
        <li>{{todo.text}}</li>
      `
    }
    const TodoList = {
      data() {
        return {
          list: [
            {id: 0, text: 'html'},
            {id: 1, text: 'javascript'},
            {id: 3, text: 'css'}
          ]
        }
      },
      components: {
        TodoItem
      }
    }
    Vue.createApp(TodoList).mount('#root')
    app.mount('#root')

在Vue3实例化后的根组件对象比vue2更简洁了,vue2是一个Vue对象,Vue3是一个object对象 准确的来说应该是一个proxy
vue2对象实例:

在这里插入图片描述
Vue3对象
在这里插入图片描述

应用和组件实例

每个 Vue 应用都是通过用 createApp 函数创建一个新的应用实例开始的:

const app = Vue.createApp({
  /* 选项 */
})

该应用实例是用来在应用中注册“全局”组件的。

const app = Vue.createApp({})
//注册组件
app.component('SearchInput', SearchInputComponent)
//自定义指令
app.directive('focus', FocusDirective)
//使用插件
app.use(LocalePlugin)

应用实例暴露的大多数方法都会返回该同一实例,允许链式:

Vue.createApp({})
  .component('SearchInput', SearchInputComponent)
  .directive('focus', FocusDirective)
  .use(LocalePlugin)

Vue3中组件的使用:

<script>
    const TodoItem = {
      props: ['todo'],
      template: `
        <li>{{todo.text}}</li>
      `
    }
    const TodoList = {
      data() {
        return {
          list: [
            {id: 0, text: 'html'},
            {id: 1, text: 'javascript'},
            {id: 3, text: 'css'}
          ]
        }
      },
      //可以通过this.$options.components获取到子组件
      components: {
        TodoItem
      },
      mounted(){
       console.log(this.$options.components)
      }
    }
Vue.createApp(TodoList).mount('#root')
</script>

三、Vue3中插件封装和自定义指令

index.html

 <div id="app">
    <my-component></my-component>
    <input type="text" v-focus />
  </div>
  <script type="module">
    import i18nPlugin from './i18n.js'
    const app = Vue.createApp({
      mounted() {
     console.log(this.$translate('greetings.hello'))
      }
    })
    // 全局定义的组件
    app.component('my-component', {
      template: `
        <h1>自定义全局组件</h1>
      `
    })
    // 自定义指令(全局)
    app.directive('focus', {
      mounted(el) {
        el.focus() 
      }
    })
    // 使用插件
    const i18nString = {
      greetings: {
        hello: '你好'
      },
      oparator: {
        open: '打开',
        close: '关闭'
      }
    }
    app.use(i18nPlugin, i18nString)
    app.mount('#app')
  </script>

i18n.js

export default {
  install: (app, options) => {
    // 这里options是app中 i18nString 
    // 挂载一个全局属性到 app.config.globalProperties
    // key是$translate传进来的 greetings.hello 这个参数
    app.config.globalProperties.$translate = key => {
      return key.split('.').reduce((o, i) => {
        if (o) {
          return o[i]
        }
      }, options)
    }
    // app.component()
    // app.directive()
  }
}

生命周期对比
图一:

在这里插入图片描述
图二:
在这里插入图片描述
beforeUnmount、unmouted 是 Vue3 调整的钩子。并且通过 app.unmount() 函数触发组件销毁。
v-for/v-if的区别
Vue2中v-for 优先级高于v-if Vue3中v-if优先级高于v-for,在Vue3中v-for遍历的对象可以通过ref绑定函数,将每个处理一遍,vue2无法处理
vue3示例:

<div id="root">
    <ul v-if="!list2">
      <!-- <li v-for="li in lists" v-if="li!=='🥕'">{{ li }}</li> -->
      <li v-for="li in lists" :ref="setItemRef">{{ li }}</li>
    </ul>
    <my-component v-for="i in 3">{{i}}</my-component>
  </div>
 
  <script>
    const app = Vue.createApp({
      data() {
        return {
          lists: ['🍒', '🍊', '🍇', '🥕'],
          refs: 'lists',
          itemRefs: []
        }
      },
      // vue3中这样的使用方法被刨除了通过const list2 = computed({get(){},set(){}})设置
      computed: {
        list2() {
          return this.lists.every(value => {
            return value !== '🥕'
          })
        }
      },
      methods: {
        setItemRef(el) {
          if (el) {
            this.itemRefs.push(el)
          }
        }
      },
      mounted() {
        // console.log(this.$refs.lists);
        console.log(this.itemRefs[0])
      },
    })
    app.component('my-component', {
      template: `
        <h1>my-component</h1>
      `
    })
    app.mount('#root')
    console.log(app)

Vue3中的多事件处理器

事件处理程序中可以有多个方法,这些方法由逗号运算符分隔:

<!-- 这两个 one()two() 将执行按钮点击事件 -->
<button @click="one($event), two($event)">
  Submit
</button>
// ...
methods: {
  one(event) {
    // 第一个事件处理器逻辑...
  },
  two(event) {
   // 第二个事件处理器逻辑...
  }
}

Vue3中的事件处理封装得更加简便

<div id="root">
    <input type="text" @keyup.13="handleClick">
  </div>
  <script>
    Vue.createApp({
      methods: {
        handleClick() {
          console.log('click.')
        }
      },
    }).mount('#root')
  </script>

vue3非 Prop 的 Attribute
一个非 prop 的 attribute 是指传向一个组件,但是该组件并没有相应 props 或 emits 定义的 attribute。常见的示例包括 class、style 和 id attribute。可以通过 attrs property 访问那些 attribute。
vue2中会将style,class等默认挂载到组件的根节点上,Vue3中通过 组件内设置 inheritAttrs: false,不会将这些挂载到组件的根节点上,但是可以通过this.$attrs获取

  <div id="root">
    <date-picker data-status="activated" class="a"></date-picker>
  </div>
  <script>
    const app = Vue.createApp({

    })
    app.component('date-picker', {
      inheritAttrs: false,
      template: `
        <div v-bind:class="$attrs.class">
          <input type="datetime-local" v-bind:class="$attrs.class"/>
        </div>
      `,
      created() {
        // console.log(this.$attrs.class)
      }
    })
    app.mount('#root')

vue3中的自定义事件,父组件给子组件权利修改父组件的值

<div id="root">
    {{counted}}
    <counter v-model:total="counted"></counter>
  </div>
  <script>
    const app = Vue.createApp({
      data() {
        return {
          counted: 0,
        }
      },
      updated(){
          console.log("fatherupdated",this.counted)
      }
    })

    app.component('counter', {
      //相当于父组件给子组件权利修改父组件的值,不破坏数据流的传递
      // v-model绑定total到父组件的counted,相当于给父组件发消息,让父组件去更新值
      props: ['total'],
      //自定义事件,根据父组件data变化响应式渲染,如果emits接收了浏览器默认事件,则浏览器默认事件不执行,这里把他理解为自定义事件
      emits: ['update:total'],
      data() {
        return {
          count: 0,
        }
      },
      updated(){
        console.log("sonupdated",this.count)
      },
      methods: {
        handleClick() {
          this.count++
          console.log("son")
          this.$emit('update:total', this.count)
        }
      },
      template: `
        <button @click="handleClick">click</button>
      `
    })
    app.mount('#root')
  </script>

Vue3中的插槽

匿名插槽
<template v-slot:default>    Default slot content   </template>
具名插槽
<template v-slot:footer>    Footer content    </template>
V-slot:可以用#代理
<template #footer>    Footer content    </template>

具名插槽接收参数

	 <todo-list #list="{ index, item }">
      <span>{{index}}</span> -
      <span>{{item}}</span>
    </todo-list>
	
	template: `
        <ul>
          <li v-for="(item, index) in items">
            <slot name="list" :item="item" :index="index"></slot>
          </li>
        </ul>
      `

provide-inject

	//父组件provide
	provide() {
        return {
          msg: Vue.computed(() => this.str)
        }
      },
    //子组件inject 接收
    app.component('TodoListStatistics', {
      inject: ['msg'],
      template: `
        <div>{{msg}} TodoListStatistics</div>
      `,
    })

异步组件defineAsyncComponent

 <div id="root">
    <suspense>
      <template #default>
        <async-example></async-example>
      </template>
      <template #fallback>
        <div>
          loading...
        </div>
      </template>
    </suspense>
  </div>
  <script>
    const { createApp, defineAsyncComponent } = Vue
    const app = createApp({})
    const AsyncComp = defineAsyncComponent(
      () => 
        new Promise((resolve, reject) => {
          setTimeout(() => {
            resolve({
              template: '<div>I am async!</div>'
            })
          }, 3000)
        })
    )
    app.component('async-example', AsyncComp)
    app.mount('#root')

Vue3抛出了$children,通过ref 获取组件

  <div id="root">
    <div>
      <my-button ref="btn">Change logo</my-button>
    </div>
  </div>
  <script>
    const app = Vue.createApp({
      mounted() {
        console.log(this.$refs.btn) // [VueComponent]
      }
    })
    app.component('my-button', {
      template: `
        <button><slot></slot></button>
      `
    })
    app.mount('#root')
  </script>

Vue3自定义指令

 <input type="range" min="0" max="500" v-model="pinPadding">
 <p v-pin:[direction]="pinPadding">text</p>

 const app = Vue.createApp({
      data() {
        return {
          pinPadding: 200,
          direction: 'right'
        }
      }
   })
 app.directive('pin', (el, binding) => {
      el.style.position = 'fixed'
      const s = binding.arg || 'top'
      el.style[s] = binding.value + 'px'
    })

自定义标签

<table>
   <tr is="vue:mytr"></tr>
</table>

app.component('mytr', {
    template: `
     <tr><td>abc</td></tr>
`
})
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值