Vue3学习笔记

40 阅读7分钟
安装 lang="scss"
npm install -D sass-embedded
安装 路由
npm i vue-router
//安装 mitt 事件总线(组件间的通知交互)
npm i mitt --save
vue2 和 vue3 最明显的差别就是页面函数: vue2 定义的是options API方式(选择式), 然而 vue3是 ComPositionAPI 组合式区别:
//vue2 的格式
<script>
export default {
  data() {
    return {
      ctx: null,
	  pageFlag: 'Home',
    };
  },
  mounted() {
    
  },
  methods: {
    changtab(name) {
		this.pageFlag = name;
	}
  },
};
、、、、、、 省略
</script>
//vue3 格式
<script setup>

import { ref } from "vue";

function handlerClick(params) {
  
}

</script>
import { ref, reactive } from "vue"; 数据的响应式处理, 使用 ref 和 reactive 包裹的数据
<script setup>
	// ref 或者 reactive 将基本数据和对象添加为 响应式
import { ref, reactive } from "vue";
// ref 可以定义全部类型的数据类型(建议是只用于定义 基本类型) 响应式
let name = ref('张三')

function changeAge() {
	// 因为 被 ref 包裹的基本类型 是响应式的, 直接 .value 赋值
	name.value += '*'
}
// reactive 定义添加对象类型为 响应式
let person = reactive({
	name: '李四',
	age: 15,
})

function changePerson() {
	// 修改数据列子1: 因为 被 reactive 包裹的对象 是响应式的,和 ref 不同 没有 .value 所以不能直接这样修改
	// person = {
	// 	name: '王昭君',
	// 	age: 50,
	// }
	// 列子2: 但是 修改对象中的某一个值就可以
	//person.age += 1
	// 列子3: 如果对 对象 全部数据修改可以用如下方法
	Object.assign(person, {name: '王昭君',age: 50,})
}

// 数组1
// let personList = reactive(
// [
// 	{
// 		name: '李四',
// 		age: 15,
// 	},
// 	{
// 		name: '张三',
// 		age: 35,
// 	},
// 	{
// 		name: '王麻子',
// 		age: 37,
// 	}
// ]
// )
//数组2
let personList = reactive(
{
	arr: [
		{
			name: '李四',
			age: 15,
		},
		{
			name: '张三',
			age: 35,
		},
		{
			name: '王麻子',
			age: 37,
		}
	]
})
// 改变数组对象的数据
function changePersonList() {
	// 更新数组里面全部数据
	// Object.assign(personList,
	// [
	// {
	// 	name: '李四New',
	// 	age: 16,
	// },
	// {
	// 	name: '张三New',
	// 	age: 36,
	// },
	// {
	// 	name: '王麻子New',
	// 	age: 40,
	// }
	// ])
	// 对list 响应式数据添加新数据
	//personList.push({name: '李牧玩', age: 400})
	
	//这样也可以 修改reactive包裹的数据
	personList.arr = [
	{
		name: '李四New',
		age: 16,
	},
	{
		name: '张三New',
		age: 36,
	},
	{
		name: '王麻子New',
		age: 40,
	}
	]

}

</script>
import { ref, reactive, watch, toRefs, toRef} from "vue"; 使用 watch 监听数据变化
1.ref 包裹数据, watch 监听
<script setup>
	// ref 或者 reactive 将基本数据和对象添加为 响应式
import { ref, reactive, watch, toRefs, toRef} from "vue";

let book = ref({name: '三国演义', author: '罗贯中'})

function changeBook() {
	book.value = {name: '红楼梦', author: '曹雪芹'}
}
// 监听 ref 包裹的对象book, 需要变动整个 book 对象才会监听到
watch(book, (newValue, oldValue) => {
	console.log(newValue, oldValue)
})



function changeBookName() {
	book.value.name = "西游记"
	changeState()
}

//列子1: Invalid watch source:  undefined A watch source 会提示无效的监视源
// watch(book.name, (newValue, oldValue) => {
// 	console.log(newValue, oldValue)
// })
// 例子2: watch 监听的是一个函数式 变化 所以需要改成 () => book.value.name 
watch(() => book.value.name, (newValue, oldValue) => {
	console.log(newValue, oldValue)
})

</script>

2.reactive 包裹数据, watch 监听

<script setup>
	// ref 或者 reactive 将基本数据和对象添加为 响应式, watch, watchEffect 监听数据变化, toRefs, toRef 监听数据的单个参数变化的函数
