Vue.js 3.0的变化

新特性

  • teleport组件
    Vue鼓励我们将UI和相关的业务逻辑封装成一个组件,使组件可以嵌套在另一个组件内部,以构建一个组合应用程序。然而,,有些组件template模块的一部分逻辑不属于该组件,从技术角度来看,最好将这部分逻辑从该组件“移动”到其他位置,但又不能拆分组件。
<template>
  <header>
    <img alt="Vue logo" class="logo" src="@/assets/logo.svg" width="125" height="125" />

    <div class="wrapper">
      <HelloWorld msg="You did it!" >
        <template v-slot:demo>
          <div class="inner">这里是插槽内容</div>
        </template>
      </HelloWorld>
      <!-- <el-button type="success">Success</el-button> -->
      <nav>
        <RouterLink to="/">Home</RouterLink>
        <RouterLink to="/about">About</RouterLink>
      </nav>
    </div>
  </header>

  <RouterView />
</template>

Vue.js 3.0的变化_第1张图片

我们知道Vue项目中所有的.vue文件渲染的dom元素并不是挂载到标签下,而是挂载到

元素中的。组件提供一种“传送”的方法,允许将指定的dom元素移动到某个父节点下渲染,而不必使用全局状态或拆分为两个组件。

<template>
  <header>
    <teleport to="body">
      <img alt="Vue logo" class="logo" src="@/assets/logo.svg" width="125" height="125" />
    </teleport>


    <div class="wrapper">
      <HelloWorld msg="You did it!">
        <template v-slot:demo>
          <div class="inner">这里是插槽内容</div>
        </template>
      </HelloWorld>
      <!-- <el-button type="success">Success</el-button> -->
      <nav>
        <RouterLink to="/">Home</RouterLink>
        <RouterLink to="/about">About</RouterLink>
      </nav>
    </div>
  </header>

  <RouterView />
</template>

