创建项目:
vite脚手架创建项目: vue3+vite2+ts
npm create vite@latest
一.页面组件结构
<template>
home
</template>
<!-- 在script标签上添加setup属性 -->
<script setup lang="ts">
</script>
<style scoped>
</style>
二. 页面属性方法
<template>
<h1>{{ name }}</h1>
<h1>{{ state.age }}</h1>
<h1>{{ sex }}</h1>
</template>
<script setup lang="ts"> import { reactive, ref, toRefs } from "vue";
// ref声明响应式数据,用于声明基本数据类型
const name = ref("王五");
// 修改 name 值要是用.value
name.value = "张三";
// reactive声明响应式数据,用于声明引用数据类型
const state = reactive({
age: 18,
sex: "男",
});
// 修改 state.age 值
state.age = 24;
// 使用toRefs解构template可直接使用{{name}}、{{sex}}
const { age, sex } = toRefs(state); </script>
<style scoped>
</style>
三.定义method
<template>
<h1>{{ age }}</h1>
<!-- 调用方法 -->
<button @click="handleClick"></button>
</template>
<script setup lang="ts"> import { reactive,toRefs } from "vue";
// reactive声明响应式数据,用于声明引用数据类型
const state = reactive({
age: 18,
sex: "男",
});
// 使用toRefs解构template可直接使用{{name}}、{{sex}}
const { age, sex } = toRefs(state);
// 声明点击事件
const handleClick = () => {
state.age++;
}
</script>
<style scoped>
</style>
四.computed (计算属性)
<template>
<h1>{{ count }}</h1>
<h1>{{doubleCount}}</h1>
<button @click="handleClick()">{{count}}</button>
</template>
<script setup lang="ts"> import { ref, computed } from 'vue'
// ref声明响应式数据,用于声明基本数据类型
const count = ref(11)
//computed 获取双倍 count 值
const doubleCount = computed(() => {
return count.value * 2
})
const handleClick = () => {
count.value++
} </script>
<style scoped>
</style>
五.父传子
parent.vue
<template>
<Child :msg="fmsg"></Child>
</template>
<script setup lang="ts"> // 引入子组件(组件自动注册)
import Child from './child.vue';
const fmsg = '父组件传递的值' </script>
<style scoped>
</style>
child.vue
<template>{{props.msg}}
<!-- 可省略props -->
<h1>{{ msg }}</h1>
</template>
<script setup lang="ts"> // defineProps 和 defineEmits 都是只能在 <script setup> 中使用的编译器宏。他们不需要导入,且会随着 <script setup> 的处理过程一同被编译掉。
// 声明props
const props = defineProps({
msg: {
type: String,
default: "",},
}); </script>
<style scoped>
</style>
六.子传父
parent.vue
<template>
<Child :msg="state.msg" @changeMag="changeMag"></Child>
</template>
<script setup lang="ts"> import { reactive } from 'vue'
// 引入子组件(组件自动注册)
import Child from './child.vue';
const state = reactive({
msg: '父组件原值'
})
const changeMag = (value: any) => {
state.msg = value
} </script>
<style scoped>
</style>
child.vue
<template>{{props.msg}}<!-- 可省略props --><h1>{{ msg }}</h1><!-- 调用子传父事件 --><button @click="handleClick">Click Me</button>
</template>
<script setup lang="ts"> // defineProps 和 defineEmits 都是只能在 <script setup> 中使用的编译器宏。他们不需要导入,且会随着 <script setup> 的处理过程一同被编译掉。
// 声明props
const props = defineProps({msg: {type: String,default: "",},
});
// 声明 emit
const emit = defineEmits(['changeMag'])
const handleClick = () => {emit('changeMag', '我是子组件传过来的值')
} </script>
<style scoped>
</style>
七.原型链绑定和组件使用
main.ts
// 创建vue实例
const app = createApp(App);
app.mount("#app");
// 获取原型
const prototype = app.config.globalProperties;
// 绑定参数
prototype.$name = "我是挂载在全局上的属性";
组件内使用
<template><!-- 方式1:在template模板中使用 -->{{$name}}
</template>
<script setup lang="ts"> import { getCurrentInstance } from "vue";
// 方式2:在setup中使用
// const cns = getCurrentInstance()
// console.log(cns.appContext.config.globalProperties.$name)
// 方式3:在setup中使用
const { proxy } = getCurrentInstance() as any
console.log(proxy.$name) </script>
<style scoped>
</style>
八.Vue3.x使用mitt.js进行组件通信
安装
npm install --save mitt
官网地址
九.v-model父子组件双向数据绑定
parent.vue
<template><div>父组件:</div><div>{{state.msg}}</div><input type="text" v-model="state.msg"><Child v-model:msg='state.msg' v-model:age="state.age" />
</template>
<script setup lang="ts"> import { reactive } from "vue";
// 引入子组件(组件自动注册)
import Child from "./child.vue";
const state = reactive({msg: "我是父组件原本的值",age: 11
}); </script>
<style scoped>
</style>
child.vue
<template><div>子组件:</div><input type="text" v-model="msg" @input="changeMsg"><!-- 可省略props --><h1>msg:{{ msg }}</h1>
</template>
<script setup lang="ts"> // 声明props
const props = defineProps({msg: {type: String,default: "",},age: {type: Number,default: 0,},
});
// 声明emit
const emit = defineEmits(["update:msg", "update:age"]);
const changeMsg = () => { console.log(props.msg);emit('update:msg',props.msg);
} </script>
<style scoped>
</style>
十.nextTick
parent.vue
<template><Child />
</template>
<script setup lang="ts"> import { nextTick } from "vue";
// 引入子组件(组件自动注册)
import Child from "./child.vue";
nextTick(() => {console.log('父组件调用了:nextTick');
})
nextTick(() => {console.log('父组件调用了:nextTick-1');
})
nextTick(() => {console.log('父组件调用了:nextTick-2');
}) </script>
<style scoped>
</style>
child.vue
<template>
</template>
<script setup lang="ts"> import { nextTick } from "vue";
nextTick(() => {console.log('子组调用了:nextTick');
})
nextTick(() => {console.log('子组调用了:nextTick-1');
})
nextTick(() => {console.log('子组调用了:nextTick-2');
}) </script>
<style scoped>
</style>
十一.插槽
parent.vue
<template><Child><!-- 匿名插槽 --><span>我是默认插槽</span><!-- 具名插槽 --><template #title><h1>我是具名插槽1</h1><h1>我是具名插槽2</h1><h1>我是具名插槽3</h1><span>1</span><span>2</span><span>3</span></template><!-- 作用域插槽 --><template #footer="{ scope }"><footer>作用域插槽——姓名:{{ scope.name }},年龄{{ scope.age }}</footer></template></Child>
</template>
<script setup lang="ts"> // 引入子组件(组件自动注册)
import Child from "./child.vue"; </script>
<style scoped>
</style>
child.vue
<template><!-- 匿名插槽 --><slot /><!-- 具名插槽 --><slot name='title' /><!-- 作用域插槽 --><slot name="footer" :scope="state" />
</template>
<script setup lang="ts"> import { reactive, useSlots } from "vue";
const state = reactive({name: '王五',age: 11
});
const slots = useSlots()
//判断<slot/>是否有传值
const slotDefault = !!useSlots().default;
//判断<slot name="test"/>是否有传值
const slotTest = !!useSlots().test;
// 匿名插槽使用情况,判断 <slot/>是否有传值
const defaultSlot = reactive(slots.default && slots.default().length)
console.log('defaultSlot', defaultSlot) // 1
// 具名插槽使用情况,判断 <slot name='title' />是否有传值
const titleSlot = reactive(slots.title && slots.title().length)
console.log('titleSlot', titleSlot) // 6 </script>
<style scoped>
</style>
十二.路由useRoute和useRouter
安装
npm install vue-router@4
// yarn add vue-router@4
新建router/index.ts
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router';
const routes: Array<RouteRecordRaw> = [{ path: '/',redirect: '/home'},{ path: '/home',name: 'home',component: () => import('../views/home/index.vue'),meta: {showFooter: true,requireAuth: false,}},{ path: '/about',name: 'about',component: () => import( '../views/about/index.vue'),meta: {showFooter: true,requireAuth: false,}},
];
const router = createRouter({history: createWebHashHistory(),routes,
});
export default router;
main.ts
//在将路由router注册
import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index'
const app=createApp(App)
app.use(router).mount('#app')
页面打印
//在页面打印结果
import { useRouter, useRoute } from "vue-router";
// 必须先声明调用
const router = useRouter();
const route = useRoute();
// 路由信息
console.log("router", router);
console.log("route",route);
十三.路由守卫
// 路由守卫
router.beforeEach((to, from, next) => {
console.log("to",to);
console.log("from",from);
next()
})
十四.生命周期
vue2和vue3对比
beforeCreate
-> 使用setup()
created
-> 使用setup()
beforeMount
->onBeforeMount
mounted
->onMounted
beforeUpdate
->onBeforeUpdate
updated
->onUpdated
beforeUnmount
->onBeforeUnmount
unmounted
->onUnmounted
errorCaptured
->onErrorCaptured
renderTracked
->onRenderTracked
renderTriggered
->onRenderTriggered
activated
->onActivated
deactivated
->onDeactivated
十五.Pinia
1:基础使用
安装
npm install pinia -S
main.ts 引入使用
import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index.ts'
// 引入pinia
import { createPinia } from 'pinia'
// 创建vue实例
const app=createApp(App)
// 创建 Pinia 实例
const pinia = createPinia()
// 注册挂载到vue实列
app.use(router).use(pinia).mount('#app')
创建 store/index.ts
import { defineStore } from "pinia";
export const useMainStore = defineStore("main", {state: () => {return {info: "hello, My Pinia",};},getters: {},actions: {},
});
组件内使用
<template><div> <h1>{{ mainStore.info}}</h1></div>
</template>
<script setup lang="ts"> import { useMainStore } from "../../store/index.ts";
const mainStore = useMainStore(); </script>
<style scoped>
</style>
2:访问state 中的数据
/store/index.ts
import { defineStore } from "pinia";
export const useMainStore = defineStore("main", {state: () => {return {info: "Hello, My Pinia",id:11,count:0,depId:6,userName: "admin"};},getters: {},actions: {},
});
组件内使用
<template><h1>{{ mainStore.count }}</h1><h1>{{ mainStore.info }}</h1><hr /><h1>{{ count }}</h1><h1>{{ info }}</h1><p><button @click="refteshData">修改数据count</button></p><br><h1>count1:{{ count1 }}</h1><h1>info1:{{ info1 }}</h1>
</template>
<script lang="ts" setup> import { toRefs } from 'vue'
import { storeToRefs } from 'pinia'
import { useMainStore } from "../../store";
const mainStore = useMainStore();
// **** 注意:直接解构处出来的数据,非响应式的
// const { count: count1, info: info1 } = mainStore;
// 转为响应式方法
// 1:使用 toRefs 可以将一个响应式 reactive 对象的所有原始属性转换为响应式的 ref 属性
const { count: count1, info: info1 } = toRefs(mainStore);
// 2. 通过pinia中提供的storeToRefs方法来解决非响应式问题
const { count, info } = storeToRefs(mainStore);
const refteshData = () => {mainStore.count += 10
} </script>
<style scoped>
</style>
2:修改state 中的数据
使用$patch修改数据
<template><h1>{{ mainStore.count }}</h1><h1>{{ mainStore.info }}</h1><hr /><h1>{{ count }}</h1><h1>{{ info }}</h1><p><button @click="refteshData">修改数据count</button></p><br><h1>count1:{{ count1 }}</h1><h1>info1:{{ info1 }}</h1>
</template>
<script lang="ts" setup> import { toRefs } from 'vue'
import { storeToRefs } from 'pinia'
import { useMainStore } from "../../store";
const mainStore = useMainStore();
// **** 注意:直接解构处出来的数据,非响应式的
// const { count: count1, info: info1 } = mainStore;
// 转为响应式方法
// 1:使用 toRefs 可以将一个响应式 reactive 对象的所有原始属性转换为响应式的 ref 属性
const { count: count1, info: info1 } = toRefs(mainStore);
// 2. 通过pinia中提供的storeToRefs方法来解决非响应式问题
const { count, info } = storeToRefs(mainStore);
const refteshData = () => {// 方式一: 不推荐// 解构后更改方式// count.value += 10// 结构前更改方式// mainStore.count += 10// 方式二:$patch方法// mainStore.$patch({// count: mainStore.count + 1,// info: "hello"// })// 方式三:通过$patch传递一个函数来实现,这里的state就是useMainStore容器中的state。mainStore.$patch(state => {state.count += 10state.info = "pinia批量更新" + state.count})
} </script>
<style scoped>
</style>
使用actions中的方法修改数据 (推荐)
store/index.ts
import { defineStore } from "pinia";
export const useMainStore = defineStore("main", {state: () => {return {info: "Hello, My Pinia",id: 11,count: 0,depId: 6,userName: "admin",};},getters: {},// Actions 相当于组件中的 methods,用来修改 state 数据actions: {changeState() {this.count += 11;this.info = "actions修改数据";},changeStates(num: number) {this.count += num + 1;this.info = "actions修改数据";},},
});
页面使用
<template><h1>{{ mainStore.count }}</h1><h1>{{ mainStore.info }}</h1><hr /><h1>{{ count }}</h1><h1>{{ info }}</h1><p><button @click="refteshData">修改数据count</button></p><br><h1>count1:{{ count1 }}</h1><h1>info1:{{ info1 }}</h1>
</template>
<script lang="ts" setup> import { toRefs } from 'vue'
import { storeToRefs } from 'pinia'
import { useMainStore } from "../../store";
const mainStore = useMainStore();
// **** 注意:直接解构处出来的数据,非响应式的
// const { count: count1, info: info1 } = mainStore;
// 转为响应式方法
// 1:使用 toRefs 可以将一个响应式 reactive 对象的所有原始属性转换为响应式的 ref 属性
const { count: count1, info: info1 } = toRefs(mainStore);
// 2. 通过pinia中提供的storeToRefs方法来解决非响应式问题
const { count, info } = storeToRefs(mainStore);
const refteshData = () => {// 调用 actions 修改数据mainStore.changeState()mainStore.changeStates(10)
} </script>
<style scoped>
</style>
3:getters 的使用
/store/index.ts
import { defineStore } from "pinia";
export const useMainStore = defineStore("main", {state: () => {return {info: "Hello, My Pinia",id: 11,count: 0,depId: 6,userName: "admin",};},// 类似于组件的computed,用来封装计算属性,具有缓存的功能getters: {// 函数接收一个可选参数:state状态对象count10(state) {return (state.count += 10);},// 若使用this.count,则必须指明返回数据的类型count11(): number {return (this.count += 11);},count12(state) {return (this.count += 12);},},// Actions 相当于组件中的 methods,用来修改 state 数据actions: {changeState() {this.count += 11;this.info = "actions修改数据";},changeStates(num: number) {this.count += num + 1;this.info = "actions修改数据";},},
});
页面使用
<template><h1>{{ mainStore.count }}</h1><p><button @click="getGetters">获取getters</button></p>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { useMainStore } from "../../store";
const mainStore = useMainStore() as any;
const count_10 = ref('');
const count_11 = ref('');
const count_12 = ref('');
const getGetters = () => {count_10.value = mainStore.count10;count_11.value = mainStore.count11;count_12.value = mainStore.count12;
}
</script>
<style scoped>
</style>
\
最后
整理了75个JS高频面试题,并给出了答案和解析,基本上可以保证你能应付面试官关于JS的提问。
有需要的小伙伴,可以点击下方卡片领取,无偿分享