vuex和pinia

master
barney 2 years ago
parent 6e0f4107f1
commit a36de53202
  1. 3
      .gitignore
  2. 3
      Vite-Vue-tutorial/package.json
  3. 8
      Vite-Vue-tutorial/src/.prettierrc
  4. 18
      Vite-Vue-tutorial/src/hooks/useCategories.js
  5. 84
      Vite-Vue-tutorial/src/hooks/useProducts.js
  6. 4
      Vite-Vue-tutorial/src/services/banners.js
  7. 4
      Vite-Vue-tutorial/src/services/categories.js
  8. 20
      Vite-Vue-tutorial/src/services/products.js
  9. 74
      Vite-Vue-tutorial/src/utils/request.js
  10. 21
      Vite-Vue-tutorial/src/utils/tools.js
  11. 40
      Vite-Vue-tutorial/src/views/Detail.vue
  12. 20
      Vite-Vue-tutorial/src/views/Home.vue
  13. 102
      Vite-Vue-tutorial/src/views/List.vue
  14. 24
      pinia-pre/.gitignore
  15. 3
      pinia-pre/.vscode/extensions.json
  16. 16
      pinia-pre/README.md
  17. 13
      pinia-pre/index.html
  18. 1492
      pinia-pre/package-lock.json
  19. 21
      pinia-pre/package.json
  20. 1
      pinia-pre/public/vite.svg
  21. 40
      pinia-pre/src/App.vue
  22. 1
      pinia-pre/src/assets/vue.svg
  23. 12
      pinia-pre/src/components/HelloWorld.vue
  24. 8
      pinia-pre/src/main.ts
  25. 47
      pinia-pre/src/stores/counter.ts
  26. 0
      pinia-pre/src/style.css
  27. 7
      pinia-pre/src/vite-env.d.ts
  28. 18
      pinia-pre/tsconfig.json
  29. 9
      pinia-pre/tsconfig.node.json
  30. 7
      pinia-pre/vite.config.ts
  31. 4
      vite-ts-project/src/views/List.vue
  32. 8
      vite-ts-project/src/views/Login.vue
  33. 14
      vite-ts-project/src/views/User.vue
  34. 24
      vuex-app/.gitignore
  35. 3
      vuex-app/.vscode/extensions.json
  36. 7
      vuex-app/README.md
  37. 13
      vuex-app/index.html
  38. 1355
      vuex-app/package-lock.json
  39. 21
      vuex-app/package.json
  40. 1
      vuex-app/public/vite.svg
  41. 26
      vuex-app/src/App.vue
  42. 1
      vuex-app/src/assets/vue.svg
  43. 5
      vuex-app/src/components/HelloWorld.vue
  44. 7
      vuex-app/src/main.js
  45. 20
      vuex-app/src/store/index.js
  46. 90
      vuex-app/src/style.css
  47. 7
      vuex-app/vite.config.js

3
.gitignore vendored

@ -1,3 +1,6 @@
# vscode-workspace
*.code-workspace
# Logs # Logs
logs logs
*.log *.log