Vue.js 3.0的变化_第2张图片
组件的to属性不但可以将html元素作为渲染元素,还可以指定id元素。

  • 组合式API
    组合式API是指将页面中可复用性的业务逻辑抽离,通过组合形式引入Vue.js组件中使用。仅此一项新特性,就可以使项目在可维护性和灵活性方面更加优越,尤其是当项目大到几百个组件时,共享和复用代码变得尤其重要。

    1. setup组件选项
    <!-- 父组件 -->
    <template>
      <header>
        <div class="wrapper">
          <HelloWorld title="标题">
      </header>
    
    </template>
    
    <!-- HelloWorld组件 -->
    <script lang="ts">
    import { computed, getCurrentInstance, reactive, ref, toRefs, watch, watchEffect } from 'vue'
    
    // defineProps<{
    //   msg: string
    // }>()
    
    
    export default {
      name: 'HelloWorld',
      data() {
        return {
          msg: "Vue"
        }
    
      },
      props: {
        title: String
      },
    
      setup(props, ctx) {
        console.log(" ~ file: HelloWorld.vue:22 ~ setup ~ ctx:", ctx)
        console.log(" ~ file: HelloWorld.vue:22 ~ setup ~ props:", props)
        
    
        let expression = ref(false)
        setTimeout(() => {
          expression.value = true
        }, 1000)
        return { expression }
      },
    }
    
    </script>
    

    Vue.js 3.0的变化_第3张图片
    Vue2中可以使用this直接获取props对象的属性,如this.title。Vue3并没有this对象,因此无法和Vue2一样使用this获取title,但setup函数在初始化时注入了props对象,因此在初始化时,可在setup函数内通过props.title获取对象的属性数据。
    setup函数内部的this不是该实例的引用,因为setup函数是在解析其他组件选项之前被调用的,所以setup函数内部的this指向与其他选项的this完全不同,因此不能在setup函数中使用this

  • 触发组件选项
    emits选项是setup函数的第二个参数,用于回调父组件的自定义方法或同步父组件的数据。

    1. 自定义事件
      与props一样,emit提供了事件名大小写自动转换功能。如果用驼峰命名的子组件触发事件,那么可在父组件添加一个@my-event,(以短横线分隔命名)的监听器。
    <!-- 父组件 -->
    <script lang="ts">
    import { RouterLink, RouterView } from 'vue-router'
    import HelloWorld from './components/HelloWorld.vue'
    import { ref } from 'vue';
    
    export default {
      setup(props, ctx) {
        const color = ref("red")
    
       const title = ref("原始title")
    
       let test=()=>{
        console.log(" ~ file: App.vue:15 ~ test ~ test:")
    
       }
    
        return { color,title,test }
      },
    }
    
    </script>
    
    <template>
      <header>
        <div class="wrapper">
          <HelloWorld v-model:title="title" @myClick="test">
            <template v-slot:demo>
              <div class="inner">这里是插槽内容</div>
            </template>
          </HelloWorld>
        </div>
      </header>
    
      <RouterView />
    </template>
    
    <!-- HelloWorld -->
    <script lang="ts">
    import { computed, getCurrentInstance, reactive, ref, toRefs, watch, watchEffect } from 'vue'
    export default {
      name: 'HelloWorld',
      data() {
        return {
          msg: "Vue"
        }
    
      },
      props: {
        title: String
      },
    
      emits:["update:title","myClick"],
      setup(props, ctx) {
        console.log(" ~ file: HelloWorld.vue:22 ~ setup ~ ctx:", ctx)
        console.log(" ~ file: HelloWorld.vue:22 ~ setup ~ props:", props)
        
        
    
        let expression = ref(false)
        setTimeout(() => {
          expression.value = true
          ctx.emit("update:title","test emits")
          ctx.emit("myClick")
        }, 1000)
        return { expression }
      },
    }
    </script>
    

    1s后HelloWorld组件便会调用myClick方法,从而回调父组件的test方法。

    1. 验证抛出的事件
      在emits对象语法中,property的值可以为null或验证函数。验证函数会接收传递给$emit调用的参数。验证函数应返回布尔值 ,以表示事件参数是否有效。
    <script lang="ts">
    import { computed, getCurrentInstance, reactive, ref, toRefs, watch, watchEffect } from 'vue'
    
    export default {
      name: 'HelloWorld',
      data() {
        return {
          msg: "Vue"
        }
    
      },
      props: {
        title: String
      },
      emits:{
        myClick:(a: any) => {
          console.log(" ~ file: HelloWorld.vue:24 ~ a:", a)
          return true
        }
      },
    
      setup(props, ctx) {
        let expression = ref(false)
        setTimeout(() => {
          expression.value = true
          // ctx.emit("update:title","test emits")
          ctx.emit("myClick",1)
        }, 1000)
        return { expression }
      },
    }
    
    </script>
    

    Vue.js 3.0的变化_第4张图片
    如果myClick函数返回false,那么控制台上输出的也是同样的结果,只不过会有一段警告信息。

    1. v-model指令
      在默认情况下,父组件的v-model指令使用modelValue作为props参数,并使用update:modelValue触发事件。可以通过向v-model传递参数来同步父组件的数据。
    <!-- 父组件 -->
    <script lang="ts">
    import { RouterLink, RouterView } from 'vue-router'
    import HelloWorld from './components/HelloWorld.vue'
    import { ref } from 'vue';
    
    export default {
      setup(props, ctx) {
        const color = ref("red")
    
       const title = ref("原始title")
    
        return { color,title }
      },
    }
    
    </script>
    <template>
      <header>
        <teleport to="body">
          <img alt="Vue logo" class="logo" src="@/assets/logo.svg" width="125" height="125" />
        </teleport>
        <div class="wrapper">
          <HelloWorld v-model:title="title">
            <template v-slot:demo>
              <div class="inner">这里是插槽内容</div>
            </template>
          </HelloWorld>
        </div>
      </header>
    </template>
    
    <!-- HelloWorld组件 -->
    <script lang="ts">
    import { computed, getCurrentInstance, reactive, ref, toRefs, watch, watchEffect } from 'vue'
    export default {
      name: 'HelloWorld',
      data() {
        return {
          msg: "Vue"
        }
    
      },
      props: {
        title: String
      },
    
      emits:["update:title"],
      setup(props, ctx) {
        console.log(" ~ file: HelloWorld.vue:22 ~ setup ~ ctx:", ctx)
        console.log(" ~ file: HelloWorld.vue:22 ~ setup ~ props:", props)
        
        let expression = ref(false)
        setTimeout(() => {
          expression.value = true
          ctx.emit("update:title","test emits")
        }, 1000)
        return { expression }
      },
    }
    </script>
    <template>
      <div class="greetings">
        <p>{{title}}</p>
      </div>
    </template>
    

    一开始title显示“原始title”,1s后便更新为"test emits"。

  • 单文件组件组合式API

你可能感兴趣的:(前端,前端,vue.js)