基于vue3.0简单的页面使用

news/2024/10/18 10:25:40/

基于vue3.0简单的页面使用

    • 项目效果图
    • 项目文件图
    • package.json
    • main.js
    • App.vue
    • views/Tutorial.vue
    • views/TS.vue
    • views/Docs.vue
    • views/Community.vue
    • views/Blog.vue
    • views/About.vue
    • utils/create.jsx
    • utils/defineCom.js
    • utils/DragIcon.js
    • utils/someName.ts
    • utils/TS.ts
    • stores/client.js
    • stores/message.js
    • router/index.js
    • components/createHtml.vue
    • components/footer.vue
    • components/header.vue
    • components/test.vue
    • assets/base.css
    • assets/main.scss
    • assets/styles.scss

项目效果图

在这里插入图片描述

项目文件图

在这里插入图片描述

package.json

{"name": "ping-vue","version": "0.0.0","private": true,"scripts": {"dev": "vite","build": "vite build","preview": "vite preview","lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore","format": "prettier --write src/"},"dependencies": {"miao-drag": "^1.0.0","pinia": "^2.0.35","vue": "^3.2.47","vue-router": "^4.1.6"},"devDependencies": {"@rushstack/eslint-patch": "^1.2.0","@vitejs/plugin-vue": "^4.0.0","@vitejs/plugin-vue-jsx": "^3.0.0","@vue/eslint-config-prettier": "^7.1.0","eslint": "^8.34.0","eslint-plugin-vue": "^9.9.0","prettier": "^2.8.4","sass": "^1.62.0","vite": "^4.1.4"}
}

main.js

import {createApp
} from 'vue'
import {createPinia
} from 'pinia'
import App from './App.vue'import router from './router'import '@/assets/main.scss'const pinia = createPinia();
const app = createApp(App);app.config.globalProperties.isRouterAlive = true;app.use(router);
app.use(pinia);app.mount('#app')

App.vue

<template><RouterView v-if="isRouterAlive" />
</template><script setup>import {ref,watch,getCurrentInstance,nextTick} from 'vue';import {RouterView,useRoute} from 'vue-router';const {appContext} = getCurrentInstance();/*** 监听路由是否变化* **/const route = useRoute();watch(route, (params) => {}, {deep: true,immediate: true})const isRouterAlive = ref(true);appContext.config.reload = () => {console.log("[萍萍]")isRouterAlive.value = false;nextTick(() => {isRouterAlive.value = true;})}watch(isRouterAlive, (value) => {console.log("[监听变化]", value)})watch(() => appContext.config.globalProperties.isRouterAlive, (value) => {console.log("[振-萍]", value)}, {deep: true,immediate: true})
</script><style lang="scss">
</style>

views/Tutorial.vue

<template><div class="ping-wrap"><!-- header --><headerComponent></headerComponent><!-- container --><div class="ping-container">手机号:{{ clientStore.phone }}<button @click="plusSalaryHandle">年龄{{ clientStore.age }}</button>总工资:{{ totalSal }}元<button @click="resetHandle">reset</button></div><!-- footer --><footerComponent></footerComponent></div>
</template><script setup>import headerComponent from '@/components/header.vue'import footerComponent from '@/components/footer.vue'import {useClientStore} from '@/stores/client'import {computed,ref,watch} from 'vue'const clientStore = useClientStore()console.log('[clientStore]', clientStore)const totalSal = ref(0)watch(() => clientStore.totalSalary,(value) => {totalSal.value = value}, {deep: true,immediate: true})totalSal.value = computed(() => clientStore.totalSalary)function plusSalaryHandle() {console.log('[新增]')clientStore.$patch({age: 45,phone: '15262680856'})}function resetHandle() {clientStore.$reset()}
</script><style lang="scss" scoped>
</style>

views/TS.vue

<template><div class="ping-wrap"><!-- header --><headerComponent></headerComponent><!-- container --><div class="ping-container"><p v-my-directive:premi="['miao', 'zhen']">{{ name }}</p><createH name="清太祖" :params="tempList"></createH><p v-stname:pers="['ping']">你应该看到我</p><p v-stname:pers="['ze']">你不应该看到我</p></div><!-- footer --><footerComponent></footerComponent></div>
</template>
<script setup>import headerComponent from '@/components/header.vue'import footerComponent from '@/components/footer.vue'import '@/utils/TS.ts'import createH from '@/utils/create.jsx'import {ref} from 'vue'const name = ref('ping')const tempList = [{name: '宋太宗',age: 29,address: '北京市海淀区'},{name: '汉武帝',age: 32,address: '上海市浦东新区'},{name: '唐太宗',age: 27,address: '河南省郑州市'},{name: '秦始皇',age: 270,address: '河南省郑州市'},{name: '',age: 450,address: '西安市'}]class Miao {constructor(firstName, lastName) {this._firstName = firstNamethis._lastName = lastName}get firstName() {return this._firstName}set firstName(value) {this._firstName = value}get lastName() {return this._lastName}set lastName(value) {this._lastName = value}draw() {return this._firstName + ' ' + this._lastName}}const miao = new Miao('Miao', 'zhenzhen')const fullName = miao.draw()console.log(fullName)const vMyDirective = (el, binding) => {console.log(el)console.log(binding)}const vStname = (el, binding) => {if (binding.value.includes('ze')) {el.parentNode.removeChild(el)}}
</script><style scoped lang="scss">
</style>

