Vue 3.x setup函数的特性

110 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第18天,点击查看活动详情

setup函数的特性

setup中不能使用this,this指向undefined,在beforeCreate之前执行

setup函数在beforeCreate和created之前执行

setup函数执行于beforeCreate和created之前,也就是说setup函数里面无法使用data和methods方法中的数据。执行顺序如下:

代码如下:

<script>
export default {
  name: "App",
  beforeCreate() {
    console.log("beforeVreate执行");
  },
  created() {
    console.log("created执行");
  },
  setup() {
    console.log("setup执行");
  },
};
</script>

在setup函数中定义的变量和方法需要return出去,不然无法在模板中使用

setup中最后适用一个return语句才能使用setup函数中定义的变量和方法,不适用return不会报error,但是无法获得想要获得的变量或者方法,如下图所示,分别是无return和有return语句的示意图:

代码如下:

<script>
import { ref } from "vue"
export default {
	name: "App",
	setup() {
		const name = ref("张三")
		console.log("setup执行")
		return {
			name,
		}
	},
}
</script>

setup函数是Composition API的入口

参考:你真的会使用Vue3吗

**Options API 和 Composition API **

Vue3.0 所采用的 Composition Api 与 Vue2.x 使用的 Options Api 是有所不同的,可以说composition API是vue3.0的一大特点,它不会像 Options API一样,约定了该在哪个位置做什么事,比如说需要在data里面设置变量,在watch里面设置监听属性、在methods里面设置事件方法等,这在一定程度上强制了我们进行代码分割。Composition API就没有这样的约定,代码组织很灵活,代码直接全部都写在setup里面即可。

Options API:

  • props 里面设置接收参数

  • data 里面设置变量

  • computed 里面设置计算属性

  • watch 里面设置监听属性

  • methods 里面设置事件方法

Options APi 约定了我们该在哪个位置做什么事,这反倒在一定程度上也强制我们进行了代码分割。

Composition API:

现在用 Composition API,控制代码写在 setup 里面即可。

setup函数提供了两个参数* props context*,重要的是在 setup 函数里没有了 this,在 vue3.0 中,访问他们变成以下形式: this.xxx => context.xxx

小结:

使用 Composition API 的核心在于将变量和方法抽取到一个模块中,降低代码耦合,提高代码复用率,哪里需要使用在哪里导入即可。可见前文参考中的说明。

期待的代码格式如下:

<script>
import UserA from './A'
import UserB from './B'

export default {
	setup() {
		// 定义方法
		const {A,methodA} = UserA()
		const {B,methodB} = UserB()
		console.log("setup执行")
		return {
			A,
			methodA,
			B,
			methodB,
		}
	},
}
</script>

setup函数定义变量

reactive

Reactive函数接受一个普通对象,返回该对象的响应式代理。reactive定义的变量直接像往常一样取值改值就好,reactive用于定义复杂数据类型,比如数组、对象等,不可用于定义简单的数据类型比如整数类型、布尔类型等类型。

代码如下:

<script>
import { reactive } from "vue";
export default {
  setup() {
    // 1. setup需要返回值, setup中返回的值才能在模板中使用
    // 2. reactive中传入一个普通对象,返回一个代理对象
    // 3. 普通对象没有响应式,需要reactive
    const car = reactive({
      brand: '宝马',
      price: 100
    })
    console.log(car);
    return {
      car
    };
  },
};
</script>

输出结果如下:

ref

ref 函数接受一个简单类型的值,返回一个可改变的 ref 对象。返回的对象有唯一的属性 value在 setup 函数中,通过 ref 对象的 value 属性可以访问到值在模板中,ref 属性会自动解套,不需要额外的 .value,如果 ref 接受的是一个对象,会自动调用 reactive

代码如下:

<script>
import { ref } from "vue";
export default {
  name: "App",
  setup() {
    const name = ref("张三");
    console.log("setup执行");
    console.log("name.value --> " + name.value);
    console.log(name);
    return {
      name,
    };
  },
};
</script>