@ -6,7 +6,8 @@
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "vite build", "build": "vite build",
"preview": "vite preview" "preview": "vite preview",
"format": "prettier --write ./**/*.{html,vue,ts,js,json}"
}, },
"dependencies": { "dependencies": {
"axios": "^0.27.2", "axios": "^0.27.2",

@ -1,4 +1,6 @@
{ {
"singleQuote": false, "singleQuote": false,
"semi": true "semi": true,
} "tabWidth": 4,
"useTabs": true
}

@ -3,15 +3,15 @@ import { ref } from "vue";
/** /**
* 返回分类接口的数据 * 返回分类接口的数据
* @returns * @returns
*/ */
export const useCategories = () => { export const useCategories = () => {
const categories = ref([]); const categories = ref([]);
loadCategoriesAPI().then(res => { loadCategoriesAPI().then((res) => {
categories.value = res.data; categories.value = res.data;
}); });
return { return {
categories, categories,
} };
}; };

@ -1,53 +1,51 @@
import { loadProductAPI } from '../services/products'; import { loadProductAPI } from "../services/products";
import { ref } from "vue"; import { ref } from "vue";
/** /**
* 返回商品接口的数据 * 返回商品接口的数据
* @param {*} categoryId 当前的商品分类id, 空表示获取所有分类 * @param {*} categoryId 当前的商品分类id, 空表示获取所有分类
* @returns * @returns
*/ */
export const useProducts = (categoryId='') => { export const useProducts = (categoryId = "") => {
const page = ref(1); // 当前页码
const loading = ref(false); // 是否在加载中
const finished = ref(false); // 是否加载完成
const currentCategoryId = ref(categoryId); // 当前分类id
const products = ref([]); // 商品数据
const page = ref(1); // 当前页码 /**
const loading = ref(false); // 是否在加载中 * 加载products
const finished = ref(false); // 是否加载完成 * @param {*} needReset 是否需要重置products
const currentCategoryId = ref(categoryId); // 当前分类id * @param {*} categoryId 分类id
const products = ref([]); // 商品数据 */
const onLoad = (needReset = false, categoryId = "") => {
if (needReset) {
// 重置一些参数
finished.value = false;
products.value = [];
page.value = 1;
}
// 分类id不为空才需要修改
if (categoryId !== "") {
currentCategoryId.value = categoryId;
}
loading.value = true; // 开始加载
loadProductAPI(page.value, currentCategoryId.value).then((res) => {
finished.value = page.value > res.pages; // 当前页码超过总页数时表示加载完成
loading.value = false;
// 将获取的数据存入products
products.value.push(...res.data);
page.value++; // 页码+1
});
};
/** return {
* 加载products // page,
* @param {*} needReset 是否需要重置products loading,
* @param {*} categoryId 分类id finished,
*/ products,
const onLoad = (needReset=false,categoryId='') => { currentCategoryId,
if (needReset) { onLoad,
// 重置一些参数 };
finished.value = false;
products.value = [];
page.value = 1;
}
// 分类id不为空才需要修改
if (categoryId !=='' ) {
currentCategoryId.value = categoryId;
}
loading.value = true; // 开始加载
loadProductAPI(page.value, currentCategoryId.value).then((res) => {
finished.value = page.value > res.pages; // 当前页码超过总页数时表示加载完成
loading.value = false;
// 将获取的数据存入products
products.value.push(...res.data);
page.value++; // 页码+1
});
};
return {
// page,
loading,
finished,
products,
currentCategoryId,
onLoad,
}
}; };

@ -2,6 +2,6 @@ import { get } from "../utils/request";
/** /**
* 获取轮播图 * 获取轮播图
* @returns * @returns
*/ */
export const loadBannersAPI = () => get('/api/v1/banners'); export const loadBannersAPI = () => get("/api/v1/banners");

@ -2,6 +2,6 @@ import { get } from "../utils/request";
/** /**
* 返回所有商品分类 * 返回所有商品分类
* @returns * @returns
*/ */
export const loadCategoriesAPI = () => get('api/v1/product_categories'); export const loadCategoriesAPI = () => get("api/v1/product_categories");

@ -1,21 +1,21 @@
import { get } from '../utils/request' import { get } from "../utils/request";
/** /**
* 获取商品信息 * 获取商品信息
* @param {*} page 页号 * @param {*} page 页号
* @param {*} category 分类为空表示不分类 * @param {*} category 分类为空表示不分类
* @returns * @returns
*/ */
export const loadProductAPI = (page = 1, category = '') => get('/api/v1/products/', { export const loadProductAPI = (page = 1, category = "") =>
page, get("/api/v1/products/", {
category, page,
// per, 每页最多多少数据 category,
}); // per, 每页最多多少数据
});
/** /**
* 返回商品详情 * 返回商品详情
* @param {*} id 商品id * @param {*} id 商品id
* @returns * @returns
*/ */
export const loadProductByIdAPI = id => get('/api/v1/products/'+ id); export const loadProductByIdAPI = (id) => get("/api/v1/products/" + id);

@ -1,13 +1,13 @@
import axios from "axios" import axios from "axios";
import NProgress from "nprogress" import NProgress from "nprogress";
import "nprogress/nprogress.css" import "nprogress/nprogress.css";
export const serverUrl = "http://localhost:1337" export const serverUrl = "http://localhost:1337";
const instance = axios.create({ const instance = axios.create({
baseURL: serverUrl, // baseURL会在发送请求的时候拼接在url参数的前面 baseURL: serverUrl, // baseURL会在发送请求的时候拼接在url参数的前面
timeout: 5000, // 设置超时时间 timeout: 5000, // 设置超时时间
}) });
/** /**
* get 请求 * get 请求
@ -17,9 +17,9 @@ const instance = axios.create({
*/ */
// axios.get(url, config)请求第二个参数表示配置信息(包括请求数据、请求头等) // axios.get(url, config)请求第二个参数表示配置信息(包括请求数据、请求头等)
export const get = (url, params) => export const get = (url, params) =>
instance.get(url, { instance.get(url, {
params: params, // url传递的参数 params: params, // url传递的参数
}) });
/** /**
* post 请求 * post 请求
@ -28,7 +28,7 @@ export const get = (url, params) =>
* @returns * @returns
*/ */
// axios.post(url, data, config)请求第三个参数表示配置信息(包括请求数据、请求头等) // axios.post(url, data, config)请求第三个参数表示配置信息(包括请求数据、请求头等)
export const post = (url, data) => instance.post(url, data) export const post = (url, data) => instance.post(url, data);
/** /**
* put 请求 * put 请求
@ -36,41 +36,41 @@ export const post = (url, data) => instance.post(url, data)
* @param {*} data 数据 * @param {*} data 数据
* @returns * @returns
*/ */
export const put = (url, data) => instance.put(url, data) export const put = (url, data) => instance.put(url, data);
/** /**
* delete 请求 * delete 请求
* @param {*} url 请求地址 * @param {*} url 请求地址
* @returns * @returns
*/ */
export const del = (url) => instance.delete(url) export const del = (url) => instance.delete(url);
// Add a request interceptor (全局请求拦截) // Add a request interceptor (全局请求拦截)
instance.interceptors.request.use( instance.interceptors.request.use(
function (config) { function (config) {
// console.group("全局请求拦截"); // console.group("全局请求拦截");
// console.log(config); // console.log(config);
// console.groupEnd(); // console.groupEnd();
NProgress.start() // 启动进度条 NProgress.start(); // 启动进度条
// 这里还可以设置token // 这里还可以设置token
return config return config;
}, },
function (error) { function (error) {
return Promise.reject(error) return Promise.reject(error);
} }
) );
// Add a response interceptor (全局响应拦截) // Add a response interceptor (全局响应拦截)
instance.interceptors.response.use( instance.interceptors.response.use(
function (response) { function (response) {
// console.group("全局响应拦截"); // console.group("全局响应拦截");
// console.log(response); // console.log(response);
// console.groupEnd(); // console.groupEnd();
NProgress.done() // 关闭进度条 NProgress.done(); // 关闭进度条
return response.data return response.data;
}, },
function (error) { function (error) {
NProgress.done() // 关闭进度条 NProgress.done(); // 关闭进度条
return Promise.reject(error) return Promise.reject(error);
} }
) );

@ -1,18 +1,17 @@
import { serverUrl } from "./request"; import { serverUrl } from "./request";
export const extName = (str) => `${str}`;
export const extName = str => `${str}`;
/** /**
* 处理返回数据中的url字段 * 处理返回数据中的url字段
* @param {*} url 请求返回的图片url * @param {*} url 请求返回的图片url
*/ */
export const dalImageUrl = url => { export const dalImageUrl = (url) => {
if (url) { if (url) {
if (url.startsWith('http')) { if (url.startsWith("http")) {
return url; return url;
} }
return serverUrl + url; return serverUrl + url;
} }
return "https://hugo.bnblogs.cc/images/img/20220215001349.png"; return "https://hugo.bnblogs.cc/images/img/20220215001349.png";
} };

@ -1,21 +1,25 @@
<template> <template>
<div class="detail"> <div class="detail">
<nav-bar <nav-bar
:title="product.name" :title="product.name"
left-text="返回" left-text="返回"
left-arrow left-arrow
@click-left="onClickLeft" @click-left="onClickLeft"
/> />
<h1>{{ product.name }}</h1> <h1>{{ product.name }}</h1>
<div class="content" v-html="product.content"></div> <div class="content" v-html="product.content"></div>
<action-bar> <action-bar>
<action-bar-icon icon="chat-o" text="客服" @click="onClickIcon" /> <action-bar-icon icon="chat-o" text="客服" @click="onClickIcon" />
<action-bar-icon icon="cart-o" text="购物车" @click="onClickIcon" /> <action-bar-icon icon="cart-o" text="购物车" @click="onClickIcon" />
<action-bar-icon icon="shop-o" text="店铺" @click="onClickIcon" /> <action-bar-icon icon="shop-o" text="店铺" @click="onClickIcon" />
<action-bar-button type="danger" text="立即购买" @click="onClickButton" /> <action-bar-button
</action-bar> type="danger"
</div> text="立即购买"
@click="onClickButton"
/>
</action-bar>
</div>
</template> </template>
<script setup> <script setup>
@ -30,11 +34,11 @@ const router = useRouter();
const product = ref({}); const product = ref({});
loadProductByIdAPI(route.query.id).then((res) => { loadProductByIdAPI(route.query.id).then((res) => {
product.value = res.data; product.value = res.data;
}); });
const onClickIcon = () => {}; const onClickIcon = () => {};
const onClickButton = () => {}; const onClickButton = () => {};
const onClickLeft = () => { const onClickLeft = () => {
router.go(-1); // router.go(-1); //
}; };
</script> </script>

@ -21,7 +21,7 @@
:price="item.price.toFixed(2)" :price="item.price.toFixed(2)"
:title="item.name" :title="item.name"
:thumb="dalImageUrl(item.coverImage)" :thumb="dalImageUrl(item.coverImage)"
@click-thumb="toDetail(item.id)" @click-thumb="toDetail(item.id)"
/> />
</div> </div>
</template> </template>
@ -38,7 +38,7 @@ import { useCategories } from "../hooks/useCategories";
import { useProducts } from "../hooks/useProducts"; import { useProducts } from "../hooks/useProducts";
// //
const { products, onLoad} = useProducts(); const { products, onLoad } = useProducts();
onLoad(); onLoad();
// //
@ -54,14 +54,14 @@ const { categories } = useCategories();
// //
const router = useRouter(); const router = useRouter();
const toDetail = id => { const toDetail = (id) => {
router.push({ router.push({
name: 'Detail', name: "Detail",
query: { query: {
id, id,
} },
}) });
} };
</script> </script>
<style scoped></style> <style scoped></style>

@ -1,32 +1,32 @@
<template> <template>
<div class="list"> <div class="list">
<sidebar v-model="active"> <sidebar v-model="active">
<sidebar-item <sidebar-item
v-for="item in categories" v-for="item in categories"
:title="item.name" :title="item.name"
:key="item.id" :key="item.id"
:to="{ name: 'List', query: { tid: item.id } }" :to="{ name: 'List', query: { tid: item.id } }"
/> />
</sidebar> </sidebar>
<!-- @load="onLoad": 当loading和finished同时为false时执行--> <!-- @load="onLoad": 当loading和finished同时为false时执行-->
<list <list
class="products" class="products"
:loading="loading" :loading="loading"
:finished="finished" :finished="finished"
@load="onLoad" @load="onLoad"
finished-text="没有更多了" finished-text="没有更多了"
> >
<card <card
v-for="item in products" v-for="item in products"
:key="item.id" :key="item.id"
:num="item.amount" :num="item.amount"
:price="item.price.toFixed(2)" :price="item.price.toFixed(2)"
:title="item.name" :title="item.name"
:thumb="dalImageUrl(item.coverImage)" :thumb="dalImageUrl(item.coverImage)"
@click-thumb="toDetail(item.id)" @click-thumb="toDetail(item.id)"
/> />
</list> </list>
</div> </div>
</template> </template>
<script setup> <script setup>
@ -39,39 +39,39 @@ import { useProducts } from "../hooks/useProducts";
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
const { loading, finished, products, currentCategoryId, onLoad } = useProducts( const { loading, finished, products, currentCategoryId, onLoad } = useProducts(
route.query.tid route.query.tid
); );
// //
const { categories } = useCategories(); const { categories } = useCategories();
// //
const active = computed({ const active = computed({
// //
set(v) { set(v) {
return v; return v;
}, },
// //
get() { get() {
return categories.value.findIndex( return categories.value.findIndex(
(item) => item.id == currentCategoryId.value (item) => item.id == currentCategoryId.value
); );
}, },
}); });
// () // ()
onBeforeRouteUpdate((to, from) => { onBeforeRouteUpdate((to, from) => {
// currentCategoryId.value = to.query.tid; // currentCategoryId.value = to.query.tid;
// //
onLoad(true, to.query.tid); onLoad(true, to.query.tid);
}); });
const toDetail = (id) => { const toDetail = (id) => {
router.push({ router.push({
name: "Detail", name: "Detail",
query: { query: {
id, id,
}, },
}); });
}; };
// loadDataFromServer(); // loadDataFromServer();
@ -79,14 +79,14 @@ const toDetail = (id) => {
<style scoped> <style scoped>
.list { .list {
display: flex; display: flex;
} }
.list .van-sidebar { .list .van-sidebar {
width: 105px; width: 105px;
} }
.products { .products {
overflow: auto; overflow: auto;
} }
</style> </style>

@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

@ -0,0 +1,3 @@
{
"recommendations": ["Vue.volar"]
}

@ -0,0 +1,16 @@
# Vue 3 + TypeScript + Vite
This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
## Recommended IDE Setup
- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar)
## Type Support For `.vue` Imports in TS
Since TypeScript cannot handle type information for `.vue` imports, they are shimmed to be a generic Vue component type by default. In most cases this is fine if you don't really care about component prop types outside of templates. However, if you wish to get actual prop types in `.vue` imports (for example to get props validation when using manual `h(...)` calls), you can enable Volar's Take Over mode by following these steps:
1. Run `Extensions: Show Built-in Extensions` from VS Code's command palette, look for `TypeScript and JavaScript Language Features`, then right click and select `Disable (Workspace)`. By default, Take Over mode will enable itself if the default TypeScript extension is disabled.
2. Reload the VS Code window by running `Developer: Reload Window` from the command palette.
You can learn more about Take Over mode [here](https://github.com/johnsoncodehk/volar/discussions/471).

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + Vue + TS</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

File diff suppressed because it is too large Load Diff

@ -0,0 +1,21 @@
{
"name": "pinia-pre",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vue-tsc --noEmit && vite build",
"preview": "vite preview"
},
"dependencies": {
"pinia": "^2.0.22",
"vue": "^3.2.37"
},
"devDependencies": {
"@vitejs/plugin-vue": "^3.1.0",
"typescript": "^4.6.4",
"vite": "^3.1.0",
"vue-tsc": "^0.40.4"
}
}

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

@ -0,0 +1,40 @@
<template>
<h1>Hello</h1>
<hr />
<button @click="onHandleSub">-</button>
<span>{{ count }}</span>
<button @click="onHandlePlus">+</button>
<div class="padding-10"></div>
<button @click="onHandleAsyncPlus">异步+</button>
<HW />
</template>
<script setup lang="ts">
import { storeToRefs } from "pinia";
import useCounterStore from "./stores/counter";
import HW from "./components/HelloWorld.vue";
const store = useCounterStore();
const { count } = storeToRefs(store);
const onHandlePlus = () => {
store.plus();
};
const onHandleSub = () => {
store.sub();
};
const onHandleAsyncPlus = () => {
store.asyncPlus();
};
</script>
<style scoped>
span {
font-size: 20px;
padding: 0 15px;
}
.padding-10 {
padding-top: 10px;
}
</style>

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>

After

Width:  |  Height:  |  Size: 496 B

@ -0,0 +1,12 @@
<script setup lang="ts">
import { storeToRefs } from "pinia";
import useCounterStore from "../stores/counter";
const store = useCounterStore();
const {count} = storeToRefs(store);
</script>
<template>
<h3>这是Hello World组件数据: {{ count }}</h3>
</template>
<style scoped></style>

@ -0,0 +1,8 @@
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import { createPinia } from 'pinia'
const pinia = createPinia();
createApp(App).use(pinia).mount('#app')

@ -0,0 +1,47 @@
import { defineStore } from "pinia";
import { ref } from 'vue'
// 选项式api的写法
// export default defineStore('counter',{
// // 定义数据
// state: () => {
// return {
// count: 1,
// title: '标题',
// }
// },
// // 数据操作
// actions: {
// plus() {
// this.count++;
// },
// sub() {
// this.count--;
// },
// asyncPlus() {
// setTimeout(() => {
// this.count++;
// }, 1000);
// }
// }
// })
// 组合式api写法
export default defineStore('counter', () => {
const count = ref(0);
const plus = () => {
count.value ++;
};
const sub = () => {
count.value --;
};
const asyncPlus = () => {
setTimeout(() => {
count.value++;
}, 1000);
};
return {
count,plus,sub,asyncPlus,
}
});

@ -0,0 +1,7 @@
/// <reference types="vite/client" />
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}

@ -0,0 +1,18 @@
{
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"module": "ESNext",
"moduleResolution": "Node",
"strict": true,
"jsx": "preserve",
"sourceMap": true,
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"lib": ["ESNext", "DOM"],
"skipLibCheck": true
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
"references": [{ "path": "./tsconfig.node.json" }]
}

@ -0,0 +1,9 @@
{
"compilerOptions": {
"composite": true,
"module": "ESNext",
"moduleResolution": "Node",
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts"]
}

@ -0,0 +1,7 @@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()]
})