views/Docs.vue

<template><div class="ping-wrap"><!-- header --><headerComponent></headerComponent><!-- container --><div class="ping-container"><div id="reload">刷新页面</div><div id="btn">按钮</div><input v-model="tempList.name" /><input v-model="tempList.age" /><input v-model="tempList.wife" /><p>单价:</p><input v-model="price" /><p>数量:</p><input v-model="count" /><p>总价:</p>{{ total }}x:{{ coordinate.x }}-y:{{ coordinate.y }}</div><!-- footer --><footerComponent ref="footerRef"><template v-slot:left><div><p>朱元璋</p><p>马皇后</p></div></template><template #center> 2023 </template><template #right><div><p>杨坚</p><p>独孤皇后</p></div></template></footerComponent></div>
</template><script setup>import {onBeforeMount,onMounted,onBeforeUnmount,onUnmounted,ref,reactive,watch,watchEffect,computed,getCurrentInstance} from 'vue'import headerComponent from '@/components/header.vue'import footerComponent from '@/components/footer.vue'const footerRef = ref(null)const tempList = reactive({name: '杨坚',age: 29,wife: '独孤皇后'})const coordinate = reactive({x: 0,y: 0})watch(tempList,(value) => {console.log('[监听1]', value)}, {deep: true})watch(() => tempList.age,(value) => {console.log('[监听]', value)})watchEffect(() => {console.log('[]', tempList.name)console.log('[]', tempList.age)console.log('[你执行了我]')})const price = ref(100)const count = ref(1)watch(count, (newCount, oldCount) => {console.log('[数量]', newCount, oldCount)})const total = computed(() => {return price.value * count.value})onBeforeMount(() => {console.log('[onBeforeMount]')})onMounted(() => {console.log('[onMounted]', tempList.name)document.querySelector('#btn').addEventListener('click', handleClick)document.querySelector('#btn').style.color = 'red'document.querySelector("#reload").addEventListener("click", handleReload)})window.addEventListener('mousemove', (e) => {coordinate.x = e.clientXcoordinate.y = e.clientY})onBeforeUnmount(() => {console.log('[onBeforeUnmount]')})onUnmounted(() => {console.log('[onUnmounted]')})const {appContext} = getCurrentInstance()function handleClick() {footerRef.value.init()console.log('[footer]', footerRef.value.publice)}function handleReload() {appContext.config.reload()}//vue3.0中的自定义指令const vMyDirective = (el, binding) => {console.log(el)console.log(binding)}
</script><style lang="scss" scoped>
</style>

views/Community.vue

<template><div class="ping-wrap"><!-- header --><headerComponent></headerComponent><!-- container --><div class="ping-container"><test message="你是好人"></test><clientComponent></clientComponent></div><!-- footer --><footerComponent></footerComponent></div>
</template><script setup>
import clientComponent from '@/utils/defineCom'
import headerComponent from '@/components/header.vue'
import footerComponent from '@/components/footer.vue'
import test from '@/components/test.vue'
import { reactive } from 'vue'
const dataList = reactive([{name: '周武王',id: 1},{name: '汉光帝',id: 2},{name: '乾隆皇帝',id: 3}
])
console.log('[]', dataList)
const tempList = dataList.map((item) => {return item.id + 1
})
console.log(tempList)
</script><style lang="scss" scoped>
</style>

views/Blog.vue

<template><div class="ping-wrap"><!-- header --><headerComponent></headerComponent><!-- container --><div class="ping-container"><p>标题:{{messageStore.title}}</p><p>内容:{{messageStore.content}}</p><p>总数量:{{messageStore.totalCount}}</p><button @click="changeCountHandle">改变数量</button></div><!-- footer --><footerComponent></footerComponent></div>
</template><script setup>import headerComponent from "@/components/header.vue"import footerComponent from "@/components/footer.vue"import {useMessageStore} from "@/stores/message.js";const messageStore = useMessageStore();console.log("[messageStore]", messageStore);function changeCountHandle() {console.log("[改变]")messageStore.setCount(12)}
</script><style lang="scss" scoped>
</style>

