VUE3的 单文件组件 <script setup>理解与实际上手案例

第一次使用VUE3时,项目中使用的时兼容VUE2引入setup函数的写法,上手很快也容易理解。
直到发现element plus官方的源码展示都用了全新的单文件组件写法,意识到这个才是主流。
这篇文章记录下学习过程。

理解:

类似VUE2写法与最原始HTML脚本的结合,将Vue2的写法export default {}的代码整体暴露出去 变成 手动调用API进行封装;

<script setup>是在单文件组件 (SFC) 中使用组合式 API的编译时语法糖。相比于普通的<script>语法,它具有更多优势
1.更简洁的代码
2.能够使用纯 Typescript 声明 props 和 抛出事件,<script setup lang="ts">
3.更好的运行时性能 (其模板会被编译成与其同一作用域的渲染函数,没有任何的中间代理)。
4.更好的 IDE 类型推导性能 (减少了语言服务器从代码中抽取类型的工作)。

<script setup>内的代码会被编译成组件 setup() 函数的内容。这意味着与普通的<script> 只在组件被首次引入的时候执行一次不同,script setup>中的代码会在每次组件实例被创建的时候执行。

HTML脚本

<p id="two">JavaScript 可以触发事件。</p>
<button type="button" onclick="twoFun()">点我</button>
<script>
    function twoFun()
    {
      
      
        document.getElementById("two").innerHTML="Hello JavaScript!";
    }
</script>

VUE2单文件组件

<template>
  <div>
	...
  </div>
</template>
<script>
import {
      
       AAAA } from '@/api/model'
export default {
      
      
    name:'',
    components: {
      
      },
    props: {
      
      },
    data(){
      
      return {
      
      }},
    computed: {
      
      },
    created (){
      
      },
	mounted (){
      
      },
    methods: {
      
      },
    watch:  {
      
      }
}
</script>

VUE3单文件组件

<script setup>
import {
      
       AAAA } from '@/api/model'
import {
      
       ref,reactive } from "vue";
const props = defineProps({
      
      
  detailData: Object
});
const showModel = ref(1)
const evaluate = reactive({
      
      A:'a'})
function myEvaluate() {
      
      
    showModel.value = 3
}
</script>
<template>
  <div>
	...
  </div>
</template>

案例

  • 当使用 <script setup> 的时候,任何在 <script setup> 声明的顶层的绑定 (包括变量,函数声明,以及 import 导入的内容) 都能在模板中直接使用
  • 与早期语法setup()函数导入类似,可以使用ref,reactive 响应式API来创建与模板双向绑定的数据。还可以引入watch,生命周期
  • 引入子组件时,无需像VUE2语法那样需要在components: {},函数中申明。
  • 使用 defineProps() 来引入父组件绑定的数据,类似VUE2的 props 对象。
    使用 defineEmits() 来引入父组件绑定的数据,类似VUE2的 this.$emit('父组件方法名', 参数组)写法
    都是只能在 <script setup> 中使用的编译器宏。他们不需要导入
  • Vue2中可直接全局调用的变量在Vite中会发生改变,例如process.env.VUE_APP_BASE_API变为 import.meta.env.VITE_APP_BASE_AP详情见vite官网
<script setup>
import DemandList from "@/components/DemandList.vue";//子组件
import {
    
     ref,reactive,computed,watch,watchEffect,onMounted } from "vue";//各种API
import {
    
    submitFeedbacEvaluate} from "@/http/index.js";//引入函数


onMounted(()=> {
    
    
//setup 是围绕beforeCreate和created生命周期钩子运行的,不需要显式地定义它们。在这些钩子中编写的任何代码都应该直接在 setup 函数中编写。
//生命周期基本都被重命名 首字母大写后加上on前缀  例如beforeUpdate => onBeforeUpdate
   console.log('onMounted')
})
const props = defineProps({
    
    
  detailData: Object//父组件绑定数据
});
const feedbackId = computed(()=>{
    
    
    return detailData.id
})
const emit = defineEmits(["closeDrawer"]);// 传递父组建内容
const showModel = ref(1)  //创建响应式基本类型数据
const evaluate = reactive({
    
     feedbackId:'',opinion:''})  //创建响应式引用类型数据

function toEvaluate() {
    
    
    if(props.detailData.feedbackEvaluateList.length>=5){
    
    
        ElNotification({
    
    
            title: "Error",
            message: "最多支持评价5次!",
            type: "error",
        });
        return;
    }
    showModel.value = 2
}
function myEvaluate() {
    
    showModel.value = 3}
function returnDetail() {
    
    showModel.value = 1}
watch(
  ()=>props.detailData,
  (newVal)=>{
    
    
    console.log('watch 已触发', newValue)
  }, 
{
    
     deep: true }),
watch(() => 
    router.currentRoute.value.path,
    (toPath:any) => {
    
    
      //要执行的方法
      const query = router.currentRoute.value.query;
},{
    
    immediate: true,deep: true})
watchEffect(()=> {
    
    
    console.log(props.detailData)//Vue3.0新增的一个监听属性的方法,可直接获取到每一次响应式数据的改变
})
function submitEvaluate() {
    
    
    evaluate.feedbackId = props.detailData.id //在模板中直接使用顶层暴露的数据与函数
    for(let key in evaluate){
    
    
        if(evaluate[key]==''){
    
    
            ElNotification({
    
    
                title: "Error",
                message: "必填内容未填写!",
                type: "error",
            });
            return;
        }
    }
    submitFeedbacEvaluate(evaluate).then((res) => {
    
    
        if(res.errCode=='00'){
    
    
            ElNotification({
    
    
                title: "Success",
                message: res.data,
                type: "success",
            });
            returnDetail();
      		handleClose();
        }
    });
}
function handleClose() {
    
    
  emit("closeDrawer");
}

</script>

<template>
  <div class="detail">
    <!-- 直接使用引入组件 直接使用顶层声明的函数与变量-->
  	<demand-list :id="detailData.id" v-if="detailData.id"/>
    <el-button @click="toEvaluate" type="primary"  v-if="detailData.feedbackEvaluateList.length==0">去评价</el-button>
    <el-button @click="myEvaluate" type="primary"  v-else>我的评价</el-button>
    <el-button @click="returnDetail" type="primary" >返回</el-button>
    <el-input clearable show-word-limit v-model="evaluate.opinion" :rows="3" type="textarea" maxlength="500"/>
    <el-button @click="submitEvaluate" type="primary">提交</el-button>
  </div>
</template>
  • 可以使用带 . 的组件标签,例如 <Foo.Bar> 来引用嵌套在对象属性中的组件。这在需要从单个文件中导入多个组件的时候非常有用:
    在这里插入图片描述

  • 使用动态组件的时候,应该使用动态的 :is 来绑定:

  • 如何写promise函数?
    <script setup> 中可以使用顶层 await。结果代码会被编译成 async setup();
    官网这句话可以简单理解为当语法糖代码中含有await时,编译时会自动变为async setup()。即省去了手动定义async函数的过程,其他与VUE2中promise函数的使用几无区别
    理解promise

<script setup>
const listData = await getData();//也可以将promise写为公告方法从外部引入使用
//JS代码仍是自上而下一步步执行 在这里会等待await执行完毕后继续向下

function getData() {
    
    
  return new promise((resolve,reject)=>{
    
    
	setTimeout(()=>{
    
    
		resolve('模拟异步调取接口')
	}2000)
  })
}

</script>

TS兼容写法

猜你喜欢

转载自blog.csdn.net/Beatingworldline/article/details/127614221
今日推荐