@ -2,13 +2,13 @@
<h1>列表</h1> <h1>列表</h1>
<hr /> <hr />
<div class="list"> <div class="list">
<router-link <router-link
:to="{ name: 'Detail', query: { id: item.id } }" :to="{ name: 'Detail', query: { id: item.id } }"
v-for="item in courses" v-for="item in courses"
:key="item.id" :key="item.id"
><li>{{ item.name }}</li></router-link
> >
<li>{{ item.name }}</li>
</router-link>
</div> </div>
</template> </template>

@ -4,13 +4,13 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { useRouter } from 'vue-router'; import { useRouter } from "vue-router";
const { replace } = useRouter(); const { replace } = useRouter();
const login = () => { const login = () => {
localStorage.setItem("token", "1111"); localStorage.setItem("token", "1111");
replace({ replace({
name: 'User', name: "User",
}) });
}; };
</script> </script>

@ -1,8 +1,8 @@
<template> <template>
<h1>用户页</h1> <h1>用户页</h1>
<router-link :to="{name: 'userInfo'}">个人信息</router-link> <router-link :to="{ name: 'userInfo' }">个人信息</router-link>
<router-link :to="{name: 'userScores'}">我的订单</router-link> <router-link :to="{ name: 'userScores' }">我的订单</router-link>
<router-link :to="{name: 'userOrders'}">我的积分</router-link> <router-link :to="{ name: 'userOrders' }">我的积分</router-link>
<hr /> <hr />
<router-view></router-view> <router-view></router-view>
</template> </template>