views/About.vue

<template><div class="ping-wrap"><!-- header --><headerComponent></headerComponent><!-- container --><div class="ping-container">关于我们{{ count }}</div><!-- footer --><footerComponent></footerComponent></div>
</template><script setup>
import headerComponent from '@/components/header.vue'
import footerComponent from '@/components/footer.vue'
import { ref, onMounted, onUnmounted, watch } from 'vue'
const count = ref(0)
const timerHandle = ref(null)
timerHandle.value = setInterval(() => {count.value += 1console.log('[计时器]', count.value)
}, 1000)watch(count, (newVal, oldVal) => {console.log('[watch]', newVal, oldVal)
})onMounted(() => {console.log('[onMounted]')
})
onUnmounted(() => {console.log('[onUnmounted]')clearInterval(timerHandle.value)
})
</script><style lang="scss" scoped>
</style>

utils/create.jsx

import { defineComponent } from 'vue'
import '@/assets/main.scss'const defaultStyles = {border: '1px solid #eee',borderRadius: '5px',padding: '10px 15px',margin: '10px 0'
}export default defineComponent({props: {name: {type: String,default: 'hello world'},params: {type: Object,default: () => ({})}},data() {return {count: 0,styles: {border: '1px solid #eee',borderRadius: '5px',padding: '10px 15px',margin: '10px 0'}}},render(props) {return (<><div style={this.styles}><h1>当前计数:{this.count}</h1><p style={{ color: 'red' }}>姓名:{props.name}</p><button onClick={() => this.count++}>增加</button></div><div style={defaultStyles}><div className="row"><div className="col-6">col-6</div><div className="col-6">col-6</div></div>{props.params.map((item, index) => {if (item.age > 30) {return (<ul className="ul-block ul-block-current" key={index}><li>{index + 1}</li><li>{item.name ? '真实姓名' : '你个骗子'}</li><li>{item.age}</li><li>{item.address}</li></ul>)} else {return (<ul className="ul-block" key={index}><li>{index + 1}</li><li>{item.name ? '真实姓名' : '你个骗子'}</li><li>{item.age}</li><li>{item.address}</li></ul>)}})}</div></>)}
})

utils/defineCom.js

import {h,defineComponent
} from "vue";const clientComponent = defineComponent({name: "clientComponent",props: {},setup() {console.log("[我是组件-defineComponent]")},render() {return h('div', '我是组件')}
})export default clientComponent;

utils/DragIcon.js