import { ref, reactive, watch, watchEffect, toRefs, toRef} from "vue";

let book = reactive({name: '三国演义', author: '罗贯中'})

function changeBook() {
	//book = {name: '红楼梦', author: '曹雪芹'}
	Object.assign(book, {name: '红楼梦', author: '曹雪芹'})
}
// 监听 ref 包裹的对象book, 需要变动整个 book 对象才会监听到
watch(book, (newValue, oldValue) => {
	// 这个时候变动了数据,但是数据 newValue === oldValue,相等了
	console.log(newValue, oldValue)
})

//reactive 包裹时, 监听某个属性

// 列子1: 可以实现监听某个属性。 如果时 ref 包裹的数据需要 采用 () => book.name 方式进行监听属性变化
// watch(() => book.name, (newValue, oldValue) => {
// 	console.log(newValue, oldValue)
// })

// 列子2: 使用 toRefs 方法, 也能达到监听 某个属性值变化
// const {name, author} = toRefs(book)
// watch(name, (newValue, oldValue) => {
// 	console.log(newValue, oldValue)
// })

// 列子3: toRef 方法, 能监听某个属性变化
const nameChange = toRef(book, 'name')
watch(nameChange, (newValue, oldValue) => {
	console.log(newValue, oldValue)
})

function changeBookName() {
	// 名字变动时 watch(book, (newValue, oldValue) 整个 book 监听也要被监视
	book.name += '~'
}

// 监视 reactive() 定义的响应式数据时,且 默认自动开启了深度监视,并且该深度监视 不可通过配置项 { deep: false } 关闭
let books = reactive([{name: '红楼梦', author: '曹雪芹'}, {name: '水浒转', author: '曹雪芹11'}])

watch(books, (newValue, oldValue) => {
	/// 注意:当只修改嵌套的属性触发监听时 `newValue` 此处和 `oldValue` 是相等的
    // 因为它们是同一个对象!
	console.log("数组变动", newValue, oldValue)
}, {
	immediate: true,//watch 默认是懒执行,  immediate: true 时页面运行就执行
})

/**
 * 介于 reactive 的设计原理,在修改 reactive 定义的数据时,无法整体修改其变量名数据,这会使其丢失响应式,
   故而,在操作 reactive 定义的数据时,需保持只通过 属性 key 或者 下标索引值去修改某个数据,尽量避免直接修改 reactive 数据源本体。
 */

function setBooksType() {
	books.push({name: '曹操', author: '三国司机带'})
}
// 监听数组 单个数据变化
// watch(() => books[0], (newValue, oldValue) => {
// 	console.log("数组单个数据变动", newValue, oldValue)
// }, {
// 	immediate: true,
// })

function setEveryOne() {
	// 这个变动个 watch(() => books[0] 这个监听也会运行
	//books[0] = {name: '红楼梦12---', author: '曹雪芹12---'}
	books[0].name = "红楼梦12---"
}

// ============ 复杂数据 处理
let bookConfig = reactive(
{
	arr: [{name: '红楼梦', author: '曹雪芹'}, {name: '水浒转', author: '曹雪芹12'}],
	bookAddress: {address: '四川成都'}
})


function moreData1() {
	bookConfig.arr = [{name: '红楼梦New', author: '曹雪芹--'}, {name: '水浒转New', author: '曹雪芹12--'}]
}

// 列子1: 监听全部数据改变
// watch(bookConfig, (newValue, oldValue) => {
// 	console.log("复杂数据变动", newValue, oldValue)
// })
// 列子2: 监听复杂数据里面 数组变化
// watch(() => bookConfig.arr, (newValue, oldValue) => {
// 	console.log("复杂数据变动", newValue, oldValue)
// })

// 同时监听 data1 和 data2.name 等多个数据的变化  写法格式为一个数组  ,回调函数接收两个数组,分别对应来源数组中的新值和旧值:
watch([book, () => book.name], ([newValuedata1, newValuedata2], [OldValuedata1, OldValuedata2]) => {
    console.log("数据变化了新值", newValuedata1, newValuedata2);
    console.log("数据变化了旧值", OldValuedata1, OldValuedata2);
});