@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

@ -0,0 +1,3 @@
{
"recommendations": ["Vue.volar"]
}

@ -0,0 +1,7 @@
# Vue 3 + Vite
This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
## Recommended IDE Setup
- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar)

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + Vue</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>

File diff suppressed because it is too large Load Diff

@ -0,0 +1,21 @@
{
"name": "vuex-app",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"router": "^1.3.7",
"vue": "^3.2.37",
"vue-router": "^4.1.5",
"vuex": "^4.0.2"
},
"devDependencies": {
"@vitejs/plugin-vue": "^3.1.0",
"vite": "^3.1.0"
}
}

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

@ -0,0 +1,26 @@
<script setup>
import { useStore } from "vuex";
const store = useStore();
const handlePlus = () => {
store.commit("increment");
};
const handleSub = () => {
store.commit("subtraction");
};
</script>
<template>
<h3>{{ store.state.title }}</h3>
<button @click="handleSub">-</button>
<span>{{ store.state.count }}</span>
<button @click="handlePlus">+</button>
</template>
<style scoped>
span {
font-size: 20px;
padding: 0 10px;
font-weight: 600;
}
</style>

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>

After

Width:  |  Height:  |  Size: 496 B

@ -0,0 +1,5 @@
<script setup></script>
<template></template>
<style scoped></style>

@ -0,0 +1,7 @@
import { createApp } from "vue";
import "./style.css";
import App from "./App.vue";
import store from "./store";
createApp(App).use(store).mount("#app");

@ -0,0 +1,20 @@
import { createStore } from "vuex";
const store = createStore({
state() {
return {
count: 0,
title: "修改count值",
};
},
mutations: {
increment(state) {
state.count++;
},
subtraction(state) {
state.count--;
},
},
});
export default store;

@ -0,0 +1,90 @@
:root {
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
font-size: 16px;
line-height: 24px;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
}
a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
body {
margin: 0;
display: flex;
place-items: center;
min-width: 320px;
min-height: 100vh;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
}
button {
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}
.card {
padding: 2em;
}
#app {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
}

@ -0,0 +1,7 @@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()]
})
Loading…
Cancel
Save