"use strict"
/*** 可拖拽悬浮框* * el:被拖拽的元素,如:#dragIcon|.dragIcon* * top:初始化悬浮框距离窗口顶部的距离,如100px|10%* * left:初始化悬浮框距离窗口左边的距离,如100px|10%* * onClick:悬浮框点击触发事件**/
class DragIcon {static DEFINED_CONFIG = {el: '#dragIcon',top: '100px',left: '100px',onClick: () => {}}constructor(options) {console.log("[]", options)if (Object.prototype.toString.call(options) !== '[object Object]') {throw "配置项必须为对象,你传递的是" + Object.prototype.toString.call(options);}this.config = Object.assign({}, DragIcon.DEFINED_CONFIG, options);this.dragElement = document.querySelector(this.config.el);this.clientWidth = document.documentElement.clientWidth || window.innerWidth;this.clientHeight = document.documentElement.clientHeight || window.innerHeight;this.create();this.drag();this.isDragging = false; // 初始化时未拖拽}/*** 初始化悬浮框**/create() {const {top,left} = this.config;this.dragElement.style.top = `${top}`;this.dragElement.style.left = `${left}`;}/*** 悬浮框拖拽事件**/drag() {this.dragElement.addEventListener("mousedown", (e) => {e.preventDefault();this.isDragging = true; // 拖拽开始const rect = this.dragElement.getBoundingClientRect();const disX = e.clientX - rect.left;const disY = e.clientY - rect.top;const onMouseMove = (e) => {let moveX = e.clientX - disX;let moveY = e.clientY - disY;moveX = Math.min(moveX, this.clientWidth - rect.width);moveY = Math.min(moveY, this.clientHeight - rect.height);moveX = Math.max(0, moveX);moveY = Math.max(0, moveY)this.dragElement.style.left = `${moveX}px`;this.dragElement.style.top = `${moveY}px`;this.isDragging = false; // 拖拽结束}const onMouseUp = () => {window.removeEventListener("mousemove", onMouseMove);window.removeEventListener("mouseup", onMouseUp);this.onClick();}window.addEventListener("mousemove", onMouseMove);window.addEventListener("mouseup", onMouseUp);});}/*** 悬浮框点击事件**/onClick() {if (this.isDragging) {this.config.onClick();this.isDragging = false; // 拖拽结束}}
}export default DragIcon;

utils/someName.ts

namespace MiaoName {export interface person {name: string;age: number;}export interface student extends person {school: string;}class Miao implements student {name: string;age: number;school: string;constructor(name: string, age: number) {this.name = name;this.age = age}}
}

utils/TS.ts

class People {/*** public:公共访问修饰符,可以在类内或者类外使用public修饰的属性或者行为,默认修饰符。* private:私有访问修饰符,只能在类内使用private修饰的属性或者行为。* protected:受保护的访问修饰符,可以本类和子类中使用protected修饰的属性和行为。* **/public _firstName: string;//公共属性public _lastName: string;//公共属性private _age: number;//私有属性protected _phone: number;//受保护的属性//公共属性与静态属性的区别//公共属性:每次实例化都会生成一个新的属性//静态属性:每次实例化都会共用一个属性static _site: string = "www.baidu.com";//静态属性_website: string = "www.baidu.com";//公共属性//什么是静态成员?//静态成员是指在类中通过static修饰的属性或者方法,静态成员只能通过类名.的方式调用。//静态成员可以被继承吗?//可以//静态成员可以被子类重写吗?//不可以//静态成员可以被实例化调用吗?//不可以//静态成员可以被实例化修改吗?//不可以//静态成员可以被实例化删除吗?//不可以//静态成员可以被实例化添加吗?//不可以//静态成员可以被实例化访问吗?//不可以//静态成员可以被实例化继承吗?//不可以//静态成员可以被实例化重写吗?//不可以//静态成员可以被实例化调用吗?//不可以//什么是实例成员?//实例成员是指在类中通过this.的方式定义的属性或者方法,实例成员只能通过实例化对象.的方式调用。//实例成员可以被继承吗?//可以//实例成员可以被子类重写吗?//可以//实例成员可以被实例化调用吗?//可以//实例成员可以被实例化修改吗?//可以//实例成员可以被实例化删除吗?//可以//实例成员可以被实例化添加吗?//可以//实例成员可以被实例化访问吗?//可以//实例成员可以被实例化继承吗?//可以//实例成员可以被实例化重写吗?//可以//实例成员可以被实例化调用吗?//可以//实例员工分为哪几种?//公共实例成员:公共实例成员是指在类中通过public修饰的属性或者方法,公共实例成员可以在本类、子类和实例化对象中使用。//私有实例成员:私有实例成员是指在类中通过private修饰的属性或者方法,私有实例成员只能在本类中使用。//私有实例成员:私有实例成员是指在类中通过private修饰的属性或者方法,私有实例成员只能在本类中使用。可以被实例化调用吗?//不可以//受保护的实例成员:受保护的实例成员是指在类中通过protected修饰的属性或者方法,受保护的实例成员只能在本类和子类中使用。//受保护的实例成员:受保护的实例成员是指在类中通过protected修饰的属性或者方法,受保护的实例成员只能在本类和子类中使用。可以被实例化调用吗?//不可以//静态实例成员:静态实例成员是指在类中通过static修饰的属性或者方法,静态实例成员只能通过类名.的方式调用。constructor(firstName: string, lastName: string, age: number, phone: number) {console.log("构造函数");this._firstName = firstName;this._lastName = lastName;this._age = age;this._phone = phone;this.showAge();console.log("[static]", People._site);console.log("[public]", this._website);}/*** void:用于标识方法返回值的类型,表示该方法没有返回值。* **/init(): void {console.log("init");console.log("[public]", this._firstName);console.log("[public]", this._lastName);console.log("[private]", this._age);console.log("[protected]", this._phone);const price: number = 103;const num: number = 2.456;const total: number = price * num;console.log("[number]", total);interface person {name: string,age: number,phone?: number,family?: family[]}interface family {name: string,age: number,phone: number}let dataList: person[] = [];dataList.push({ name: "张三", age: 18, phone: 123456789 });dataList.push({ name: "张三", age: 18, phone: 123456789, family: [{ name: "张三", age: 18, phone: 123456789 }] });console.log("[interface]", dataList);dataList[0].age = 19;console.log("[interface]", dataList);dataList.forEach((item: person, index: number) => {console.log("[interface]", item, index);})}get firstName(): string {return this._firstName;}set firstName(value: string) {this._firstName = value;}showFullName(): string {console.log("[姓名:]", this._firstName + "" + this._lastName);return this._firstName + "" + this._lastName;}private showAge(): number {console.log("[年龄:]", this._age);return this._age;}protected showPhone() {console.log("[手机号:]", this._phone);}}
const site = new People("张", "三", 18, 123456789);
console.log(site.firstName);
site.firstName = "李";
console.log(site.firstName);
site.showFullName();
site.init();
console.log("[People]", People._site);/*** 子类继承父类* **/
class Woman extends People {constructor(firstName: string, lastName: string, age: number, phone: number) {super(firstName, lastName, age, phone);console.log("子类构造函数");console.log("[Woman]", Woman._site);}show() {console.log("子类", this._phone);}
}
const woman = new Woman("李", "四", 19, 123456789);woman.show();
//子类可以使用父类的静态属性吗?
//可以
//子类可以使用父类的公共属性吗?
//可以
//子类可以使用父类的私有属性吗?
//不可以
//子类可以使用父类的受保护的属性吗?
//可以console.log("[Woman]", Woman._site)
//循环数据时,使用forEach,for,find,还是map
//forEach:只能遍历数组,不能return,不能返回一个新的数组
//for:可以遍历数组,可以return,返回一个新的数组
//map:可以遍历数组,可以return,返回一个新的数组
//find:可以遍历数组,可以return,只返回第一个符合条件的数据const dataList: any[] = [{name: "张三",age: 18,phone: 123456789
}, {name: "张四",age: 19,phone: 123456789
}, {name: "张五",age: 20,phone: 123456789
}, {name: "张六",age: 21,phone: 123456789
}, {name: "张七",age: 22,phone: 123456789
}, {name: "张八",age: 23,phone: 123456789
}]dataList.map((item: any, index: number) => {item['id'] = indexreturn item;
})
console.log("[map]", dataList);dataList.find((item: any, index: number) => {item['code'] = index;return item
})
console.log("[find]", dataList);dataList.forEach((item: any, index: number) => {item['code'] = index;
})
console.log("[forEach]", dataList);const str: string = "MiaoZhenZhen";
console.log("[slice]", str.slice(2, 3));
console.log("[substr]", str.substr(2, 3));
console.log("[substring]", str.substring(2, 3));
const count = new Number(123);
console.log("[toString]", count);
console.log("[valueOf]", count.valueOf());
//slice:截取字符串,返回一个新的字符串,不会改变原来的字符串
//substr:截取字符串,返回一个新的字符串,不会改变原来的字符串
//substring:截取字符串,返回一个新的字符串,不会改变原来的字符串
//slice与substring的区别:slice可以接受负数,substring不可以接受负数
//slice与substr的区别:slice第二个参数是截取的长度,substr第二个参数是截取的结束位置const temp = [{name: "张三1",}, {name: "张三2",
}]
console.log("[temp]", temp);
temp.push({name: "张三3",})
console.log("[temp]", temp);
//为什么两次console。log(temp)值一样
//因为temp是一个引用类型,指向的是同一个内存地址,所以改变temp的值,会改变内存地址的值,所以两次打印的值一样
//如何解决两次值一样的问题?
//使用深拷贝,浅拷贝
//深拷贝:拷贝的是值,不是内存地址
//浅拷贝:拷贝的是内存地址,不是值
//如何实现深拷贝?
//JSON.parse(JSON.stringify(temp))
//如何实现浅拷贝?
//Object.assign({},temp)
const tempStr = JSON.parse(JSON.stringify(temp));
console.log("[JSON.parse(JSON.stringify(temp))]", tempStr);
tempStr.push({name: "张三4",
})
console.log("[JSON.parse(JSON.stringify(temp))]", tempStr);
//使用JSON.parse(JSON.stringify(temp))实现深拷贝,但是有一个问题,如果temp中有函数,会怎么样?
//函数会被忽略掉
//使用Object.assign({},temp)实现浅拷贝,但是有一个问题,如果temp中有函数,会怎么样?
//函数会被忽略掉
//使用JSON.parse(JSON.stringify(temp))处理过的数据,需要重新赋值新变量吗?
//需要
//为什么不能继续使用temp变量
//因为temp变量已经被重新赋值了
//如果继续使用temp变量,会怎么样?
//会报错,因为temp变量已经被重新赋值了
//在js中,每创建一个变量,都会在内存中开辟一个空间,存储这个变量的值,
//如果这个变量的值是一个引用类型,那么这个变量存储的是一个内存地址,这个内存地址指向的是引用类型的值,
//如果这个变量的值是一个基本类型,那么这个变量存储的是一个基本类型的值,
//什么是基本类型?什么是引用类型?
//基本类型:string,number,boolean,null,undefined,symbol
//引用类型:object,array,function
//如何判断一个变量是基本类型还是引用类型?
//typeofconst tempArr: any[] = ["miao", "zhen", "zhen", 1, 3, 5, 6, 8];
console.log("[tempArr]", tempArr.join(","));
console.log("[tempArr]", tempArr.toString());//join(",")与toString()的区别?//元组和数组的区别?
//元组:可以存储不同类型的数据
//数组:只能存储相同类型的数据
//元组和数组的相同点?
//都可以存储多个数据
//如何定义元组?
const tempTuple: [string, number, boolean] = ["miao", 1, true]
tempTuple.push("zhen")
console.log("[tempTuple]", tempTuple);
//如何定义数组?
//const tempArr:any[] = ["miao",1,true]
//如何获取元组中的数据?
//tempTuple[0]
//如何获取数组中的数据?
//tempArr[0]
//如何修改元组中的数据?
//tempTuple[0] = "zhen"
//如何修改数组中的数据?
//tempArr[0] = "zhen"const tempMap = new Map();
tempMap.set("name", "miao");
tempMap.set("age", 18);
console.log("[tempMap]", tempMap);console.log("[Map-1]", Map)
console.log("[Map-tempMap-2]", tempMap)
//Map有原型吗?
//有
//Map的原型是什么?
//Map.prototype
//Map的原型是谁?
//Map.prototype.constructor///<reference path="./test.ts" />
console.log(Object.prototype)
const obj: { name: string, age: number, school: string } = {name: "miao",age: 18,school: '北京大学'
};
const obj1: MiaoName.student = {name: "miao",age: 18,school: '北京大学'
};
console.log("[obj]", obj);//如何引入其他文件的内容?
console.log("[MiaoName.temp]",)
const p: MiaoName.person[] = [{name: "miao",age: 18
}]
const p1: MiaoName.student[] = [{name: "miao",age: 18,school: '北京大学'
}]
console.log("[MiaoName.temp]", p)
console.log("[MiaoName.temp]", p1)function test(): MiaoName.person[] {return [{name: "miao",age: 18}]
}console.log("[MiaoName.temp]", test.prototype.constructor())class Person {name: string;age: number;constructor(name: string, age: number) {this.name = name;this.age = age}say() {console.log("[say]", "hello")}
}

