安装 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模式 访问路径带有 # ,并且服务端不需要配置
配置路由
上图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>