//显式调用返回值以停止侦听:要 手动停止一个侦听器,请调用 watch或 watchEffect返回的函数:
//stop();
watchEffect(() => {
    console.log('Array changed:', book);
});
// 模板
// watchEffect((onCleanup) => {
//     onCleanup(() => {
//         console.log("清除副作用");
//     })
// }, {
//     flush: 'post',  // sync  \ pre
//     onTrack(e) {
//     //被追踪为依赖时触发
//         console.log(e);
//     },
//     onTrigger(e) {
//     // 所追踪数据更改时触发
//         console.log(e);
//     }
// })

</script>
vue3 路由学习
安装路由:
npm install vue-router@4

组件: 路由组件 不用去写标签, 路由配置自己生成的 page 或者 views
          一般组件 需要写标签  <xxx/> 文件放在 compents

模式:history模式 访问路径 不带# 并且服务端需要配置, 一般网页都是 history
     hash模式 访问路径带有 # ,并且服务端不需要配置

配置路由

image.png

上图router 文件目录下的 index.ts 文件内容:

import {createRouter, createWebHistory} from 'vue-router'

import ContentOne from '../views/content1.vue'
import ContentTwo from '../views/content2.vue'

import ContentThree from '../views/content3.vue'

const routes = [
  { 
	  name: 'contentOne',
	  path: '/contentOne', 
	component: ContentOne ,
  },
  { 
	  name: 'contentTwo',
	  path: '/contentTwo', 
	  component: ContentTwo,
   },
   {
   	  name: 'ContentThree',
   	  path: '/ContentThree', 
   	  component: ContentThree,
    },
]

 
// 3. 创建路由实例并传递 `routes` 配置
// 你可以在这里输入更多的配置,但我们在这里
// 暂时保持简单
const router = createRouter({
  // 4. 内部提供了 history 模式的实现。为了简单起见,我们在这里使用 hash 模式。
  history: createWebHistory(),
  routes, // `routes: routes` 的缩写
})


export default router

最后在 main.js 配置调用:
import router from './router'

createApp(App).use(router).mount('#app')

页面使用:
### 路由导航:
取值:
import {useRoute} from 'vue-router'
let route = useRoute()

##### 导航 router-link 方式1:
<router-link class="button" to="contentOne">描述</router-link>
<router-link class="button" to="contentTwo">详情</router-link>
<router-link class="button" to="ContentThree">个人资料</router-link>

##### 导航 router-link 方式2: :to="{path:'/contentOne'}" 对象
<router-link class="button" :to="{path:'/contentOne'}">描述</router-link>
<router-link class="button" :to="{name: 'contentTwo'}">详情</router-link>
<router-link class="button" to="contentThree">个人资料</router-link>

##### 导航 router-link 方式3 (传参数):
1. <router-link class="button" to="/contentThree?a=1">个人资料</router-link>,
to="/contentThree?a=1" 传入数据, 为query 形式

2. query 传值
:to="{
    path:'/contentOne',
    query: {
       a: '钢铁股'
    }
}"
3. params 配置方式一
先配置路由规则:path: '/contentOne/:a',
{ 
    name: 'contentOne',
    //contentOne/:a?  字段添加问号, 标识此字段可以不用必传
    path: '/contentOne/:a', // 使用 a 字段站位(实际开发a提交对应字段)
    component: ContentOne ,
}
/contentOne/:a 这个 a 字段就是需要传的值, 通过 to="/contentOne/测试" 方式。也可以:to="`/contentOne/${oneTip}`"模版数据传值
4. params 配置方式二
:to="{
    name: 'contentOne',
    params: {
        a: oneTip,
        // (测试需要删除这两句)如果路由预留字段配置不一致会提示: Discarded invalid param(s) "b" when navigating
        // b: oneTip
    }
}"
5. 配置路由 props
{ 
	  name: 'contentOne',
	  //contentOne/:a?  字段添加问号, 标识此字段可以不用必传
	  path: '/contentOne/:a?', 
	component: ContentOne ,
	//props: true,//方式一 只能处理 params处理传值
	// 可以自己决定将 任何一张传值方式作为 props
	props(route) {
		console.log('route路由', route)
		return route.params// route.params 是params 参数值传递, route.query 是query 参数值传递
		// return {
		// 	a: "测试环境props"
		// }
	},
	// 方式三 对象写法, 将 每组 key-vaule作为 props 传给路由(不常用)
	// props: {
	// 	a: "测试环境props2222"
	// }
	
  }

### 路由挂载页面
<router-view></router-view>