输出如下:

toRefs

toRefs 用于将响应式对象转换为结果对象,其中结果对象的每个属性都是指向原始对象相应属性的ref,reactive的响应式功能是赋予给对象的,但是如果给对象解构或者展开的时候,会让数据丢失响应式的能力。使用toRefs可以保证该对象展开的每一个属性都是响应式的。

示例代码:

<script>
import { ref, reactive, toRefs } from "vue";
export default {
  setup() {
    const state = {
      money: 100,
      car: {
        brand: "宝马",
        price: 1000000,
      },
      name: "zs",
    };
    console.log(state);
    const newState = toRefs(state);
    setTimeout(() => {
      state.money = 200;
      console.log(state, newState);
    }, 2000);

    return {
      state,
      ...newState,
    };
  },
};
</script>

结果如下,state中的money由100变成200了,但界面渲染中(视图)的money=100是不变的:

小结:

1、ref是对元数据的拷贝,修改响应式数据时不会影响之前的数据,视图会更新

2、toRef和toRefs是对元数据的引用,修改响应式数据时,元数据也会改变,但是视图不会更新,toRef修改的是对象的某个属性,toRefs修改的是整个对象

3、toRefs的使用场景:如果想让响应式数据和原来的数据关联起来同步更新,并且不更新视图,那么就可以使用toRefs

Vue2.0 --> Vue3.0 的 script 结构变化

参考:你真的会使用Vue3吗

vue2.0的script结构

<script>
// 引入组件login、top等

export default {
	name: "main",
	// 注册组件
	components: {
		// login,
		// top,
		// index,
	},
	beforeCreate(){},
	created() {
},
	// ...
	data() {
		return {
			// 定义变量
		}
	},
	methods: {
		// 定义方法
		},
	},
}
</script>

vue3.0的script结构,使用setup

错误示例如下,这种方式并没有很好地使用组合式API(Composition API),使用组合式API是为了减小耦合,提高组件的复用,这种方式并没有体现组件的复用,严格意义上不算组合式API的使用。

<script>
export default {
  setup() {
    const A = ref('')
    const methodsA = ()=>{
        // todo
    }
    const B = ref('')
    const methodsB = ()=>{
        // todo
    }
    const C = ref('')
    const methodsC = ()=>{
        // todo
    }
  },
  return: {
		A,
		methodsA,
		B,
		methodsB,
		C,
		methodsC,
	},
};
</script>

正确使用组合式API的简单示例如下,将A和methodA提取到一个模块中,使用时导入即可,降低了耦合程度,同时提高了模块的复用率,哪里需要用到直接导入即可,不需要反复编写重复代码。

<script>
import userA from "./mudoleA"
import userB from "./mudoleB"
import userC from "./mudoleC"
export default {
	name: "app",
	// 注册组件
	components: {
		// login,
		// top,
		// index,
	},
	setup() {
		const { A, methodsA } = userA()
		const { B, methodsB } = userB()
        const { C, methodsC } = userC()
	},
	return: {
		A,
		methodsA,
		B,
		methodsB,
		C,
		methodsC,
	},
}
</script>

vue3.0的setup语法糖形式

这种形式是官方推荐使用的形式,使用这种形式就不用显示的导入并注册组件,比如HelloWorld等,导入即自动注册;也不用显示的导出组件,比如App这个组件,自动导出。同时也不需要使用return语句返回方法和变量,可以直接使用定义的方法和变量。

<script setup>
// vue3.0之后,使用<script setup>这个语法糖,就不用显示的导入并注册组件,比如HelloWorld等,导入即自动注册;也不用显示的导出组件,比如App这个组件,自动导出
import HelloWorld from "./components/HelloWorld.vue";

const props = defineProps({
	title:{
		type: String,
		default: ()=>{ return '测试信息'}
	}
})
const { A, methodsA } = userA()
const { B, methodsB } = userB()
const { C, methodsC } = userC()
</script>

参考

参考:vue3.0——setup的使用

参考:vue3.0中setup的使用