vue3与vue2的区别
1.代码组织方式发生变化
vue2选项式api { data(){},methods:{},watch:{},computed… }
vue3组合式api
2.底层架构发生改变
vue3使用typescript实现,vue2底层使用js*
3.数据绑定发生变化
vue2 通过Object.defineProperty() 方式来监听
vue3 通过Proxy
4.生命周期发生变化
vue3根据vue2生命周期取消了创建前后的生命周期 其他的生命周期+on前缀
全局变量
为了定义一些全局能用的公共变量或方法,可以将变量或方法注入给
app.config.globalProperties
步骤1.main.js中定义定义全局属性或方法
app.config.globalProperties.msg = “hello, 我是全局的msg”;
步骤2.组件中通过下面的方法获取:
import { getCurrentInstance } from “vue”;
const { proxy } = getCurrentInstance();
proxy.全局变量或方法名
Vue3在原型上挂载方法
例如我们全局挂载axios
yarn add axios -S
进行全局安装- ↓
然后引入并挂载到原型上组件中 import { getCurrentInstance } from "vue";
const { proxy } = getCurrentInstance();
// getCurrentInstance() 获取当前组件实例
proxy.$axios.get("http://elm.cangdu.org/v1/cities?type=guess").then(res => { data.arr = res.data; });
就能进行请求了
Vue的生命周期!
指的是组件实例从创建到销毁的过程,在不同的阶段做不同的事情
主要经常使用的有8个生命周期钩子函数(创建前后,挂载前后,更新前后,销毁前后)
在项目中我们一般在created创建后的钩子函数中进行数据请求,获取本地存储的数据、
在mounted挂载后的钩子函数中获取Dom元素、也可以通过在标签上添加ref属性来获取Dom元素 * vue内获取dom元素尽量使用ref;相当于class * 获取元素使用的是 this.$refs.divbox
、(有时候也存在获取不到dom元素的情况,这个时候我们⼀般⽤$nextTick⽅法来解决)
另外三个钩子函数是在keep-alive使用的、
还有一个页面中我们有时候修改数据时,试图不更新我们可以用
this.
s
e
t
(
)
方
法
来
进
行
更
新
。
t
h
i
s
.
set()方法来进行更新。 this.
set()方法来进行更新。this.set(需要修改的对象,属性,值)
还可以用 JSON.parse(JSON.stringify("数据”)) 方法来更新视图
Vue3使用监听属性
vue3有两个监听方式,第一种是watch方式
import { computed,watch } from "vue";
watch(()=>one.flag,(newVal,oldVal)=>{
one.list.forEach(item=>item.flag=newVal)
},{
immediate:true, //立即监听
deep:true //深度监听
});
第二种是
watchEffect(()=>{console.log('watchEffect',num.value)})
watchEffect 是立即执行,watch不会,若想让watch执行一次开启immediate
Vue3使用计算属性
const ones=computed(()=>{
let num=0;
one.list.forEach(item=>{
if(item.flag){
num+=item.minnum*item.price
}
})
return num
})
Vue3的setup
setup有两个参数,一个是props,一个是ctx
props是父子组件传值的数据存在props中,ctx我们一般使用里面的emit,进行子传父
setup还可以在script标签内<script setup></script>
就不用return了。
如果这样写,props和ctx怎么获取呢?
setup script语法糖提供了三个新的
API来供我们使用:
defineProps、
defineEmits和
useContext
-
defineProps 用来接收父组件传来的值props。
-
defineEmits 用来声明触发的事件表。
-
useContext 用来获取组件上下文context。
import { useContext, defineProps, defineEmits } from 'vue'
// defineProps 用来接收父组件传来的值props。
// defineEmits 用来声明触发的事件表。
// useContext 用来获取组件上下文context。
const emit = defineEmits(['click'])
const ctx = useContext()
const props = defineProps({ // 可以拿到它的值
msg: String,
})
const sonClick = () => {
emit('click', ctx)
}
Vue3的vuex
- vuex是vue的状态(理解为数据)管理工具;主要实现个组件之间的数据共享
5个核心的概念
-
state – 存放状态(数据)
-
getters — 认为是计算属性 (可以对state内的数据进行处理)
-
mutations – 唯一一个更新state内的值的 方法
-
actions — 改变state值的方法;但是 一般 放置 异步的方法;并且需要调用mutations内的方法
-
modules – 模块 (同一类的或者说是 同一模块的单独放置)
获取值
- state 内的值: $store.state.属性名
- getters 内的值: $store.getters.属性名
- mutations内的方法: $store.commit(‘vuex内mutations内的方法名’)
- actions内的方法: $store.dispatch(‘vuex内actions内的方法名’)
辅助函数(四大金刚);作用就是说可以在页面内直接调用;因此需要映射到页面
-
值的映射必须写在计算属性内
- mapState,
- mapGetters,
- 方法的映射必须写在 methods内
- mapMutations,
- mapActions
- 映射过之后,页面可以直接通过this调用
import { mapState, mapGetters, mapMutations, mapActions } from "vuex";
export default {
name: "Home",
// 值的映射必须写在 计算属性内
computed: {
...mapState(["num", "msg"]),
...mapGetters({
getNUmMsg: "getNUmMsg",
}),
},
// 方法的映射必须写在 methods内
mounted() {
// 获取state内的值
console.log(this.$store.state);
console.log(this.$store.getters);
},
methods: {
// 点击按钮的事件
addHandle(num) {
// 讲vuex内的num加1
// this.$store.state.num++ // 错误的写法
// this.$store.commit("addNum", num);
// 辅助函数的写法
this.addNum(num);
},
addActionsHAnldxe() {
// 原始写法
// this.$store.dispatch("changeNum");
// 辅助函数的写法
this.changeNum();
},
...mapMutations(["addNum"]),
...mapActions({
changeNum: "changeNum",
}),
},
};
路由跳转和传参
-
vue2内 使用
- this.$router – 跳转 传参数
- this.$route — 接收参数
-
vue3 内 组合api 使用 该如何使用路由呢
- import {useRoute,useRouter} from ‘vue-router’
- const route = useRoute – 接收的
- const router = useRouter – 跳转 传参数
-
vue内的传参数 3 种: params query传参数 动态路由
* query 形式的传参数: * router.push('') * router.push({}) --------- 里边path或者name;query:{}传的参数 * 刷新不会丢失 * 接收参数的时候: route.query
- params传参数
- router.push({name:‘’,params:{}})
- name-- 只能使用路由名称
- params–参数
- 刷新页面,参数就会丢失
- 获取参数的时候 router.params
- params传参数
-
动态路由
- router.push(‘/about?name=2104&age=9’)
vue router-link标签
在vue-router4.0之前,我们都是使用 tag 来自定义 router-link 渲染成什么标签
<router-link to='/' tag="span">
在vue-router4.x 之后废弃了 tag 有了v-solt 概念
<router-link custom to="/catcan" v-slot="{ href,route,isActive,navigate,isExactActive}">
<li @click="navigate">我是路由自定义标签</li>
</router-link>
// custom 属性的意思,就是允许自定义标签,如果不写就会定义成 a 标签
// href 就是解析后的 url
// route 就是解析后的规范的route对象
// navigate 导航的触发函数
// isActive 是否匹配的状态
// isExactActive 是否精准匹配的状态
vue3的组合式api
响应式api:
1.ref:定义单值时使用,通常用于定义基本类型值,例如:number,string,boolean,null,
2.reactive:定义复杂数据结构时使用
3.toRef:将reative对象中的某个属性转换成单个ref的形式
4.computed:计算属性,默认只能get,没有get,除非指定set,才能实现修改
例如:
let fullName = computed({
get() {
return firstName.value + lastName.value;
},
set(v) {
let arr1 = v.split("-");
console.log("要修改的值:", arr1);
firstName.value = arr1[0];
lastName.value = arr1[1];
},
});
5.nextTick:数据与视图不同步时,但想获取dom更新后的数据
//等绑定,或dom数据更新完才执行操作
nextTick(() => {
t.value.style.border = “1px solid #f00”;
});
5. watch:监听数据的改变
//1.监听ref值变化
watch(
firstName,
(newV, oldV) => {
console.log("新值:", newV);
console.log("旧值:", oldV);
},
{ deep: true }
);
//2.监听reactive值变化
watch(
() => cartObj.num,
(newV, oldV) => {
console.log("新值:", newV);
console.log("旧值:", oldV);
},
{ deep: true }
);
watchEffect:
例如:
watchEffect(() => {
console.log(“cartObj.num:”, cartObj.num);
});
总结watcht watchEffect区别:
watch:只有数据改变时才触发
watchEffect:进入页面,可以访问时立即触发,同时数据改变时也会执行
vue3组件通讯
父传子
- 用defineProps()来接收父级传过来的值
- 代码演示:
父传:
在父组件的子组件标签上添加自定义属性:
<HelloWorld msg="我传值了" title="今天天气挺好"></HelloWorld>
子接:
在子组件的js中通过defineProps接收
defineProps({
msg: {
//要接收的数据类型
type: String,
//必填项
//required: true,
//指定默认值
default: "此处省略",
},
title: {
type: String,
default: "此处是标题",
},
});
子传父
-
跟vue2类似,也是事件监听派发机制
-
演示代码:
子传:
1.声明要派发的事件
const emit = defineEmits(["go", "play"]);
2.触发事件
HTML:
<button @click="goParent">向父级传递数据</button>
JS:
const news = "我是hello world组件一条新闻";
const goParent = () => {
emit("go", news);
};
父接:
<HelloWorld @go="receive"></HelloWorld>
JS:
//在父组件中接收子组件传过来的值
const receive = (v) => {
title.value = v;
};
兄弟之间
-
借助公共组件当桥梁,子(B)传给公共组件A,A再将接收的值传给另一个组件C
-
集中状态管理工具
- vuex(vue2推荐)
- pinia(vue3推荐)
-
具体使用
- 安装pinia
- npm i pinia // “pinia”: “^2.0.14”
//解构pinia中的createPinia用于创建pinia实例
import { createPinia } from "pinia";
//实例化pinia
const store = createPinia();
//注册给app
app.use(store);
定义数据
import { defineStore } from "pinia";
export const userInfo = defineStore("userinfo", {
//定义要管理的数据
state: () => {
return {
userid: "1001111",
username: "张三",
age: 20,
address: "北京",
};
},
//要处理的业务逻辑方法
actions: {},
//通过state处理的计算属性
getters: {},
});
在组件中使用数据
//引入定义的数据
import { userInfo } from "@/stores/userInfo";
//调用方法
const store = userInfo();
HTML:
<div>{{ store.username }}</div>
<div>{{ store.age }}</div>
<div>{{ store.address }}</div>
<div>共有{{ store.childsLen }}个孩子</div>
<div>count:{{ store.count }}</div>
<button @click="store.changeAge">改变年龄</button>
pinia数据持久化
npm i pinia-plugin-persistedstate
在main.js中引入
//解构pinia中的createPinia用于创建pinia实例
import { createPinia } from "pinia";
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
//实例化pinia
const pinia = createPinia();
pinia.use(piniaPluginPersistedstate);
如何实现数据持久化
import { defineStore } from "pinia";
import { useCounterStore } from "./counter";
const useCounter = useCounterStore();
export const userInfo = defineStore("userinfo", {
//数据持久化
persist: true,
//定义要管理的数据
state: () => {
return {
count: useCounter.counter,
userid: "1001111",
username: "哈哈哈",
age: 20,
address: "北京",
info: [
{ id: 1001, name: "jack", age: 20 },
{ id: 1002, name: "alice", age: 22 },
{ id: 1003, name: "hanmeimei", age: 18 },
{ id: 1004, name: "zhanglei", age: 19 },
],
};
},
//要处理的业务逻辑方法
actions: {
changeAge() {
this.age++;
},
},
//通过state处理的计算属性
getters: {
childsLen(state) {
return state.info.length;
},
},
});
如何改变本地存储的名称和改变存储的位置
import { defineStore } from "pinia";
import { useCounterStore } from "./counter";
const useCounter = useCounterStore();
export const userInfo = defineStore("userinfo", {
//数据持久化
persist: {
key: "给一个要保存的名称",
//保存的位置
storage: window.sessionStorage,
},
//定义要管理的数据
state: () => {
return {
count: useCounter.counter,
userid: "1001111",
username: "哈哈哈",
age: 20,
address: "北京",
info: [
{ id: 1001, name: "jack", age: 20 },
{ id: 1002, name: "alice", age: 22 },
{ id: 1003, name: "hanmeimei", age: 18 },
{ id: 1004, name: "zhanglei", age: 19 },
],
};
},
//要处理的业务逻辑方法
actions: {
changeAge() {
this.age++;
},
},
//通过state处理的计算属性
getters: {
childsLen(state) {
return state.info.length;
},
},
});