vue3를 빠르게 시작하는 방법은 무엇인가요? 이 기사에서는 몇 가지 API를 공유할 것입니다. 이러한 API를 배우면 vue3을 직접 시작할 수 있습니다. 다른 API도 천천히 배워서 모든 사람에게 도움이 되기를 바랍니다.
vue2로 프로젝트를 개발한 분들은 vue3를 빨리 시작하고 싶으실 텐데요, 몇 가지 API만 알아도 충분합니다. API 사용법에 익숙해진 후 일부 API 원리를 연구하는 사람이라면 누구나 vue3을 천천히 마스터할 수 있을 것입니다.
그리고 vue3를 TS와 결합해서 사용하면 개발 과정에서 TS가 차지하는 비중은 그다지 크지 않습니다. 앞서 공유한 TS의 기본 사항만 알면 개발에 충분합니다. [관련 추천 : vuejs 영상 튜토리얼]
Global API and application API
vue3의 새로운 개념으로, 애플리케이션 컨텍스트를 제공하는 애플리케이션 인스턴스를 반환하고, 애플리케이션 인스턴스가 마운트한 전체 컴포넌트 트리는 애플리케이션 컨텍스트를 공유합니다. 같은 맥락 :
const app = createApp(App); app.use(store).use(router).mount("#app");
vue2:
new Vue({ router, store, render: (h) => h(App), }).$mount("#app");
그런 다음 Vue. .comComponent
app.config | |
---|---|
app.mixin | |
app.use | |
composition API | |
tips |
vue3을 사용하지 않습니다. 구성 요소는 그렇지 않습니다 루트 태그가 필요하지만 Extraneous non-props attribute
단일 파일 구성 요소를 사용하는 것이 좋습니다. 후속 구현 코드는 모두 단일 파일 구성 요소입니다setup
<template> <div class="hello"> <h1>{{ msg }}</h1> <h1 @click="test">{{ isRef }}</h1> </div> </template> <script lang="ts"> import { defineComponent, ref } from "vue"; export default defineComponent({ name: "HelloWorld", props: { msg: String, }, setup(props) { console.log(props.msg); let isRef = ref("is ref"); const test = () => { console.log(isRef.value); }; return { isRef, test, }; }, }); </script>
<template> <div class="hello"> <h1>{{ msg }}</h1> <h1 @click="test">{{ isRef }}</h1> </div> <MyComponent /> </template> <script lang="ts" setup> import MyComponent from './MyComponent.vue' import { ref } from "vue"; const msg = "msg"; const isRef = ref(""); function test() { console.log(isRef.value); } </script>단일 파일 구성 요소를 사용하면 일부 속성의 사용도 변경해야 합니다. 물론 다른 대체 API도 있습니다:
해당
ㅋㅋㅋ接受一个内部值并返回一个响应式且可变的 ref 对象,在setup函数内部访问ref函数需要加.value, 如果要加类型,要用泛型,不加则会类型推论,也可以不给初始值,则是any,且是undefined:
const ref1 = ref(1); const ref2 = ref<number>(2); const ref3 = ref1.value;//不是响应式,相当于变量 const ref4 = ref();//refs.value是undefined ref2.value = 5;//赋值 读取都要.value
一般来说,ref只会赋值基础数据类型和数组,也可以泛型联合类型 如果将对象分配为ref值,则它将被reactive函数处理为深层的响应式对象:
//不建议,内部也是reactive处理 const ref1 = ref({ a: 10, }); //不确定类型 const ref3 = ref<string | number>(); ref3.value = 1; ref3.value = ""; //数组对象,ts类型声明,用泛型 type Obj1 = { c: string }; type Obj2 = { b: string; c: Obj1[]; }; const ref2 = ref<Obj2[]>([ { b: "", c: [{ c: "" }], }, ]);
用来声明响应式的对象,类型通过泛型添加:
type Obj = { a: number; b: string; }; let obj = reactive<Obj>({ a: 10, b: "", }); let state = reactive({ a: 10, b: "", });
reactive将会解包所有深层的 refs,同时维持ref的响应性, 将ref分配给reactive的property时,ref也会被自动解包。 简单说就是ref的值和reactive的值响应式了
const count = ref(1) const obj = reactive({ count }) // ref 会被解包 console.log(obj.count === count.value) // true // 它会更新 `obj.count` count.value++ console.log(count.value) // 2 console.log(obj.count) // 2 // 它也会更新 `count` ref obj.count++ console.log(obj.count) // 3 console.log(count.value) // 3 //跟上面一样效果 const count = ref(1) const obj = reactive({}) obj.count = count console.log(obj.count) // 1 console.log(obj.count === count.value) // true
为源响应式对象上的某个property新创建一个ref,也就是reactive创建的才可以, 会保持对其源 property 的响应式连接:
const state = reactive({ foo: 1, bar: 2 }) const fooRef = toRef(state, 'foo') fooRef.value++ console.log(state.foo) // 2 state.foo++ console.log(fooRef.value) // 3
将响应式对象转换为普通对象,其中结果对象的每个property都是指向原始对象相应property的ref:
const state = reactive({ foo: 1, bar: 2 }) const stateAsRefs = toRefs(state) /* stateAsRefs 的类型: { foo: Ref<number>, bar: Ref<number> } */ // ref 和原始 property 已经“链接”起来了 state.foo++ console.log(stateAsRefs.foo.value) // 2 stateAsRefs.foo.value++ console.log(state.foo) // 3
toRef和toRefs在对一些响应式对象结构展开会很有用,可以有用的时候看看。
watch接收两个参数,第一个参数可以是有return的函数,也可以是一个ref, 第二个参数则跟vue2相同的函数,并且watch可以很多个:
//一般ref不用这种方式 let count = ref(0); watch( () => count.value, (val, old) => { console.log(old, val); } ); //单个ref推荐 watch(count, (val, old) => { console.log(old, val); }); //监听reactive对象 let state = reactive({ count: 0 }); //函数参数必须具体到某个值,如果是() => state无效,或者加上{ deep: true } watch( () => state.count, (val, old) => { console.log(old, val); } ); //加上{ deep: true } watch( () => state, (val, old) => { console.log(old, val); }, { deep: true } ); //监听整个对象,新旧的值都相同,或者用lodash.cloneDeep进行深拷贝 //state改成() => _.cloneDeep(state) watch(state, (val, old) => { console.log(old.count, val.count); });
也可以同时监听多个,两个参数分别用数组,个人还是建议单个:
const state = reactive({ count: 1 }); const count = ref(0); // 监听一个数组 watch( [() => state.count, count], ([newState, newCount], [oldState, oldCount]) => { console.log("new:", newState, newCount); console.log("old:", oldState, oldCount); } );
官网一直提到惰性,其实就是是否加immediate: true,加了初始化就会执行。
它"立即执行"传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数:
const state = reactive({ count: 1 }); const count = ref(0); watchEffect(() => { if (state.count > 3) { count.value++; } }); watchEffect(() => console.log(count.value));
至于watch和watchEffect共享停止侦听,清除副作用 (相应地 onInvalidate 会作为回调的第三个参数传入)、 副作用刷新时机和侦听器调试行为后面要仔细研究一下。
从vue2开始,就很多人分不清什么时候用computed什么时候用watch,computed主要是用来声明 有两个及以上的依赖的数据,也就是说一个变量是根据多个数据进行判断的,用computed,单个的用watch。 至于语法的不同就不多说了,vue3的computed常用语法是一个带有return的函数,也可以同时存在多个:
let count = ref(0); let page = ref(0); let pg = computed(() => { return count.value + page.value; });
要注意,computed声明的变量(pg)是不能直接去修改的(只读),跟vue2一样也有get、set函数(可读可写)。
在单文件组件中必须使用defineProps和defineEmits API来声明props和emits,可以算是语法糖。 父组件还是跟原来一样传值,子组件接收:
//父组件 <template> <div class="home"> <input v-model="msg" /> <HelloWorld :msg="msg" @change="change" /> </div> </template> <script lang="ts" setup> import { ref } from "vue"; import HelloWorld from "@/components/HelloWorld.vue"; let msg = ref("is parent"); const change = (val: string) => { msg.value = val; }; </script> //子组件 <template> <div>{{ msg }}</div> <button @click="change">emit</button> </template> <script lang="ts" setup> import { defineProps, defineEmits } from "vue"; const props = defineProps({ msg: String, }); console.log(props.msg); const emit = defineEmits(["change"]); const change = () => { emit("change", "is son"); }; </script> //设置默认值 defineProps({ msg: { type: Number, default: 100, }, });
template可以直接使用msg,要调用的话就得props.msg。
defineProps只能限制类型,没有提供默认值(这边应该是限定用ts的接口才没有默认值)。为了解决这个问题,提供了 withDefaults 编译器宏:
type Porps = { msg: string; }; const props = withDefaults(defineProps<Porps>(), { msg: "default", });
withDefaults接收两个参数,第一个参数是defineProps加props字段的泛型,第二个字段是默认值,也可以不设置。
也可以监听props:
watch( () => props.msg, (val) => { console.log(val); } );
vue2很多情况还是需要用到这个api,vue3中比较特别, 为了获得对模板内元素或组件实例的引用,我们可以像往常一样声明ref, 在渲染上下文中暴露root,并通过ref="root",将其绑定到 div 作为其 ref。 在虚拟DOM补丁算法中,如果 VNode 的 ref 键对应于渲染上下文中的 ref, 则VNode的相应元素或组件实例将被分配给该ref的值。 这是在虚拟 DOM 挂载/打补丁过程中执行的,因此模板引用只会在初始渲染之后获得赋值。
<button ref="testRef">testRef</button> let testRef = ref(null); onMounted(() => { // DOM 元素将在初始渲染后分配给 ref console.log(testRef.value); // <button>testRef</button> });
跟vue2一样的使用:
nextTick(() => { console.log(testRef.value); });
也可以跟官网提供的一样用async的函数await:
let testRef = ref(null); const nextTickFn = async () => { await nextTick(); console.log(testRef.value); }; nextTickFn();
vue2有时候会用this.$refs调用子组件的函数或者变量, 单文件组件是默认关闭的,所以单文件组件要用defineExpose编译器宏暴露出去:
//父组件 <template> <div class="home"> <HelloWorld ref="sonRef" /> </div> </template> <script lang="ts" setup> import { nextTick, ref } from "vue"; import HelloWorld from "@/components/HelloWorld.vue"; let sonRef = ref(); nextTick(() => { sonRef.value.sonFn(); console.log(sonRef.value.sonRef); }); </script> //子组件 let sonRef = ref("is son"); const sonFn = () => { console.log("is son fn"); }; defineExpose({ sonFn, sonRef });
vue2的this.$parent在单文件组件中,自己是实现了,但是官方没有直接给出代码:
//父组件 const parentRef = ref("is parent ref"); const parentFn = () => { console.log("is parent fn"); }; defineExpose({ parentRef, parentFn, }); //子组件 let parent = getCurrentInstance(); console.log(parent?.parent?.exposed?.parentRef.value); parent?.parent?.exposed?.parentFn();
新增组件
官网介绍了很多,这个组件最大的作用就是可以让组件脱离固定的组件位置,可以挂载在逻辑上最优的位置, 其它使用都跟组件一样,只有位置改变:
<teleport to="#teleportDiv"> <HelloWorld /> </teleport> <teleport to="body"> <HelloWorld /> </teleport>
挂载的元素会从上向下解析,第一个to的元素,标签、class、id等。一般使用也不会随便,都会用id元素或者body。
Suspense是一个试验性的新特性,官方也说生产环境请勿使用。 主要是允许将组件异步处理等待过程提升到组件树中处理。
单文件组件里面顶层await里面提到: async setup() 必须与 Suspense 组合使用,Suspense 目前还是处于实验阶段的特性。 我们打算在将来的某个发布版本中开发完成并提供文档。
所以这边就不给出不是单文件组件的代码实现了。
生命周期
生命周期还是跟原来的一样,只是前面都加上了on,destroy都变成了unmount。 setup会在beforeCreate、created之前执行,取代了beforeCreate、created。
使用:
onMounted(() => { console.log("mounted"); });
试了一下,居然可以写多个。
vue3新增或者删除了哪些API,其实没必要一下子全部去记住,当一些API使用的时候如果发现不生效了, 再去官网查一下,当然,基础的这些API就得记下来。
还是那句话,先学会基础,上手开发,然后慢慢去了解学习不常用的,甚至是源码。
위 내용은 vue3을 빠르게 시작하는 방법, 이 API를 배워보세요!의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!