Vue3+Vite+TypeScript+pinia
- Vue3更新点
- 新建项目方式一
- 新建项目方式二
- vite-demo目录讲解
- 安装常用扩展
- vue3书写风格
- 动态css也可以这样使用
- 虚拟DOM
- Ref全家桶
- ref小知识1
- ref小知2,可以直接操作Dom
- recative全家桶
- 数组赋值方式一
- 数组赋值方式二
- to系列全家桶
- Vue3的响应式原理
- Vue2的不足
- computed计算属性
- watch侦听器
- watchEffect高级侦听器
- 更新时机(例如,一进来获取dom)
- 开发调试
- Vue3生命周期
- 引入组件,有红色下划线的警告提示
- 认识less sass和scoped
- 定义变量
- 插值语句,动态类名
- 混入样式
- bem规则实现
Vue3更新点
- MVVM架构
- Composition API结构
- 重写双向数据绑定
vue2:基于Object.defineProperty()实现
vue3:基于Proxy去做的劫持
优点:1,丢掉麻烦的备份数据
——:2,省去for in 循环
——:3,可以监听数据变化
——:4,代码更简化,对数组更友好
——:5,可以监听动态新增的属性
——:6,可以监听删除的属性
——:7,可以监听数组的索引和length属性
- VDOM性能瓶颈
- Fragments
允许我们有多个根节点
同时支持render JSX写法
新增Suspense teleport 和多v-model用法
- Tree-Shaking的支持
Vue3:import {watch} from ‘vue’
新建项目方式一
- npm init vite@latest或者
- 进入项目,npm install,安装devDependencies的东西
- npm i有可能报错,切换成淘宝镜像即可
- npm run dev
新建项目方式二
- npm init vue@latest
- 它是专门为VUE去做一个定制的
- npm i 即可
- npm run dev
vite-demo目录讲解
安装常用扩展
vue3书写风格
- 必须手动return出去,页面才能使用
- 为解决手动return这个麻烦方式-采用setup语法糖,且不需要ts
- 为满足ts格式
动态css也可以这样使用
虚拟DOM
- 通过JS来生成一个AST节点数
- 为什么使用虚拟DOM,因为一个dom上面的属性是非常多的,直接操作DOM浪费性能
- 解决方案:用js的计算属性来换取操作DOM所消耗的性能,虽然也会操作DOM,但我们尽可能的操作js,减少操作Dom的次数
- 例如,v-for数组循环的key有没有的渲染情况,有key会更加友好
Ref全家桶
- 注意ref是深层次的,shallowRef是浅层次的
- 两者不能再一块写,shallowRef会受ref的影响,造成视图更新
- 而triggerRef(变量),代表强制更新
<template><div class="main">{{ detail.name }}</div><button @click="changebtn">修改</button>
</template><script setup lang="ts">
import { ref,shallowRef,triggerRef} from 'vue';
const detail = ref({ name: '花神' });
const changebtn = () => {detail.value.name = '花神技术点击';
};
</script><style scoped></style>
- 当碰到引入的vue下红色波浪线
- 修改moduleResolution的值为’node’
ref小知识1
-
当我们打印修改过的值的时候
-
控制台显示的不直观
-
通过修改游览器的,勾选这个属性即可
-
这样就显示的直观啦
ref小知2,可以直接操作Dom
<template><div class="main">{{ detail.name }}</div><div ref="dom">dom值</div><button @click="changebtn">修改</button>
</template><script setup lang="ts">
import { ref } from 'vue';
const detail = ref({ name: '花神' });
//注意,定义在点击事件外定义,并且不能让他自主推断类型
//需要设置类型为HTMLDivElement
const dom = ref<HTMLDivElement>();
const changebtn = () => {detail.value.name = '花神技术点击';console.log(detail);//然后因为一上来dom没渲染完,所以在点击事件里面打印console.log(dom.value?.innerText);
};
</script><style scoped></style>
recative全家桶
-
ref支持所有的类型
-
reactive支持引用类型 Array Object Map Set
-
reactive取值,赋值不需要.value
-
注意,reactive数组赋值不可以直接直接赋值,需要通过push+解构的方式
-
全家桶系列:readonly只读,shallowReactive浅层的
-
注意以下的报错
-
原因ref是一个响应式的数据类型,它只能包含一个值。当你尝试在ref上使用push方法时,TypeScript会提示错误,因为push方法是数组对象的方法,而不是ref对象的方法。
-
解决这个问题的方法是,你需要使用reactive来创建响应式的数组对象
数组赋值方式一
数组赋值方式二
- 添加一个对象,把数组作为一个属性
to系列全家桶
-
toRef,如果原始对象是非响应式的就不会更新视图,数据会变,是响应式的就会更新视图,更新数据
-
toRefs,解构多个值
-
toRaw,可以让响应式数据不响应
Vue3的响应式原理
- Vue2使用的是Object defineProperty
- Vue3使用的是Proxy
Vue2的不足
- 对象只能劫持设置好的数据,新增的数据需要Vue Set(xxx)数组只能操作7种方法,修改某一项值无法劫持
computed计算属性
- 计算属性,就是当依赖的属性的值发生变化的时候,才触发他的更改,如果依赖的值,不发生变化,使用的是缓存中的属性值
<template><div class="main"><div>姓:<input type="text" v-model="firstname" name="" id="" /></div><div>名:<input type="text" v-model="lastname" name="" id="" /></div><div>姓名:{{ name }}</div><div>姓名:{{ name1 }}</div><button @click="changename">修改姓名</button></div>
</template><script setup lang="ts">
import { ref, computed } from 'vue';
let firstname = ref('花');
let lastname = ref('神');//computed用法
//1,选项式写法,支持一个对象传入get函数以及set函数自定义操作
let name = computed<string>({get() {return firstname.value + lastname.value;},set(newvalue) {[firstname.value, lastname.value] = newvalue.split('-');},
});
const changename = () => {name.value = '小-花';
};
//2,函数式写法,只能支持一个getter函数,不允许修改值
let name1 = computed(() => firstname.value + lastname.value);
</script><style scoped></style>
watch侦听器
- watch需要侦听特定的数据源,并在单独的回调函数中执行副作用
- 第一个参数是监听源
- 第二个参数是回调函数
- 第三个参数是一个options配置项是一个对象{immediately:true,//是否立即调用一次deep:true//是否开启深度监听 }
- deep:true,//一般用来监听深层次对象,但注意的是源数据如果是reactive绑定的,不开启深度监听也可以监听到,因为在源码里面有开启
<template><div class="main"><div>姓:<input type="text" v-model="firstname" /></div><div>姓:<input type="text" v-model="lastname" /></div><div>姓:<input type="text" v-model="obj.foo.box.bar.name" /></div></div>
</template><script setup lang="ts">
import { ref, reactive, watch } from 'vue';
let firstname = ref<string>('花神');
let lastname = ref<string>('花神');
let obj = reactive({foo: {box: {bar: {name: '花神',},},},
});//监听单个数组
watch(firstname,(oldvalue, newvalue) => {console.log(oldvalue, newvalue);},{deep: true, //一般用来监听深层次对象,但注意的是源数据如果是reactive绑定的,不开启深度监听也可以监听到}
);
//监听多个数组.此时的oldvalue, newvalue也是数组
watch([firstname, lastname], (oldvalue, newvalue) => {console.log(oldvalue, newvalue);
});
//如果监听对象中深层次的一个属性
watch(() => obj.foo.box.bar.name,(oldvalue, newvalue) => {console.log(oldvalue, newvalue);}
);
</script><style scoped></style>
watchEffect高级侦听器
- 立即执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数
//具有非惰性,一进页面,会自动调用一下
watchEffect((oninvalidate) => {oninvalidate(()=>{console.log('这个函数用来清除副作用,是最先执行的,类似可以防抖')})console.log('firstname', firstname.value);console.log('obj', obj.foo.box.bar.name);
});
- 还可以防止监听
//具有非惰性,一进页面,会自动调用一下
const stop = watchEffect((oninvalidate) => {oninvalidate(() => {console.log('这个函数用来清除副作用,是最先执行的,类似可以防抖');});console.log('firstname', firstname.value);console.log('obj', obj.foo.box.bar.name);
});
//watchEffect会返回一个函数,可以用来取消监听
const changestop = () => stop();
更新时机(例如,一进来获取dom)
- pre ,组件更新前执行
- sync,强制效果始终同步触发
- post,组件更新后执行
开发调试
- onTrigger对于监听的值将在依赖项变更导致副作用被触发时被调用
Vue3生命周期
引入组件,有红色下划线的警告提示
- 当组件引用有下划线的时候,虽然不影响使用,但看着不舒服
- 在设置里面配置一下
- 重启即可
<template><div class="main"></div>
</template><script setup lang="ts">
import {ref,onBeforeMount,onMounted,onBeforeUpdate,onUpdated,onBeforeUnmount,onUnmounted,
} from 'vue';//beforeCreate,created setup语法糖模式是没有这两个生命周期的,setup去代替
console.log('created');//创建
onBeforeMount(() => {console.log('创建');
});
//创建完成
onMounted(() => {console.log('创建完成');
});
//更新之前
onBeforeUpdate(() => {console.log('更新之前');
});
//更新完成
onUpdated(() => {console.log('更新完成');
});
//卸载之前
onBeforeUnmount(() => {console.log('卸载之前');
});
//卸载后
onUnmounted(() => {console.log('卸载完成');
});
</script><style scoped></style>
认识less sass和scoped
- bem规则,块元素-,块里面的元素__,同层级,不同修饰–
- less,是一门向后兼容的css扩展语言
- sass,一款强化css的辅助工具,在css语法基础上增加了变量,嵌套,混合,导入等高级功能
- sass中文网
定义变量
插值语句,动态类名
混入样式
- 定义混入
- 引用混入
bem规则实现
- 步骤一:新建.scss文件
//bem规则
//在变量的结尾添加 !default 给一个未通过 !default 声明赋值的变量赋值,此时,如果变量已经被赋值,不会再被重新赋值
$namespace: 'vt' !default;
$block-sel: '-' !default;
$elem-sel: '__' !default;
$mod-sel: '--' !default;//生成vt-$block类名
@mixin b($block) {//定义$B,接收凭借后的参数$B: #{$namespace + $block-sel + $block};//插槽使用.#{$B} {//@content相当于占位符@content;}
}//生成vt-$block__$el类名
@mixin e($el) {//获取父级类名$parent: &;//此时的类目就是全的,但可能在调用的时候会在元素内部使用,所以需要@at-root跳出嵌套@at-root {#{$parent + $elem-sel + $el} {@content;}}
}//生成vt-$block--$m类名
@mixin m($m) {$parent: &;@at-root {#{$parent + $mod-sel + $m} {@content;}}
}
- 步骤二,全局引入bem.scss文件
- 步骤三,页面上使用即可
<template><div class="main"><div><div class="vt-test">测试bem规则<div class="vt-test__name">花神技术</div><div class="vt-test--age">花神技术24岁</div></div></div></div>
</template><script setup lang="ts"></script><style scoped lang="scss">
@include b(test) {color: red;@include e(name) {color: green;}@include m(age) {color: blue;}
}
</style>
- 步骤四,实现效果