vue脚手架
一、vite简介
官网:开始 | Vite 官方中文文档 (vitejs.dev)
二、创建
npm create vite
最后的生成目录结构:
注:Volar 取代了我们之前为 Vue 2 提供的官方 VSCode 扩展 Vetur。如果你之前已经安装了 Vetur,请确保在 Vue 3 的项目中禁用它。
vue3
一、简介
二、基础
1、简单示例
<template>
<p>计算:{{ num }}</p>
<button @click="toAdd">加</button>
<p>复杂计算:{{ objNum.num }}</p>
<p ref="op">我是p标签</p>
</template>
<script lang="ts">
import { defineComponent, ref, reactive, onMounted, nextTick } from "vue";
export default defineComponent({
setup(){
/**
* ref基本数据类型
*/
// let num = 10;//不是响应式数据,做不到双向数据绑定,影响页面变化
let num = ref(10);//这是vue内部封装的一个响应式对象数据;num.value才能真正拿到10这个值
//所以,以后在js中操作这种响应式数据,需要 .value;但是在模板中不需要,直接使用num(原因是在vue编译的时候已经帮我们用.value获取了一次)。
/**
* reactive:复杂类型
*/
let objNum = ref({
num:20
})
console.log(objNum.value.num);
let objNum2 = reactive({
num:10
})
console.log(objNum2.num)//不需要.value
//获取绑定了ref属性,且值为op的标签
let op = ref();
//方法
const toAdd = () => {
num.value++;
objNum.value.num++;
}
//生命周期
onMounted(() => {
console.log(op.value);//挂载完成后,才能获取到元素
})
nextTick(() => {
console.log(op.value);//在下一个dom更新的时候执行(只会执行1次)
})
return {
num,
objNum,
op,
toAdd
}
}
});
</script>
<style lang="scss" scoped>
</style>
Tip:定义快捷代码片段:设置-用户代码片段-新建全局代码片段文件。(其中prefix中定义的名字,就是在使用时直接输入vue3,可以快速生成代码片段)
{
"demo":{
"prefix":"vue3",
"body":["<template>",
"\t",
"</template>",
"",
"<script lang='ts'>",
"import { defineComponent, ref } from 'vue';",
"",
"export default defineComponent({",
"\tsetup(){\n",
"\t\t",
"\t\treturn {",
"",
"\t\t}",
"\t}",
"});",
"</script>",
"",
"<style lang='scss' scoped>",
"",
"</style>"]
},
"description": "定义vue3的代码片段"
}
2.setup语法糖
<template>
<p>复杂计算:{{ num }}</p>
<button @click="toAdd">加</button>
</template>
<script lang="ts" setup>
import { reactive, toRefs } from "vue";
let objNum = reactive({
num: 20,
});
// let {num} = objNum;//结构后,不是响应式数据
//解构成响应式数据,依旧需要通过.value的方式操作
let {num} = toRefs(objNum);
const toAdd = () => {
num.value++
}
</script>
<style lang="scss" scoped></style>
3.watch和watchEffect
import { reactive, ref, toRefs, watch, watchEffect } from "vue";
let num = ref(10);
const toAdd = () => {
num.value++
}
watch(num, (newVal, oldVal) => {
console.log(newVal, oldVal)
})
//监听复杂类型中的属性
let obj = reactive({
age:10
});
let {age} = toRefs(obj);
watch(age, (newVal, oldVal) => {
console.log(newVal, oldVal)
})
watch(() => obj.age, (newVal, oldVal) => {
console.log(newVal, oldVal)
})
watch([() => obj.age], (newVal, oldVal) => {
console.log(newVal, oldVal)
})
//页面刷新的时候就立即监听
watchEffect(() => {
})
4.computed计算属性
import { computed, reactive, ref } from "vue";
let num = ref(10);
let doubleNum = computed(() => {
return num.value * 2;
});
let obj = reactive({
age: 10,
});
let doubleAge = computed(() => {
return obj.age * 2;
});
let name=ref('张三');
let checkAll = computed({
get(){
return name.value;
},
set(val){
name.value = "我是:"+val;
}
});
checkAll.value = '李四';
console.log(checkAll.value);
5.父子组件
//------第一种写法
父组件:
<script setup lang="ts">
import {ref} from 'vue';
//子组件
import child from './child.vue'
let num = ref(1000);
const submit = (n:number)=>{
num.value = n;
}
</script>
<template>
<child :num="num" @submit="submit"></child>
</template>
子组件:
<template>
<p>参数:{{ num }}</p>
<button @click="toSubmit">提交</button>
</template>
<script lang="ts" setup>
//子组件接受参数
defineProps({
num: {
type: Number,
default: 10,
},
});
//ts中子传父
const emits = defineEmits<{(event: "submit", id: number): void }>();
const toSubmit = () => {
emits("submit", 12);
};
</script>
<style lang="scss" scoped></style>
//------第二种写法
父组件:
<script setup lang="ts">
import {ref} from 'vue';
//子组件
import child from './child.vue'
let num = ref(1000);
</script>
<template>
<child v-model:num="num"></child>
</template>
<style scoped>
</style>
子组件:
<template>
<p>参数:{{ num }}</p>
<button @click="toSubmit">提交</button>
</template>
<script lang="ts" setup>
//子组件接受参数
defineProps({
num: {
type: Number,
default: 10,
},
});
//ts中子传父,update:固定写法,后面的变量就是父组件中的v-model:后面的这个变量
const emits = defineEmits<{(event: "update:num", id: number): void }>();
const toSubmit = () => {
emits("update:num", 12);
};
</script>
<style lang="scss" scoped></style>
6.匿名插槽和具名插槽
父组件:
</script>
<template>
<child>
<p>我是匿名插槽的内容</p>
<!-- <template v-slot:first> -->
<!-- 简写# -->
<template #first>
我是具名插槽的内容
</template>
</child>
</template>
子组件:
<template>
<slot name="first">
</slot>
<p>插槽测试</p>
<slot></slot>
</template>
7.全局配置
需求:把userType接口定义为全局。
实现步骤:
7.1 新建一个userType.d.ts文件,文件内容:
interface UserType{
name:string,
age:number
}
7.2 修改tsconfig.json文件中的include,添加userType.d.ts的文件路径(其中**表示所有文件夹)。在inlucde中配置的文件内容都是全局引用的。
8.Teleport传送门,可以把组件传送到指定位置
<!-- 能够把里面的内容跟传送到指定位置的最后的位置 -->
<Teleport to="#app">
<p>测试传送</p>
</Teleport>
9.类型增强
declare var globalVar:string;//声明全局变量
declare var globalObj:UserType;
declare function globalFun(a:number):void;//声明全局方法
declare class 声明全局类;
declare enum 声明全局枚举类型;
declare type 声明全局类型;
declare interface 声明全局接口;
declare namespace 声明(含有某方法的)全局对象;
9.1 在index.html中添加:
<script>
var globalVar = "test";
</script>
9.2 在vue中使用会飘红,但是实际是有值的。(声明下就可以不会飘红了)
10.指令
hasPermi指令:
import {userStore} from '@/store/user'
export default {
mounted(el, binding, vnode) {
const { value } = binding
const all_permission = "*:*:*";
const store = userStore();
const permissions = store.permissions
if (value && value instanceof Array && value.length > 0) {
const permissionFlag = value
const hasPermissions = permissions.some(permission => {
return all_permission === permission || permissionFlag.includes(permission)
})
if (!hasPermissions) {
el.parentNode && el.parentNode.removeChild(el)
}
} else {
throw new Error(`请设置操作权限标签值`)
}
}
}
绑定到全局:
import hasPermi from './hasPermi'
app.directive('hasPermi', hasPermi)
三、配置项目路径别名
1.tsconfig.json文件中配置baseUrl和path
2.vite.config.ts文件中修改