Pinia --笔记
作用:VueX的升级版,对接TS使用
一、安装依赖
yarn add pinia@2.0.23
二、main.ts
import { createApp } from 'vue'
import './styles/base.css'
import './styles/index.css'
import App from './App.vue'
import { createPinia } from 'pinia'
createApp(App).use(createPinia()).mount('#app')
三、data.json & request.ts & 接口类型
模拟数据data.json
{
"todos": [
{
"id": 0,
"name": "吃饭",
"done": false
},
{
"id": 1,
"name": "睡觉",
"done": true
},
{
"id": 2,
"name": "写代码",
"done": false
}
]
}
封装axios请求
- 先安装依赖yarn add axios
import axios from 'axios'
const request = axios.create({
baseURL: 'http://localhost:8888/todos',
})
export default request
- 注:里面的baseURL可以根据开发环境 和 生产环境更换,
看情况来编写
.env.development
NODE_ENV = "development"
VUE_APP_BASE_URL = "http://192.168.3.161:8009"
VUE_APP_CDNURL = "http://192.168.3.230:7080"
VUE_APP_GEOURL = "http://192.168.3.161:8010"
.env.production
NODE_ENV = "production"
VUE_APP_BASE_URL = "http://124.70.78.39:8009"
VUE_APP_CDNURL = "http://124.70.78.39"
VUE_APP_GEOURL = "http://124.70.78.39:8010"
api封装
export default class AxiosInterceptors {
localhost = process.env.VUE_APP_BASE_URL
constructor (url, params) {
this.url = url
this.params = params
}
post () {
return axios({
method: 'post',
baseURL: this.localhost,
url: this.url,
data: qs.stringify(this.params),
withCredentials: true,
timeout: 5000
})
.then(res => {
if (res.code === 200) {
return this.successfun(res)
} else {
that.$message('出错啦!')
throw new Error(res.msg)
}
}, err => {
that.$message('出错啦!')
throw new Error(err.msg)
})
}
}
接口类型
export interface ITodoItem {
id: number
name: string
done: boolean
}
四、store
根store文件
//根据不同的需求 写 不同的模块导入
import useMainStore from './modules/main'
import useFooterStore from './modules/footer'
/*
* o = {}是一个对象类型,然后通过:{} 来 指定该对象的内部键值对类型
* @[key: string] 表示索引键可有多个,每个索引键都是string类型
* @any 表示每个索引键对应的值类型可以是任何类型
*/
const o: { [key: string]: any } = {}
export default function useStore() {
if (!o.main) o.main = useMainStore()
if (!o.footer) o.footer = useFooterStore()
return o
}
a模块
import { defineStore } from 'pinia'
import { ITodoItem } from '../../types/data' //引用接口类型
import request from '../../utils/request'
import footerStore from './footer'
const useMainStore = defineStore('main', {
state: () => {
return {
list: [] as ITodoItem[],
}
},
actions: {
async getList() {
const { data } = await request.get<ITodoItem[]>('/')
this.list = data
},
async deleteTodo(id: number) {
await request.delete(`/${id}`)
this.getList()
},
async updateTodo(id: number, key: string, value: string | boolean) {
await request.patch(`/${id}`, {
[key]: value,
})
this.getList()
},
async addTodo(name: string) {
await request.post('/', {
name,
done: false,
})
this.getList()
},
async updateAllDone(done: boolean) {
//map 映射新数组
const arrPromise = this.list.map((item) => {
return request.patch(`/${item.id}`, {
done,
})
})
await Promise.all(arrPromise)
this.getList()
},
// #2
async clearCompleted() {
const arrPromise = this.completed.map((item) => {
return request.delete(`/${item.id}`)
})
await Promise.all(arrPromise)
this.getList()
},
},
getters: {
mainRadioStatus(): boolean {
return this.list.every((item) => item.done)
},
// #1
completed(): ITodoItem[] {
return this.list.filter((item) => item.done)
},
unCompleted(): ITodoItem[] {
return this.list.filter((item) => !item.done)
},
renderList(): ITodoItem[] {
const footer = footerStore()
if (footer.active === 'Active') {
return this.list.filter((item) => !item.done)
} else if (footer.active === 'Completed') {
return this.list.filter((item) => item.done)
}
return this.list
},
},
})
export default useMainStore
b模块
import { defineStore } from 'pinia'
const useFooterStore = defineStore('footer', {
state: () => {
return {
tabs: ['All', 'Active', 'Completed'],
active: 'All',
}
},
actions: {
updateActive(active: string) {
this.active = active
},
},
})
export default useFooterStore
五(1)、组件使用
todoItem 是 todoMain的子组件
<script setup lang="ts">
import { ref } from 'vue'
import useStore from '../store'
import { ITodoItem } from '../types/data'
const isEditing = ref(false)
const { main } = useStore()
const { deleteTodo, updateTodo } = main
const handleDelete = (id: number) => deleteTodo(id)
const handleChange = (item: ITodoItem) => updateTodo(item.id, 'done', !item.done)
// #2
const handleDblClick = () => {
isEditing.value = true
}
defineProps<{
item: ITodoItem
}>()
</script>
<template>
<li
:class="{
completed: item.done,
editing: isEditing,
}"
>
<div class="view">
<input class="toggle" type="checkbox" :checked="item.done" @change="handleChange(item)" />
<label @dblclick="handleDblClick">{{ item.name }}</label>
<button class="destroy" @click="handleDelete(item.id)"></button>
</div>
<input class="edit" value="Create a TodoMVC template" />
</li>
</template>
todoMian
<script setup lang="ts">
import TodoItem from './TodoItem.vue'
//pinia部分
import { storeToRefs } from 'pinia'
import useStore from '../store'
const { main } = useStore()
const { getList, updateAllDone } = main
const { mainRadioStatus, renderList } = storeToRefs(main) //响应式
// #4
const handleChangeAll = (done: boolean) => updateAllDone(done)
getList()
</script>
<template>
<section class="main">
<!-- #2 -->
<input id="toggle-all" class="toggle-all" type="checkbox" :checked="mainRadioStatus" @change="handleChangeAll(!mainRadioStatus)" />
<label for="toggle-all">Mark all as complete</label>
<ul class="todo-list">
<!-- These are here just to show the structure of the list items -->
<!-- List items should get the class `editing` when editing and `completed` when marked as completed -->
<TodoItem v-for="item in renderList" :item="item" />
</ul>
</section>
</template>
todoFooter
<script setup lang="ts">
import { storeToRefs } from 'pinia'
import useStore from '../store'
const { main, footer } = useStore()
const { clearCompleted } = main
const { updateActive } = footer
const { tabs, active } = storeToRefs(footer)
const { completed, unCompleted, list } = storeToRefs(main)
const initActive = () => {
const hs = window.location.hash
// active.value = hs === '#/Active' || hs === '#/Completed' ? hs.slice(2) : 'All'
const hsRes = hs === '#/Active' || hs === '#/Completed' ? hs.slice(2) : 'All'
updateActive(hsRes)
}
initActive()
</script>
<template>
<footer class="footer" v-if="list.length > 0">
<!-- This should be `0 items left` by default -->
<span class="todo-count"
><strong>{{ unCompleted.length }}</strong> item left</span
>
<!-- Remove this if you don't implement routing -->
<ul class="filters">
<li v-for="item in tabs" :key="item" @click="updateActive(item)">
<a
:class="{
selected: item === active,
}"
:href="`#/${item}`"
>{{ item }}</a
>
</li>
</ul>
<!-- Hidden if no completed items are left ↓ -->
<button v-if="completed.length > 0" class="clear-completed" @click="clearCompleted">Clear completed</button>
</footer>
</template>
五(2)、组件setup使用Demo2
<template>
<div class="all">
<SvgIcon name="github" style="width: 20px;height: 20px;"></SvgIcon>
<SvgIcon name="twitter" style="width: 20px;height: 20px; margin-left: 15px;"></SvgIcon>
<SvgIcon name="youtube" style="width: 20px;height: 20px; margin-left: 15px;"></SvgIcon>
<el-icon :size="20">
<Edit />
</el-icon>
111
<el-button @click="showList">测试按钮</el-button>
<div>{{data}}</div>
</div>
</template>
<script>
import SvgIcon from "./svgIcon/SvgIcon.vue";
import useStore from "../store/index.ts";
import {reactive} from "vue";
export default {
name: "Home",
components:{
SvgIcon
},
setup(){
const data = reactive([])
async function showList(){
const { moduleOne } = useStore()
await moduleOne.getlist().then(function () {
for(let i in moduleOne.list) {
data.push(moduleOne.list[i])
}
})
}
return {
showList,
data
}
}
}
</script>
<style scoped lang="scss">
.all{
width: 100%;
height: 100%;
background-color: pink;
}
</style>