nuxt3:基于vue3的服务端渲染框架。
服务端渲染解决的问题:1、搜索引擎优化(seo)2、首屏优化。
1、创建Nuxt项目:
终端中输入npx nuxi init <project-name>
安装依赖:npm i
运行项目:npm run dev。
注*:node 版本要 > 16.11*。
目录结构:
启动成功页面:
2、写一个商品加入购物车的demo。
编辑器打开项目:app.vue里面的 <NuxtWelcome />就是启动页,这个组件是内置的(目录中找不到),删掉即可。app.vue是Nuxt应用程序的主要组件,添加到里面的东西都是全局的,包含在每个页面中。这里我们不需要这个文件,删掉即可。
根目录下新建pages文件夹。新建两个文件。 根目录下新建layouts文件夹,新建default.vue文件。
layouts:是一个自定义的布局框架,可在整个应用使用。也可以指定页面使用。
注:nuxt是约定式路由,按照官方规定的目录结构去创建文件,会自动生成路由,不需要我们去写路由文件。
layouts/default.vue:
<template>
<div>
<header>
<nuxt-link to="/">
<h1>商品列表</h1>
</nuxt-link>
<nuxt-link to="cart">
<h1>购物车</h1>
</nuxt-link>
</header>
<div>
<slot />
</div>
</div>
</template>
看下效果:
改下样式,用下taiwindcss:
1、下载npm install --save-dev @nuxtjs/tailwindcss。 2、nuxt.config.ts配置
modules: [
'@nuxtjs/tailwindcss'
]
})
3、npx tailwindcss init 创建一个tailwind.config.js文件,可以配置全局的一些样式,具体去看官网。(修改配置文件要重启哦~) tailwind.confit.js:
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [],
theme: {
extend: {
colors: {
primary: '#270A4B',
secondary:'#f08200',
dark: '#333843',
},
fontFamily: {
sans: [ '"Noto Sans"'],
}
},
},
plugins: [],
}
4、根目录新建assets/css/tailwind.css assets/css/tailwind.css:
@tailwind base;
@tailwind components;
@tailwind utilities;
body {
@apply bg-dark;
}
.wrapper {
@apply my-8 max-w-5xl mx-auto;
}
5、使用:layouts/default.vue:
<template>
<div>
<header class="wrapper flex justify-between">
<nuxt-link class="text-secondary text-5xl" to="/">
<h1>商品列表</h1>
</nuxt-link>
<nuxt-link to="cart">
<span class=" text-secondary text-5xl">购物车</span>
</nuxt-link>
</header>
<div>
<slot />
</div>
</div>
</template>
写页面: 1、根目录新建一个data/db.json随便写几条数据,模拟数据,实际开发中是接口请求来的数据,新建public/img 存放造的数据要用到的图片。 注:可以使用json-server来模拟数据库接口,本文直接用的假数据,json-server使用可参考:juejin.cn/post/717949…
注*:public/目录直接在服务器根部提供服务,包含必须保持其名称(如 robots.txt)或可能不会改变的公共文件(如 favicon.ico)。*
2、pages/index.vue
<template>
<div>
<h2 class="text-white text-2xl text-center my-8">Products</h2>
<div class="grid grid-cols-2 gap-7">
<div v-for="product in products" :key="product.id">
<ProductCard :product="product" />
</div>
</div>
</div>
</template>
<script setup>
import { products } from '../data/db.json';
</script>
<style scoped></style>
注: <ProductCard />是个组件,渲染每个商品。在 components/ProductCard.vue文件中。通过defineProps(['product']);接收父组件传过来的值。
3、pages/cart.vue:
<template>
<div>
<h2 class="text-white text-2xl text-center my-8">购物车</h2>
<div v-for="p in cart" :key="p.id" class="flex items-center gap-8">
<img :src="p.img" :alt="p.title">
<p class="text-white">{{ p.title }}</p>
<p class="text-white">{{ p.price * p.quantity}} coins</p>
</div>
</div>
</template>
<script setup>
import { cart } from '../data/db.json';
</script>
<style scoped>
</style>
以上是布局样式.
下一步是利用pinia管理购物车数据,实现购物车数据的增删改查。
1、安装: npm i @pinia/nuxt --legacy-peer-deps。npm版本较高时要加 --legacy-peer-deps。
2、配置:nuxt.config.ts:
modules: [
'@nuxtjs/tailwindcss',
'@pinia/nuxt',
],
3、新建:store/cartStore.vue
import { defineStore } from "pinia";
import { cart } from "@/data/db.json";
export const useCartStore = defineStore("cart", {
state: () => ({
cart: [],
}),
actions: {
async getCart() {
const data = cart;
this.cart = data;
},
// 从购物车删除
async deleteFromCart(product) {
this.cart = this.cart.filter((p) => {
return p.id !== product.id;
});
// 请求删除接口更新数据库
// await $fetch('http://xxxxx' + product.id, {
// method: 'delete'
// })
},
// 增加商品数量
async incQuantity(product) {
let updataedProduct;
this.cart = this.cart.map((p) => {
if (p.id === product.id) {
p.quantity++;
updataedProduct = p;
}
return p;
});
// 请求接口增加商品数量
// await $fetch('http://xxxxx' + product.id, {
// method: 'put',
// body: JSON.stringify(updatedProduct)
// })
},
// 减少商品数量
async decQuantity(product) {
let updatedProduct;
this.cart = this.cart.map((p) => {
if (p.id === product.id && p.quantity > 1) {
p.quantity--;
updatedProduct = p;
}
return p;
});
// 减少商品数量接口
// if (updatedProduct) {
// await $fetch('http://xxxx' + product.id, {
// method: 'put',
// body: JSON.stringify(updatedProduct)
// })
// }
},
// 加入购物车
async addToCart(product) {
// 购物车中是否存在此商品
const exists = this.cart.find((p) => p.id === product.id);
// 存在则数量 +1
if (exists) {
this.incQuantity(product);
}
// 不存在增加
if (!exists) {
this.cart.push({ ...product, quantity: 1 });
// 加入购物车接口请求更新数据库
// await $fetch('http://xxxxx', {
// method: 'post',
// body: JSON.stringify({...product, quantity: 1})
// })
}
},
},
});
4、页面中使用pinia:
(1)引入:import { useCartStore } from '@/stores/cartStore';
(2)使用:useCartStore().cart