stores/client.js

import {defineStore
} from "pinia";export const useClientStore = defineStore("client", {state: () => {return {name: '忽必烈',age: 29,salary: 10,phone: '18895350000'}},getters: {totalSalary: (state) => {console.log("[state]", state)return state.age * state.salary}},actions: {setAge(params) {console.log("[params]", params)this.age = params;}}
})

stores/message.js

import {defineStore
} from "pinia";
import {computed,ref
} from "vue";export const useMessageStore = defineStore("message", () => {const title = ref("标题");const content = ref("内容");const count = ref(0);const totalCount = computed(() => {return count.value * 12})function setCount(params) {console.log("[]", params)count.value = params}return {title,content,totalCount,setCount}
})

router/index.js

import {createRouter,createWebHistory
} from 'vue-router'const router = createRouter({history: createWebHistory(import.meta.env.BASE_URL),routes: [{path: '',redirect: '/docs',}, {path: '/docs',name: 'Docs',meta: {title: '文档'},component: () => import('@/views/Docs.vue')},{path: '/tutorial',name: 'Tutorial',meta: {title: '教程'},component: () => import('@/views/Tutorial.vue')},{path: '/blog',name: 'Blog',meta: {title: '博客'},component: () => import('@/views/Blog.vue')},{path: '/community',name: 'Community',meta: {title: '社区'},component: () => import('@/views/Community.vue')},{path: '/about',name: 'About',meta: {title: '关于'},component: () => import('@/views/About.vue')},{path: '/ts',name: 'Ts',meta: {title: 'TypeScript 教程'},component: () => import('@/views/TS.vue')}],scrollBehavior: () => {return {top: 0}}
})import {useClientStore
} from '@/stores/client'
router.beforeEach((to, from, next) => {console.log("[to]", to)const store = useClientStore();console.log("[store]", store)next();
})export default router

components/createHtml.vue

<script>
import { defineComponent } from 'vue';export default defineComponent({data() {return {count: 0,};},render() {return (<div><h1>当前计数:{this.count}</h1><button onClick={() => this.count++}>增加</button></div>);},
});
</script>

components/footer.vue

<template><div class="footer-wrap"><slot name="left" v-if="!isShow"></slot><p>Copyright © <slot name="center"></slot> Meta Platforms, Inc.</p><slot name="right" v-if="isShow"></slot></div>
</template><script setup>import {ref,watch} from 'vue';const publice = ref('123');const isShow = ref(true)function init() {console.log("[我是footer]")publice.value = '456';}watch(publice, (value) => {console.log("[我改变了]", value, publice.value)isShow.value = false;})defineExpose({init,publice})
</script><style lang="scss" scoped>.footer-wrap {width: 100%;min-height: 100px;background-color: rgb(249, 249, 251);display: flex;justify-content: center;align-items: center;}
</style>

components/header.vue

<template><div class="header-wrap"><div class="header-tips">This site is no longer updated.</div><ul class="header-content"><li class="header-icon" @click="goLinkHandle('docs')"><img :src="icon" /><span>React</span></li><template v-for="(item,index) in menuList" :key="index"><li class="header-li" :class="{'header-li-current':currentPath==item.path}"@click="goLinkHandle(item.type)">{{item.name}}</li></template></ul></div><div id="dragIcon"></div>
</template><script setup>import dragIcon from "miao-drag";import {watch,ref,reactive,onMounted} from 'vue';import {useRoute,useRouter} from 'vue-router';const icon = ref('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9Ii0xMS41IC0xMC4yMzE3NCAyMyAyMC40NjM0OCI+CiAgPHRpdGxlPlJlYWN0IExvZ288L3RpdGxlPgogIDxjaXJjbGUgY3g9IjAiIGN5PSIwIiByPSIyLjA1IiBmaWxsPSIjNjFkYWZiIi8+CiAgPGcgc3Ryb2tlPSIjNjFkYWZiIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiPgogICAgPGVsbGlwc2Ugcng9IjExIiByeT0iNC4yIi8+CiAgICA8ZWxsaXBzZSByeD0iMTEiIHJ5PSI0LjIiIHRyYW5zZm9ybT0icm90YXRlKDYwKSIvPgogICAgPGVsbGlwc2Ugcng9IjExIiByeT0iNC4yIiB0cmFuc2Zvcm09InJvdGF0ZSgxMjApIi8+CiAgPC9nPgo8L3N2Zz4K')const currentPath = ref('');const route = useRoute();watch(route, (params) => {currentPath.value = params.path;}, {deep: true,immediate: true})onMounted(() => {console.log("[onMounted]")setDragIcon();});const menuList = reactive([{id: 1,name: 'Docs',path: '/docs',type: 'docs'}, {id: 2,name: 'Tutorial',path: '/tutorial',type: 'tutorial'}, {id: 3,name: 'Blog',path: '/blog',type: 'blog'}, {id: 4,name: 'Community',path: '/community',type: 'community'}, {id: 5,name: 'About',path: '/about',type: 'about'}, {id: 5,name: 'TypeScript 教程',path: '/ts',type: 'ts'}])//进行页面跳转const router = useRouter();function goLinkHandle(type) {if (type == 'docs') {router.push({path: '/docs'})} else if (type == 'tutorial') {router.push({path: '/tutorial'})} else if (type == 'blog') {router.push({path: '/blog'})} else if (type == 'community') {router.push({path: '/community'})} else if (type == 'about') {router.push({path: '/about'})} else if (type == 'ts') {router.push({path: '/ts'})}}function setDragIcon() {const clientHeight = document.documentElement.clientHeight;const clientWidth = document.documentElement.clientWidth;new dragIcon({el: '#dragIcon',top: ((clientHeight / 2) - 50) + 'px',left: (clientWidth - 250) + 'px',onClick: () => {console.log("我是点击事件")}});}
</script><style lang="scss" scoped>.header-wrap {width: 100%;display: flex;flex-direction: column;background-color: rgb(22, 24, 29);.header-tips {width: 100%;max-width: 1200px;display: flex;flex-direction: row;justify-content: center;align-items: center;font-size: 18px;font-weight: bold;color: #ffffff;margin: 12px auto;}.header-content {width: 100%;max-width: 1200px;display: flex;flex-direction: row;margin: 12px auto;align-items: center;.header-icon {height: auto;display: flex;flex-direction: row;color: #61dafb;align-items: center;justify-content: center;margin-right: 100px;cursor: pointer;img {width: 40px;height: 40px;}span {font-weight: 700;font-size: 20px;margin-left: 12px;}}.header-li {height: 40px;position: relative;font-size: 18px;color: #ffffff;padding-left: 15px;padding-right: 15px;cursor: pointer;}.header-li-current {color: #61dafb;}.header-li-current::after {content: " ";height: 3px;position: absolute;width: 100%;left: 50%;transform: translate(-50%);bottom: 0px;background-color: #61dafb;animation: identifier 1s ease;}@keyframes identifier {0% {width: 0%;}100% {width: 100%;}}}}#dragIcon {border: 1px solid #00a2ef;border-radius: 8px;width: 100px;height: 100px;position: fixed;cursor: pointer;z-index: 999;}
</style>

components/test.vue

<template><div><p>{{message}}</p></div>
</template><script>export default {props: {message: {type: String,default: () => {return "消息"}}},setup(props) {console.log("[props]", props)console.log("[this]", props.message)return {}}}
</script><style>
</style>

assets/base.css

* {padding: 0px;margin: 0px;box-sizing: border-box;-webkit-box-sizing: border-box;
}html,
body {width: 100%;background-color: #f2f2f2;
}a {text-decoration: none;
}ul,
li,
ol {list-style: none;
}button {cursor: pointer;
}button::after {border: none;
}

assets/main.scss

@import './base.css';
@import './styles.scss';.ping-wrap {width: 100%;display: flex;flex-direction: column;.ping-container {width: 100%;max-width: 1200px;min-height: 100vh;margin: 0px auto;display: flex;flex-direction: column;background-color: #fff;}
}

assets/styles.scss

.row {border: 1px solid red;width: 100%;display: flex;
}
.col-6 {border: 1px solid red;width: 50%;
}
.ul-block {border: 1px solid #dcdcdc;border-radius: 12px;padding: 10px;margin-bottom: 12px;li {border-bottom: 1px solid #dcdcdc;padding: 12px 0px;}li:last-child {border-bottom: none;}
}
.ul-block-current{border: 1px solid #00a2ef;
}

vue3.0官网
Pinia官网
Vue Router4.X官网
Vite官网

https://github.com/zzmiao/vue3.0.git


http://www.ppmy.cn/news/107243.html

相关文章

支付宝 小程序 抽奖组件 大转盘

介绍 使用支付宝原有的大转盘营销组件进行改造的&#xff0c;由于背景使用的图片&#xff0c;目前只支持 6 个奖品&#xff0c;一般情况下的大转盘都是这个规格。 转盘停止&#xff1a;之前使用的是计算角度来完成的&#xff0c;没有那种缓慢停止的动画。现在加了一个缓慢停止…

【测试开发】第四节.测试开发(测试分类)

作者简介&#xff1a;大家好&#xff0c;我是未央&#xff1b; 博客首页&#xff1a;未央.303 系列专栏&#xff1a;Java测试开发 每日一句&#xff1a;人的一生&#xff0c;可以有所作为的时机只有一次&#xff0c;那就是现在&#xff01;&#xff01;&#xff01; 文章目录 前…

iOS 性能优化方案

一、启动优化 1、冷启动&#xff08;从零开始的启动&#xff09; 冷启动三个阶段 1.1 Main函数执行前 加载可执行文件&#xff08;mach-o文件&#xff09;加载动态链接库&#xff0c;进行rebase指针调整和bind符号绑定Objc运行时的初始化处理&#xff0c;包括Objc相关类的注…

c++实现【典型的旅行商问题(TSP)】实现配送中心最多可以用2辆车对8个客户进行运输配送

假定配送中心最多可以用2辆车对8个客户进行运输配送。每个车辆载重均 为8吨,车辆每次配送的最大行驶距离为50km,配送中心(编号0)与8个客 户之间及8个客户相互之间的距离d; (i, j= 1, 2, ... 8)、8个客户的货物需 求r;(j= 1, 2... 8)如表1所示。要求寻找一条路径, 使得配送总…

麓言信息UI设计和web前端的区别

很多想从事互联网岗位的朋友在选择UI设计还是web前端&#xff0c;也不知道选哪个好&#xff0c;今天小编将带你了解UI设计和web前端的区别&#xff0c;让大家对UI设计和web前端有更多的了解&#xff0c;也能为之后的选择有一定的帮助。   UI设计要考虑人机交互的效果   …

设计师们都在用的AI作图神器,你还不抓紧入手一款

人工智能在机器和计算机控制的机器人中模拟人类智能过程。这允许计算机系统执行繁重的任务&#xff0c;帮助人类专注于更重要的事情。因此&#xff0c;多年来&#xff0c;工作场所对 AI 集成的需求不断增加。 同样&#xff0c;人工智能正迅速成为设计行业的一部分。在平面设计…

去了字节跳动,才知道年薪40W的测试有这么多?

今年大环境不好&#xff0c;内卷的厉害&#xff0c;薪资待遇好的工作机会更是难得。最近脉脉职言区有一条讨论火了&#xff1a; 哪家互联网公司薪资最‘厉害’&#xff1f; 下面的评论多为字节跳动&#xff0c;还炸出了很多年薪40W的测试工程师 我只想问一句&#xff0c;现在的…

七大软件架构设计原则详解

目录 1、概述 2、七大设计原则 2.1、开闭原则 2.2、里氏替换原则 2.3、依赖倒置原则 2.4、单一职责原则 2.5、接口隔离原则 2.6、迪米特法则 2.7、合成复用原则 3、最后 VC常用功能开发汇总&#xff08;专栏文章列表&#xff0c;欢迎订阅&#xff0c;持续更新...&…