<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	
	xmlns:georss="http://www.georss.org/georss"
	xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#"
	>

<channel>
	<title>Web &#8211; Blog of Code</title>
	<atom:link href="https://www.cztcode.com/category/web-build/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.cztcode.com</link>
	<description></description>
	<lastBuildDate>Mon, 27 Nov 2023 07:03:10 +0000</lastBuildDate>
	<language>zh-Hans</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://www.cztcode.com/wp-content/uploads/2024/02/cropped-logo-32x32.webp</url>
	<title>Web &#8211; Blog of Code</title>
	<link>https://www.cztcode.com</link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">217219486</site>	<item>
		<title>Next.js项目初始化配置</title>
		<link>https://www.cztcode.com/2023/5073/</link>
					<comments>https://www.cztcode.com/2023/5073/#respond</comments>
		
		<dc:creator><![CDATA[Jellow]]></dc:creator>
		<pubDate>Tue, 17 Oct 2023 09:31:48 +0000</pubDate>
				<category><![CDATA[next.js]]></category>
		<guid isPermaLink="false">https://www.cztcode.com/?p=5073</guid>

					<description><![CDATA[记录使用next.js(app router)+tailwind+typestript+prisma+trpc+tanstack+shadcn/ui项目初始化结构]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>记录下next.js全栈项目初始化需要的组件</p>
<ol>
<li>next.js (app router)</li>
<li>tailwind</li>
<li>typescript</li>
<li>prisma</li>
<li>trpc</li>
<li>tanstack</li>
<li>shadcn/ui</li>
</ol>
<h2>使用pnpm初始化next.js</h2>
<pre><code class="language-bash">pnpm dlx create-next-app@latest</code></pre>
<p>起好项目名字后全部默认就可以</p>
<pre><code class="language-bash">(base) ➜  ~ pnpm dlx create-next-app@latest
Packages: +1
+
Progress: resolved 1, reused 0, downloaded 1, added 1, done
✔ What is your project named? … demo
✔ Would you like to use TypeScript? … No / Yes
✔ Would you like to use ESLint? … No / Yes
✔ Would you like to use Tailwind CSS? … No / Yes
✔ Would you like to use `src/` directory? … No / Yes
✔ Would you like to use App Router? (recommended) … No / Yes
✔ Would you like to customize the default import alias (@/*)? … No / Yes</code></pre>
<h2>使用eslint和prettier</h2>
<p>一、安装eslint + prettier + eslint-plugin-prettier</p>
<pre><code class="language-bash">pnpm i eslint prettier eslint-plugin-prettier eslint-config-prettier prettier-plugin-tailwindcss -D</code></pre>
<p>二、配置.eslintrc.json</p>
<pre><code class="language-tsx">{
  &quot;extends&quot;: [
    &quot;next/core-web-vitals&quot;,
    &quot;eslint:recommended&quot;,
    &quot;plugin:prettier/recommended&quot;
  ],
  // 这个是nextjs官网推荐的写法
  &quot;env&quot;: {
    &quot;es2020&quot;:true,
    &quot;es6&quot;: true,
    &quot;node&quot;: true
  },
  &quot;plugins&quot;: [
    &quot;prettier&quot;
  ],
  &quot;rules&quot;: {
    &quot;prettier/prettier&quot;: &quot;warn&quot;
  }
}</code></pre>
<p>三、新建.prettierrc.js，注意名字别打错了</p>
<pre><code class="language-tsx">module.exports = {
  // 基础配置
  singleQuote: false, // 使用双引号
  printWidth: 100, // 设置行宽度为100，稍微宽一点可能更适合现代屏幕
  semi: true, // 使用分号
  trailingComma: &#039;all&#039;, // 在多行输入的尾逗号处添加一个逗号

  // TypeScript相关配置
  arrowParens: &#039;always&#039;, // 箭头函数参数始终使用括号，有助于代码清晰
  bracketSpacing: true, // 在对象字面量声明所使用的的大括号内部添加空格

  // 与编辑器和其他工具集成
  useTabs: false, // 使用空格替代Tab
  tabWidth: 2, // 设置tab宽度为2

  // 其他配置
  proseWrap: &#039;always&#039;, // 总是折行，适用于Markdown等
  htmlWhitespaceSensitivity: &#039;css&#039;, // 尊重CSS中的空白字符
  plugins: [&#039;prettier-plugin-tailwindcss&#039;],
};
</code></pre>
<p>手动格式化</p>
<pre><code class="language-bash"> prettier --write &quot;src/**/*.{js,jsx,ts,tsx}&quot;    </code></pre>
<p>添加到package.json</p>
<pre><code class="language-bash"> &quot;prettier&quot;: &quot;prettier --write \&quot;src/**/*.{js,jsx,ts,tsx}\&quot;&quot;</code></pre>
<p>推荐开启保存自动格式化</p>
<p><img decoding="async" src="https://markdown.cztcode.com/ccc2ffb497138a58eca75f94fc5c6b3a.png" alt="image-20231017165849028" /></p>
<h2>安装husky</h2>
<p>husky负责实现在git提交前检查规范</p>
<pre><code class="language-bash">pnpm dlx husky-init &amp;&amp; pnpm install</code></pre>
<p>运行husky初始化，上面的脚本会帮我们添加一个prepare指令</p>
<pre><code class="language-bash"> pnpm run prepare   </code></pre>
<h3>修改配置</h3>
<p>把.husky/pre-commit 修改为</p>
<pre><code class="language-bash">pnpm run prettier
pnpm run lint</code></pre>
<p>记得把.husky添加到git</p>
<h2>安装commitlint</h2>
<p>commitlint可以让提交信息更规范</p>
<pre><code class="language-bash"> pnpm install  -D @commitlint/{config-conventional,cli}       </code></pre>
<p>初始化</p>
<pre><code class="language-bash">echo &quot;module.exports = {extends: [&#039;@commitlint/config-conventional&#039;]}&quot; &gt; commitlint.config.js</code></pre>
<p>把commitlint添加进husky</p>
<pre><code class="language-bash"> pnpm dlx husky add .husky/commit-msg  &#039;npx --no -- commitlint --edit ${1}&#039;</code></pre>
<p>记得把commitlint.config.js添加到git</p>
<h2>安装prisma</h2>
<p>prisma 是nextjs中热门的ORM组件</p>
<pre><code class="language-bash">pnpm dlx prisma  </code></pre>
<p>初始化prisma</p>
<pre><code class="language-bash"> pnpm dlx prisma init  </code></pre>
<p>在.env文件中更改数据库链接字符串DATABASE_URL，小项目建议去Mongodb Atlas</p>
<p>模型定义在prisma/schema.prisma，这里我给出mongodb的配置和一些简单类型</p>
<pre><code class="language-tsx">generator client {
  provider = &quot;prisma-client-js&quot;
  output   = &quot;./client&quot; // 如果写了这个就不用配置webstorm排除目录了
}

datasource db {
  provider     = &quot;mongodb&quot;
  url          = env(&quot;DATABASE_URL&quot;)
  relationMode = &quot;prisma&quot;
}

model Post {
  id       String    @id @default(auto()) @map(&quot;_id&quot;) @db.ObjectId
  slug     String    @unique
  title    String
  body     String
  author   User      @relation(fields: [authorId], references: [id])
  authorId String    @db.ObjectId
  comments Comment[]
}

model User {
  id      String   @id @default(auto()) @map(&quot;_id&quot;) @db.ObjectId
  email   String   @unique
  name    String?
  address Address?
  posts   Post[]
}

model Comment {
  id      String @id @default(auto()) @map(&quot;_id&quot;) @db.ObjectId
  comment String
  post    Post   @relation(fields: [postId], references: [id])
  postId  String @db.ObjectId
}

// Address is an embedded document
type Address {
  street String
  city   String
  state  String
  zip    String
}
</code></pre>
<p>prisma会生成client便于类型提示，在你更改完schema.prisma后要运行</p>
<pre><code class="language-bash">pnpm dlx prisma generate</code></pre>
<p>在修改表后，还要运行push指令同步到数据库</p>
<pre><code class="language-bash">pnpm dlx prisma db push</code></pre>
<p>使用studio指令查看数据库表</p>
<pre><code class="language-bash">pnpm dlx prisma studio  </code></pre>
<p>如果你使用的是webstorm，注意要把这个文件夹标记为不排除，因为node_module这里webstorm默认不会生成索引，当你使用<code>prisma generate</code>后会动态生成新的代码，而由于webstorm默认不生成索引，你就不会得到ts的代码提示。</p>
<p>排除了就会重新索引这个文件，具体路径</p>
<pre><code class="language-bash">/node_modules/.pnpm/@prisma+client@5.4.2/node_modules/.prisma</code></pre>
<p><img decoding="async" src="https://markdown.cztcode.com/d64f5bd5742d6b9422c01f78cd7482f2.png" alt="image-20231017155450168" /></p>
<p>创建一个prisma客户端实例化代码，这段代码会在开发环境复用client实例（避免next的热更新造成重复创建实例）。</p>
<pre><code class="language-tsx">import { PrismaClient } from &quot;@prisma/client&quot;;

const prismaClientSingleton = () =&gt; {
  return new PrismaClient();
};

type PrismaClientSingleton = ReturnType&lt;typeof prismaClientSingleton&gt;;

const globalForPrisma = globalThis as unknown as {
  prisma: PrismaClientSingleton | undefined;
};

const prisma = globalForPrisma.prisma ?? prismaClientSingleton();

export default prisma;

if (process.env.NODE_ENV !== &quot;production&quot;) globalForPrisma.prisma = prisma;</code></pre>
<h2>配置shadcn/ui</h2>
<p>shadcn是一个开源的，可定制化很高的组件库，与传统的导入整个组件库不同，shadcn/ui会精确导入你使用的组件，并且你可以直接进一步修改这些组件，就像是自己写的一样。</p>
<p><a href="https://ui.shadcn.com/" target="_blank" rel="noopener">https://ui.shadcn.com/</a></p>
<pre><code class="language-bash">pnpm dlx shadcn-ui@latest init</code></pre>
<p>除了tailwind.config.js需要改成ts，其他都用默认</p>
<pre><code class="language-bash">Progress: resolved 198, reused 198, downloaded 0, added 198, done
✔ Would you like to use TypeScript (recommended)? … no / yes
✔ Which style would you like to use? › Default
✔ Which color would you like to use as base color? › Zinc
✔ Where is your global CSS file? … app/globals.css
✔ Would you like to use CSS variables for colors? … no / yes
✔ Where is your tailwind.config.js located? … tailwind.config.ts
✔ Configure the import alias for components: … @/components
✔ Configure the import alias for utils: … @/lib/utils
✔ Are you using React Server Components? … no / yes
✔ Write configuration to components.json. Proceed? … yes
</code></pre>
<p>需要任何组件从这里找https://ui.shadcn.com/docs/components/</p>
<p>文档里有写每个组件如何安装</p>
<pre><code class="language-bash">pnpx dlx shadcn-ui@latest add xxx</code></pre>
<p>之后正常在page中使用即可</p>
<h2>使用trpc</h2>
<pre><code class="language-bash">pnpm add @trpc/server @trpc/client  @trpc/react-query   </code></pre>
<p>创建trpc文件夹，然后分别创建client.ts，init.ts，index.ts</p>
<p>client.ts</p>
<pre><code class="language-tsx">import { AppRouter } from &quot;@/trpc&quot;;
import { createTRPCReact } from &quot;@trpc/react-query&quot;;

export const trpc = createTRPCReact&lt;AppRouter&gt;({});
</code></pre>
<p>index.ts 这里放端点，我还使用了zod动态验证数据格式，你可以安装pnpm install zod</p>
<p>下面写了一个创建新用户的例子</p>
<pre><code class="language-ts">import db from &quot;@/lib/prisma&quot;;
import { z } from &quot;zod&quot;;
import { publicProcedure, router } from &quot;@/trpc/init&quot;;

export const appRouter = router({
  createUser: publicProcedure
    .input(
      z.object({
        name: z.string(),
        email: z.string(),
      }),
    )
    .query(async ({ input }) =&gt; {
      await db.user.create({
        data: {
          name: input.name,
          email: input.email,
        },
      });
      return { success: true };
    }),
});

// Export type router type signature,
// NOT the router itself.
export type AppRouter = typeof appRouter;
</code></pre>
<p>init.ts 在这里你可以定义公开procedure，或者利用middleware创建私有的</p>
<pre><code class="language-ts">import { initTRPC } from &quot;@trpc/server&quot;;

/**
 * Initialization of tRPC backend
 * Should be done only once per backend!
 */
const t = initTRPC.create();

/**
 * Export reusable router and procedure helpers
 * that can be used throughout the router
 */
export const router = t.router;
export const publicProcedure = t.procedure;
</code></pre>
<p>给一个使用kinde的例子</p>
<pre><code class="language-ts">import { getKindeServerSession } from &#039;@kinde-oss/kinde-auth-nextjs/server&#039;
import { TRPCError, initTRPC } from &#039;@trpc/server&#039;

const t = initTRPC.create()
const middleware = t.middleware

const isAuth = middleware(async (opts) =&gt; {
  const { getUser } = getKindeServerSession()
  const user = getUser()

  if (!user || !user.id) {
    throw new TRPCError({ code: &#039;UNAUTHORIZED&#039; })
  }

  return opts.next({
    ctx: {
      userId: user.id,
      user,
    },
  })
})

export const router = t.router
export const publicProcedure = t.procedure
export const privateProcedure = t.procedure.use(isAuth)
</code></pre>
<p>推荐使用tanstack帮助trpc进行请求状态管理</p>
<p><a href="https://tanstack.com/query/latest/docs/react/overview" target="_blank" rel="noopener">https://tanstack.com/query/latest/docs/react/overview</a></p>
<p>安装tanstack</p>
<pre><code class="language-bash">pnpm add @tanstack/react-query</code></pre>
<p>具体使用方法推荐查看官网</p>
<p>现在需要创建一个Provider，把trpc与tanstack结合，在conponents文件夹下</p>
<pre><code class="language-ts">&quot;use client&quot;;

import { PropsWithChildren, useState } from &quot;react&quot;;
import { QueryClient, QueryClientProvider } from &quot;@tanstack/react-query&quot;;
import { httpBatchLink } from &quot;@trpc/client&quot;;
import { trpc } from &quot;@/trpc/client&quot;;

const Providers = ({ children }: PropsWithChildren) =&gt; {
  const [queryClient] = useState(() =&gt; new QueryClient());
  const [trpcClient] = useState(() =&gt;
    trpc.createClient({
      links: [
        httpBatchLink({
          url: &quot;http://localhost:3000/api/trpc&quot;,
        }),
      ],
    }),
  );
  return (
    &lt;trpc.Provider queryClient={queryClient} client={trpcClient}&gt;
      &lt;QueryClientProvider client={queryClient}&gt;{children}&lt;/QueryClientProvider&gt;
    &lt;/trpc.Provider&gt;
  );
};

export default Providers;</code></pre>
<p>最后在最父层layout.tsx中把里面用Provider，你就可以在任何地方使用了</p>
<pre><code class="language-tsx">import type { Metadata } from &quot;next&quot;;
import { Inter } from &quot;next/font/google&quot;;
import &quot;./globals.css&quot;;
import React from &quot;react&quot;;
import Providers from &quot;@/components/Providers&quot;;

const inter = Inter({ subsets: [&quot;latin&quot;] });

export const metadata: Metadata = {
  title: &quot;Create Next App&quot;,
  description: &quot;Generated by create next app&quot;,
};

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    &lt;html lang=&quot;en&quot;&gt;
      &lt;Providers&gt;
        &lt;body className={inter.className}&gt;{children}&lt;/body&gt;
      &lt;/Providers&gt;
    &lt;/html&gt;
  );
}
</code></pre>
<p>一个项目的初始化就完成啦</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.cztcode.com/2023/5073/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">5073</post-id>	</item>
		<item>
		<title>前端项目部署方法</title>
		<link>https://www.cztcode.com/2023/4277/</link>
					<comments>https://www.cztcode.com/2023/4277/#comments</comments>
		
		<dc:creator><![CDATA[Jellow]]></dc:creator>
		<pubDate>Sun, 19 Feb 2023 11:25:36 +0000</pubDate>
				<category><![CDATA[Web]]></category>
		<guid isPermaLink="false">https://www.cztcode.com/?p=4277</guid>

					<description><![CDATA[介绍如何将Vue/React等前端项目部署到服务器上。除了必须的服务器外，有域名和SSL证书访问会更方便。]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div>
<p>介绍如何将Vue/React等前端项目部署到服务器上。除了必须的服务器外，有域名和SSL证书访问会更方便。</p>



<h2 class="wp-block-heading">项目打包</h2>



<p>以React项目为例，首先运行npm run build 生成build文件夹</p>



<p>React 打包后通常会做以下几个优化：</p>



<ol class="wp-block-list">
<li>代码压缩：将代码中的无用空格、注释等内容删除，减小文件体积，加快页面加载速度。</li>



<li>Tree shaking：从代码中剔除未使用的模块，以减少打包后的文件大小。</li>



<li>按需加载：将页面上的不同部分分割成不同的代码块，按需加载，提高页面的响应速度。</li>



<li>代码分割：将代码拆分成多个小块，使得每个页面只加载必要的代码，而非整个应用程序的全部代码，提高页面加载速度。</li>



<li>缓存：使用缓存技术来避免重复请求已经请求过的数据，从而提高应用程序的性能。</li>



<li>代码优化：对代码进行一些细节上的优化，如避免使用不必要的循环或函数调用，以提高代码执行效率。</li>
</ol>



<p>总的来说，React 打包后的优化目的是减小文件大小、提高加载速度和执行效率，从而提高用户的体验。</p>



<h2 class="wp-block-heading">Nginx进行反向代理</h2>



<h3 class="wp-block-heading">什么是反向代理？</h3>



<p>反向代理的主要区别在于代理的对象不同。在正向代理中，客户端通过代理服务器来访问其他服务器。而在反向代理中，代理服务器位于后端服务器之前，客户端不会直接与后端服务器通信，而是通过代理服务器来访问后端服务器。</p>



<p>具体来说，反向代理服务器在收到客户端请求后，会根据配置的策略和算法，将请求转发到后端服务器上，并将后端服务器的响应返回给客户端。客户端并不知道请求是由代理服务器转发到后端服务器上处理的，因为代理服务器会将自己的IP地址和端口隐藏在请求头中，而不是将客户端的真实IP地址发送到后端服务器。</p>



<p>使用反向代理的优势在于，它可以为后端服务器提供了一个额外的保护层，并且可以轻松地实现负载均衡、缓存优化、安全控制等功能。反向代理的核心思想就是代理服务器充当了客户端与后端服务器之间的中介，使得后端服务器更加安全、稳定和高效。</p>



<ol class="wp-block-list">
<li>安装 Nginx：安装并启动 Nginx。</li>



<li>配置 Nginx：编辑 Nginx 配置文件（通常位于 <code>/etc/nginx/nginx.conf</code>），在 <code>http</code> 块中添加以下代码：</li>
</ol>



<pre class="wp-block-preformatted">&nbsp;bashCopy code<br>&nbsp;server {<br>&nbsp; &nbsp;  listen 80;<br>&nbsp; &nbsp;  server_name example.com; # 填写你的域名或 IP<br>&nbsp; &nbsp;  root /path/to/your/react-project/build; # 填写你的 React 项目构建后的静态文件所在目录<br>&nbsp; &nbsp;  index index.html;<br>&nbsp; &nbsp;  location / {<br>&nbsp; &nbsp; &nbsp; &nbsp;  try_files $uri $uri/ /index.html; # 使得所有路由都指向 index.html 文件<br>&nbsp; &nbsp;  }<br>&nbsp;}</pre>



<p>这个配置文件将 Nginx 监听 80 端口，把所有的请求都转发到 React 项目构建后的静态文件中。其中 <code>location /</code> 的配置将使得所有的路由都指向 <code>index.html</code> 文件，这样可以避免出现 404 错误。</p>



<ol class="wp-block-list">
<li>重新加载 Nginx 配置：在终端中运行 <code>sudo nginx -t</code> 命令检查 Nginx 配置文件是否正确，如果正确，运行 <code>sudo service nginx reload</code> 命令重新加载配置文件。</li>



<li>访问 React 应用：在浏览器中访问你的 IP 地址，应该能够看到 React 应用的首页了</li>
</ol>



<p>这里提供一些Nginx常见指令</p>



<ol class="wp-block-list">
<li>nginx 启动</li>



<li>nginx -s stop 快速停止</li>



<li>nginx -s quit 优雅关闭，在退出前完成已经接受的连接请求</li>



<li>nginx -s reload 重新加载配置</li>
</ol>



<h2 class="wp-block-heading">配置域名和证书</h2>



<p>腾讯云，阿里云还是其他云厂商都差不多，这里以腾讯云为例。</p>



<ol class="wp-block-list">
<li>进入DNS控制台，添加一条A记录，内容是服务器的IP。注意放行80端口和443端口。</li>
</ol>



<figure class="wp-block-image"><img decoding="async" src="https://markdown.cztcode.com/image-20230219191513537.png" alt="image-20230219191513537"/></figure>



<ol class="wp-block-list" start="2">
<li>申请SSL证书，用免费的就好</li>
</ol>



<figure class="wp-block-image"><img decoding="async" src="https://markdown.cztcode.com/image-20230219191814296.png" alt="image-20230219191814296"/></figure>



<ol class="wp-block-list" start="3">
<li>下载Nginx证书，将crt和key文件上传到服务器上，然后按照下图路径配置/etc/nginx/nginx.conf，我这里还进行了跨域设置。</li>
</ol>



<pre class="wp-block-preformatted">&nbsp;server {<br>&nbsp; &nbsp; &nbsp; #SSL 默认访问端口号为 443<br>&nbsp; &nbsp; &nbsp;  listen 443 ssl;<br>&nbsp; &nbsp; &nbsp; # listen 65535 ssl; <br>&nbsp; &nbsp; &nbsp; #请填写绑定证书的域名<br>&nbsp; &nbsp; &nbsp; server_name api.nanqiuu.dailymoments.site; <br>&nbsp; &nbsp; &nbsp; #请填写证书文件的相对路径或绝对路径<br>&nbsp; &nbsp; &nbsp; ssl_certificate nanqiuu/api.nanqiuu.dailymoments.site_bundle.crt; <br>&nbsp; &nbsp; &nbsp; #请填写私钥文件的相对路径或绝对路径<br>&nbsp; &nbsp; &nbsp; ssl_certificate_key nanqiuu/api.nanqiuu.dailymoments.site.key; <br>&nbsp; &nbsp; &nbsp; ssl_session_timeout 5m;<br>&nbsp; &nbsp; &nbsp; #请按照以下协议配置<br>&nbsp; &nbsp; &nbsp; ssl_protocols TLSv1.2 TLSv1.3; <br>&nbsp; &nbsp; &nbsp; #请按照以下套件配置，配置加密套件，写法遵循 openssl 标准。<br>&nbsp; &nbsp; &nbsp; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; <br>&nbsp; &nbsp; &nbsp; ssl_prefer_server_ciphers on;<br>&nbsp; &nbsp; &nbsp; add_header Access-Control-Allow-Origin $http_origin; <br>&nbsp; &nbsp;  add_header Access-Control-Allow-Credentials true;<br>&nbsp;   add_header Access-Control-Allow-Methods *;<br>&nbsp; # &nbsp; 预检命令的缓存，如果不缓存每次会发送两次请求<br>&nbsp; &nbsp;  add_header Access-Control-Max-Age 3600;<br>&nbsp; add_header Access-Control-Allow-Headers <br>&nbsp; &nbsp;  $http_access_control_request_headers;<br>&nbsp;​<br>&nbsp; &nbsp;  # &nbsp; OPTIONS预检命令，预检命令通过时才发送请求<br>&nbsp; &nbsp;  # &nbsp; 检查请求的类型是不是预检命令<br>&nbsp; &nbsp;  if ($request_method = OPTIONS){<br>&nbsp; &nbsp; &nbsp; &nbsp;  return 200;<br>&nbsp; &nbsp;  }<br>&nbsp; &nbsp; &nbsp; location / {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; #网站主页路径。此路径仅供参考，具体请您按照实际目录操作。<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; #例如，您的网站主页在 Nginx 服务器的 /etc/www 目录下，则请修改 root 后面的 html 为 /etc/www。<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; root html; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; index  index.html index.htm;<br>&nbsp;  proxy_pass http://127.0.0.1:65535; <br>&nbsp; &nbsp; &nbsp; }<br>&nbsp; }</pre>



<p>配置完成后访问域名测试下能不能正常显示</p>



<h2 class="wp-block-heading">webstorm进行快速上传</h2>



<p>新建部署服务器</p>



<figure class="wp-block-image"><img decoding="async" src="https://markdown.cztcode.com/image-20230219192035355.png" alt="image-20230219192035355"/></figure>



<figure class="wp-block-image"><img decoding="async" src="https://markdown.cztcode.com/image-20230219192101308.png" alt="image-20230219192101308"/></figure>



<p>将build路径映射到服务器build路径</p>



<figure class="wp-block-image"><img decoding="async" src="https://markdown.cztcode.com/image-20230219192141023.png" alt="image-20230219192141023"/></figure>



<p>以后部署的时候只需要这样即可快速部署</p>



<figure class="wp-block-image"><img decoding="async" src="https://markdown.cztcode.com/image-20230219192210280.png" alt="image-20230219192210280"/></figure>



<p><strong>大功告成</strong></p>



<p>除此之外还可以使用自动化进行部署，自动拉取github的代码，以后更新～</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.cztcode.com/2023/4277/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">4277</post-id>	</item>
		<item>
		<title>VUE项目搭建规范</title>
		<link>https://www.cztcode.com/2023/4275/</link>
					<comments>https://www.cztcode.com/2023/4275/#respond</comments>
		
		<dc:creator><![CDATA[Jellow]]></dc:creator>
		<pubDate>Wed, 04 Jan 2023 10:29:47 +0000</pubDate>
				<category><![CDATA[Vue]]></category>
		<guid isPermaLink="false">https://www.cztcode.com/?p=4275</guid>

					<description><![CDATA[转自coderwhy，写项目按照这个来啦！]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div>
<p>转自：coderwhy，写项目按照这个来啦！</p>



<h2 class="wp-block-heading">一. 代码规范</h2>



<h3 class="wp-block-heading">1.1. 集成editorconfig配置</h3>



<p>EditorConfig 有助于为不同 IDE 编辑器上处理同一项目的多个开发人员维护一致的编码风格。</p>



<pre class="wp-block-preformatted">&nbsp;# http://editorconfig.org<br>&nbsp;​<br>&nbsp;root = true<br>&nbsp;​<br>&nbsp;[*] # 表示所有文件适用<br>&nbsp;charset = utf-8 # 设置文件字符集为 utf-8<br>&nbsp;indent_style = space # 缩进风格（tab | space）<br>&nbsp;indent_size = 2 # 缩进大小<br>&nbsp;end_of_line = lf # 控制换行类型(lf | cr | crlf)<br>&nbsp;trim_trailing_whitespace = true # 去除行首的任意空白字符<br>&nbsp;insert_final_newline = true # 始终在文件末尾插入一个新行<br>&nbsp;​<br>&nbsp;[*.md] # 表示仅 md 文件适用以下规则<br>&nbsp;max_line_length = off<br>&nbsp;trim_trailing_whitespace = false</pre>



<p>VSCode需要安装一个插件：EditorConfig for VS Code</p>



<figure class="wp-block-image"><img decoding="async" src="https://markdown.cztcode.com/008i3skNgy1gsq2gh989yj30pj05ggmb.jpg" alt="image-20210722215138665"/></figure>



<h3 class="wp-block-heading">1.2. 使用prettier工具</h3>



<p>Prettier 是一款强大的代码格式化工具，支持 JavaScript、TypeScript、CSS、SCSS、Less、JSX、Angular、Vue、GraphQL、JSON、Markdown 等语言，基本上前端能用到的文件格式它都可以搞定，是当下最流行的代码格式化工具。</p>



<p>1.安装prettier</p>



<pre class="wp-block-preformatted">&nbsp;npm install prettier -D</pre>



<p>2.配置.prettierrc文件：</p>



<ul class="wp-block-list">
<li>useTabs：使用tab缩进还是空格缩进，选择false；</li>



<li>tabWidth：tab是空格的情况下，是几个空格，选择2个；</li>



<li>printWidth：当行字符的长度，推荐80，也有人喜欢100或者120；</li>



<li>singleQuote：使用单引号还是双引号，选择true，使用单引号；</li>



<li>trailingComma：在多行输入的尾逗号是否添加，设置为 <code>none</code>；</li>



<li>semi：语句末尾是否要加分号，默认值true，选择false表示不加；</li>
</ul>



<pre class="wp-block-preformatted">&nbsp;{<br>&nbsp; &nbsp;"useTabs": false,<br>&nbsp; &nbsp;"tabWidth": 2,<br>&nbsp; &nbsp;"printWidth": 80,<br>&nbsp; &nbsp;"singleQuote": true,<br>&nbsp; &nbsp;"trailingComma": "none",<br>&nbsp; &nbsp;"semi": false<br>&nbsp;}</pre>



<p>3.创建.prettierignore忽略文件</p>



<pre class="wp-block-preformatted">&nbsp;/dist/*<br>&nbsp;.local<br>&nbsp;.output.js<br>&nbsp;/node_modules/**<br>&nbsp;​<br>&nbsp;**/*.svg<br>&nbsp;**/*.sh<br>&nbsp;​<br>&nbsp;/public/*</pre>



<p>4.VSCode需要安装prettier的插件</p>



<figure class="wp-block-image"><img decoding="async" src="https://markdown.cztcode.com/008i3skNgy1gsq2acx21rj30ow057mxp.jpg" alt="image-20210722214543454"/></figure>



<p>5.测试prettier是否生效</p>



<ul class="wp-block-list">
<li>测试一：在代码中保存代码；</li>



<li>测试二：配置一次性修改的命令；</li>
</ul>



<p>在package.json中配置一个scripts：</p>



<pre class="wp-block-preformatted">&nbsp; &nbsp; &nbsp;"prettier": "prettier --write ."</pre>



<h3 class="wp-block-heading">1.3. 使用ESLint检测</h3>



<p>1.在前面创建项目的时候，我们就选择了ESLint，所以Vue会默认帮助我们配置需要的ESLint环境。</p>



<p>2.VSCode需要安装ESLint插件：</p>



<figure class="wp-block-image"><img decoding="async" src="https://markdown.cztcode.com/008i3skNgy1gsq2oq26odj30pw05faaq.jpg" alt="image-20210722215933360"/></figure>



<p>3.解决eslint和prettier冲突的问题：</p>



<p>安装插件：（vue在创建项目时，如果选择prettier，那么这两个插件会自动安装）</p>



<pre class="wp-block-preformatted">&nbsp;npm i eslint-plugin-prettier eslint-config-prettier -D</pre>



<p>添加prettier插件：</p>



<pre class="wp-block-code"><code>&nbsp; &nbsp;extends: &#91;<br>&nbsp; &nbsp; &nbsp;"plugin:vue/vue3-essential",<br>&nbsp; &nbsp; &nbsp;"eslint:recommended",<br>&nbsp; &nbsp; &nbsp;"@vue/typescript/recommended",<br>&nbsp; &nbsp; &nbsp;"@vue/prettier",<br>&nbsp; &nbsp; &nbsp;"@vue/prettier/@typescript-eslint",<br>&nbsp; &nbsp; &nbsp;'plugin:prettier/recommended'<br>&nbsp;  ],</code></pre>



<ol class="wp-block-list" start="4">
<li>添加忽略规则.eslintrc.js</li>
</ol>



<pre class="wp-block-code"><code>&nbsp;module.exports = {<br>&nbsp; &nbsp;root: true,<br>&nbsp; &nbsp;env: {<br>&nbsp; &nbsp; &nbsp;node: true,<br>&nbsp;  },<br>&nbsp; &nbsp;extends: &#91;<br>&nbsp; &nbsp; &nbsp;"plugin:vue/vue3-essential",<br>&nbsp; &nbsp; &nbsp;"eslint:recommended",<br>&nbsp; &nbsp; &nbsp;"@vue/typescript/recommended",<br>&nbsp; &nbsp; &nbsp;"plugin:prettier/recommended",<br>&nbsp;  ],<br>&nbsp; &nbsp;parserOptions: {<br>&nbsp; &nbsp; &nbsp;ecmaVersion: 2020,<br>&nbsp;  },<br>&nbsp; &nbsp;rules: {<br>&nbsp; &nbsp; &nbsp;"no-console": process.env.NODE_ENV === "production" ? "warn" : "off",<br>&nbsp; &nbsp; &nbsp;"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",<br>&nbsp; &nbsp; &nbsp;"vue/multi-word-component-names": "off", //关闭组件名必须为多个单词<br>&nbsp;  },<br>&nbsp;};<br>&nbsp;​</code></pre>



<h3 class="wp-block-heading">1.4. git Husky和eslint</h3>



<p>虽然我们已经要求项目使用eslint了，但是不能保证组员提交代码之前都将eslint中的问题解决掉了：</p>



<ul class="wp-block-list">
<li>也就是我们希望保证代码仓库中的代码都是符合eslint规范的；</li>



<li>那么我们需要在组员执行 <code>git commit</code> 命令的时候对其进行校验，如果不符合eslint规范，那么自动通过规范进行修复；</li>
</ul>



<p>那么如何做到这一点呢？可以通过Husky工具：</p>



<ul class="wp-block-list">
<li>husky是一个git hook工具，可以帮助我们触发git提交的各个阶段：pre-commit、commit-msg、pre-push</li>
</ul>



<p>如何使用husky呢？</p>



<p>这里我们可以使用自动配置命令：</p>



<pre class="wp-block-preformatted">&nbsp;npx husky-init &amp;&amp; npm install</pre>



<p>这里会做三件事：</p>



<p>1.安装husky相关的依赖：</p>



<figure class="wp-block-image"><img decoding="async" src="https://markdown.cztcode.com/008i3skNgy1gsqq0o5jxmj30bb04qwen.jpg" alt="image-20210723112648927"/></figure>



<p>2.在项目目录下创建 <code>.husky</code> 文件夹：</p>



<pre class="wp-block-preformatted">&nbsp;npx huksy install</pre>



<figure class="wp-block-image"><img decoding="async" src="https://markdown.cztcode.com/008i3skNgy1gsqq16zo75j307703mt8m.jpg" alt="image-20210723112719634"/></figure>



<p>3.在package.json中添加一个脚本：</p>



<figure class="wp-block-image"><img decoding="async" src="https://markdown.cztcode.com/008i3skNgy1gsqq26phpxj30dj06fgm3.jpg" alt="image-20210723112817691"/></figure>



<p>接下来，我们需要去完成一个操作：在进行commit时，执行lint脚本：</p>



<figure class="wp-block-image"><img decoding="async" src="https://markdown.cztcode.com/008i3skNgy1gsqq3hn229j30nf04z74q.jpg" alt="image-20210723112932943"/></figure>



<p>这个时候我们执行git commit的时候会自动对代码进行lint校验。</p>



<h3 class="wp-block-heading">1.5. git commit规范</h3>



<h4 class="wp-block-heading">1.5.1. 代码提交风格</h4>



<p>通常我们的git commit会按照统一的风格来提交，这样可以快速定位每次提交的内容，方便之后对版本进行控制。</p>



<figure class="wp-block-image"><img decoding="async" src="https://markdown.cztcode.com/008i3skNgy1gsqw17gaqjj30to0cj3zp.jpg" alt=""/></figure>



<p>但是如果每次手动来编写这些是比较麻烦的事情，我们可以使用一个工具：Commitizen</p>



<ul class="wp-block-list">
<li>Commitizen 是一个帮助我们编写规范 commit message 的工具；</li>
</ul>



<p>1.安装Commitizen</p>



<pre class="wp-block-preformatted">&nbsp;npm install commitizen -D</pre>



<p>2.安装cz-conventional-changelog，并且初始化cz-conventional-changelog：</p>



<pre class="wp-block-preformatted">&nbsp;npx commitizen init cz-conventional-changelog --save-dev --save-exact</pre>



<p>这个命令会帮助我们安装cz-conventional-changelog：</p>



<figure class="wp-block-image"><img decoding="async" src="https://markdown.cztcode.com/008i3skNgy1gsqvz2odi4j30ek00zmx2.jpg" alt="image-20210723145249096"/></figure>



<p>并且在package.json中进行配置：</p>



<figure class="wp-block-image"><img decoding="async" src="https://markdown.cztcode.com/008i3skNgy1gsqvzftay5j30iu04k74d.jpg" alt=""/></figure>



<p>这个时候我们提交代码需要使用 <code>npx cz</code>：</p>



<ul class="wp-block-list">
<li>第一步是选择type，本次更新的类型</li>
</ul>



<figure class="wp-block-table"><table><thead><tr><th>Type</th><th>作用</th></tr></thead><tbody><tr><td>feat</td><td>新增特性 (feature)</td></tr><tr><td>fix</td><td>修复 Bug(bug fix)</td></tr><tr><td>docs</td><td>修改文档 (documentation)</td></tr><tr><td>style</td><td>代码格式修改(white-space, formatting, missing semi colons, etc)</td></tr><tr><td>refactor</td><td>代码重构(refactor)</td></tr><tr><td>perf</td><td>改善性能(A code change that improves performance)</td></tr><tr><td>test</td><td>测试(when adding missing tests)</td></tr><tr><td>build</td><td>变更项目构建或外部依赖（例如 scopes: webpack、gulp、npm 等）</td></tr><tr><td>ci</td><td>更改持续集成软件的配置文件和 package 中的 scripts 命令，例如 scopes: Travis, Circle 等</td></tr><tr><td>chore</td><td>变更构建流程或辅助工具(比如更改测试环境)</td></tr><tr><td>revert</td><td>代码回退</td></tr></tbody></table></figure>



<ul class="wp-block-list">
<li>第二步选择本次修改的范围（作用域）</li>
</ul>



<figure class="wp-block-image"><img decoding="async" src="https://markdown.cztcode.com/008i3skNgy1gsqw8ca15oj30r600wmx4.jpg" alt="image-20210723150147510"/></figure>



<ul class="wp-block-list">
<li>第三步选择提交的信息</li>
</ul>



<figure class="wp-block-image"><img decoding="async" src="https://markdown.cztcode.com/008i3skNgy1gsqw8mq3zlj60ni01hmx402.jpg" alt="image-20210723150204780"/></figure>



<ul class="wp-block-list">
<li>第四步提交详细的描述信息</li>
</ul>



<figure class="wp-block-image"><img decoding="async" src="https://markdown.cztcode.com/008i3skNgy1gsqw8y05bjj30kt01fjrb.jpg" alt="image-20210723150223287"/></figure>



<ul class="wp-block-list">
<li>第五步是否是一次重大的更改</li>
</ul>



<figure class="wp-block-image"><img decoding="async" src="https://markdown.cztcode.com/008i3skNgy1gsqw9z5vbij30bm00q744.jpg" alt="image-20210723150322122"/></figure>



<ul class="wp-block-list">
<li>第六步是否影响某个open issue</li>
</ul>



<figure class="wp-block-image"><img decoding="async" src="https://markdown.cztcode.com/008i3skNgy1gsqwar8xp1j30fq00ya9x.jpg" alt="image-20210723150407822"/></figure>



<p>我们也可以在scripts中构建一个命令来执行 cz：</p>



<figure class="wp-block-image"><img decoding="async" src="https://markdown.cztcode.com/008i3skNgy1gsqwc4gtkxj30e207174t.jpg" alt="image-20210723150526211"/></figure>



<h4 class="wp-block-heading">1.5.2. 代码提交验证</h4>



<p>如果我们按照cz来规范了提交风格，但是依然有同事通过 <code>git commit</code> 按照不规范的格式提交应该怎么办呢？</p>



<ul class="wp-block-list">
<li>我们可以通过commitlint来限制提交；</li>
</ul>



<p>1.安装 @commitlint/config-conventional 和 @commitlint/cli</p>



<pre class="wp-block-preformatted">&nbsp;npm i @commitlint/config-conventional @commitlint/cli -D</pre>



<p>2.在根目录创建commitlint.config.js文件，配置commitlint</p>



<pre class="wp-block-preformatted">&nbsp;module.exports = {<br>&nbsp; &nbsp;extends: ['@commitlint/config-conventional']<br>&nbsp;}</pre>



<p>3.使用husky生成commit-msg文件，验证提交信息：</p>



<pre class="wp-block-preformatted">&nbsp;npx husky add .husky/commit-msg "npx --no-install commitlint --edit $1"</pre>



<h2 class="wp-block-heading">二. 第三方库集成</h2>



<h3 class="wp-block-heading">2.1. vue.config.js配置</h3>



<p>vue.config.js有三种配置方式：</p>



<ul class="wp-block-list">
<li>方式一：直接通过CLI提供给我们的选项来配置：
<ul class="wp-block-list">
<li>比如publicPath：配置应用程序部署的子目录（默认是 <code>/</code>，相当于部署在 <code>https://www.my-app.com/</code>）；</li>



<li>比如outputDir：修改输出的文件夹；</li>
</ul>
</li>



<li>方式二：通过configureWebpack修改webpack的配置：
<ul class="wp-block-list">
<li>可以是一个对象，直接会被合并；</li>



<li>可以是一个函数，会接收一个config，可以通过config来修改配置；</li>
</ul>
</li>



<li>方式三：通过chainWebpack修改webpack的配置：
<ul class="wp-block-list">
<li>是一个函数，会接收一个基于 <a href="https://github.com/mozilla-neutrino/webpack-chain" target="_blank" rel="noopener">webpack-chain</a> 的config对象，可以对配置进行修改；</li>
</ul>
</li>
</ul>



<pre class="wp-block-code"><code>&nbsp;const path = require('path')<br>&nbsp;​<br>&nbsp;module.exports = {<br>&nbsp; &nbsp;outputDir: './build',<br>&nbsp; &nbsp;// configureWebpack: {<br>&nbsp; &nbsp;// &nbsp; resolve: {<br>&nbsp; &nbsp;// &nbsp; &nbsp; alias: {<br>&nbsp; &nbsp;// &nbsp; &nbsp; &nbsp; views: '@/views'<br>&nbsp; &nbsp;// &nbsp; &nbsp; }<br>&nbsp; &nbsp;// &nbsp; }<br>&nbsp; &nbsp;// }<br>&nbsp; &nbsp;// configureWebpack: (config) =&gt; {<br>&nbsp; &nbsp;// &nbsp; config.resolve.alias = {<br>&nbsp; &nbsp;// &nbsp; &nbsp; '@': path.resolve(__dirname, 'src'),<br>&nbsp; &nbsp;// &nbsp; &nbsp; views: '@/views'<br>&nbsp; &nbsp;// &nbsp; }<br>&nbsp; &nbsp;// },<br>&nbsp; &nbsp;chainWebpack: (config) =&gt; {<br>&nbsp; &nbsp; &nbsp;config.resolve.alias.set('@', path.resolve(__dirname, 'src')).set('views', '@/views')<br>&nbsp;  }<br>&nbsp;}</code></pre>



<h3 class="wp-block-heading">2.2. vue-router集成</h3>



<p>安装vue-router的最新版本：</p>



<pre class="wp-block-preformatted">&nbsp;npm install vue-router@next</pre>



<p>创建router对象：</p>



<pre class="wp-block-code"><code>&nbsp;import { createRouter, createWebHashHistory } from 'vue-router'<br>&nbsp;import { RouteRecordRaw } from 'vue-router'<br>&nbsp;​<br>&nbsp;const routes: RouteRecordRaw&#91;] = &#91;<br>&nbsp;  {<br>&nbsp; &nbsp; &nbsp;path: '/',<br>&nbsp; &nbsp; &nbsp;redirect: '/main'<br>&nbsp;  },<br>&nbsp;  {<br>&nbsp; &nbsp; &nbsp;path: '/main',<br>&nbsp; &nbsp; &nbsp;component: () =&gt; import('../views/main/main.vue')<br>&nbsp;  },<br>&nbsp;  {<br>&nbsp; &nbsp; &nbsp;path: '/login',<br>&nbsp; &nbsp; &nbsp;component: () =&gt; import('../views/login/login.vue')<br>&nbsp;  }<br>&nbsp;]<br>&nbsp;​<br>&nbsp;const router = createRouter({<br>&nbsp; &nbsp;routes,<br>&nbsp; &nbsp;history: createWebHashHistory()<br>&nbsp;})<br>&nbsp;​<br>&nbsp;export default router</code></pre>



<p>安装router：</p>



<pre class="wp-block-code"><code>&nbsp;import router from './router'<br>&nbsp;​<br>&nbsp;createApp(App).use(router).mount('#app')</code></pre>



<p>在App.vue中配置跳转：</p>



<pre class="wp-block-code"><code>&nbsp;&lt;template&gt;<br>&nbsp; &nbsp;&lt;div id="app"&gt;<br>&nbsp; &nbsp; &nbsp;&lt;router-link to="/login"&gt;登录&lt;/router-link&gt;<br>&nbsp; &nbsp; &nbsp;&lt;router-link to="/main"&gt;首页&lt;/router-link&gt;<br>&nbsp; &nbsp; &nbsp;&lt;router-view&gt;&lt;/router-view&gt;<br>&nbsp; &nbsp;&lt;/div&gt;<br>&nbsp;&lt;/template&gt;</code></pre>



<h3 class="wp-block-heading">2.3. vuex集成</h3>



<p>安装vuex：</p>



<pre class="wp-block-preformatted">&nbsp;npm install vuex@next</pre>



<p>创建store对象：</p>



<pre class="wp-block-code"><code>&nbsp;import { createStore } from 'vuex'<br>&nbsp;​<br>&nbsp;const store = createStore({<br>&nbsp; &nbsp;state() {<br>&nbsp; &nbsp; &nbsp;return {<br>&nbsp; &nbsp; &nbsp; &nbsp;name: 'coderwhy'<br>&nbsp; &nbsp;  }<br>&nbsp;  }<br>&nbsp;})<br>&nbsp;​<br>&nbsp;export default store</code></pre>



<p>安装store：</p>



<pre class="wp-block-preformatted">&nbsp;createApp(App).use(router).use(store).mount('#app')</pre>



<p>在App.vue中使用：</p>



<pre class="wp-block-preformatted">&nbsp;&lt;h2&gt;{{ $store.state.name }}&lt;/h2&gt;</pre>



<h3 class="wp-block-heading">2.4. element-plus集成</h3>



<p>Element Plus，一套为开发者、设计师和产品经理准备的基于 Vue 3.0 的桌面端组件库：</p>



<ul class="wp-block-list">
<li>相信很多同学在Vue2中都使用过element-ui，而element-plus正是element-ui针对于vue3开发的一个UI组件库；</li>



<li>它的使用方式和很多其他的组件库是一样的，所以学会element-plus，其他类似于ant-design-vue、NaiveUI、VantUI都是差不多的；</li>
</ul>



<p>安装element-plus</p>



<pre class="wp-block-preformatted">&nbsp;npm install element-plus</pre>



<h4 class="wp-block-heading">2.4.1. 全局引入</h4>



<p>一种引入element-plus的方式是全局引入，代表的含义是所有的组件和插件都会被自动注册：</p>



<pre class="wp-block-code"><code>&nbsp;import ElementPlus from 'element-plus'<br>&nbsp;import 'element-plus/lib/theme-chalk/index.css'<br>&nbsp;​<br>&nbsp;import router from './router'<br>&nbsp;import store from './store'<br>&nbsp;​<br>&nbsp;createApp(App).use(router).use(store).use(ElementPlus).mount('#app')</code></pre>



<h4 class="wp-block-heading">2.4.2. 局部引入</h4>



<p>也就是在开发中用到某个组件对某个组件进行引入：</p>



<pre class="wp-block-code"><code>&nbsp;&lt;template&gt;<br>&nbsp; &nbsp;&lt;div id="app"&gt;<br>&nbsp; &nbsp; &nbsp;&lt;router-link to="/login"&gt;登录&lt;/router-link&gt;<br>&nbsp; &nbsp; &nbsp;&lt;router-link to="/main"&gt;首页&lt;/router-link&gt;<br>&nbsp; &nbsp; &nbsp;&lt;router-view&gt;&lt;/router-view&gt;<br>&nbsp;​<br>&nbsp; &nbsp; &nbsp;&lt;h2&gt;{{ $store.state.name }}&lt;/h2&gt;<br>&nbsp;​<br>&nbsp; &nbsp; &nbsp;&lt;el-button&gt;默认按钮&lt;/el-button&gt;<br>&nbsp; &nbsp; &nbsp;&lt;el-button type="primary"&gt;主要按钮&lt;/el-button&gt;<br>&nbsp; &nbsp; &nbsp;&lt;el-button type="success"&gt;成功按钮&lt;/el-button&gt;<br>&nbsp; &nbsp; &nbsp;&lt;el-button type="info"&gt;信息按钮&lt;/el-button&gt;<br>&nbsp; &nbsp; &nbsp;&lt;el-button type="warning"&gt;警告按钮&lt;/el-button&gt;<br>&nbsp; &nbsp; &nbsp;&lt;el-button type="danger"&gt;危险按钮&lt;/el-button&gt;<br>&nbsp; &nbsp;&lt;/div&gt;<br>&nbsp;&lt;/template&gt;<br>&nbsp;​<br>&nbsp;&lt;script lang="ts"&gt;<br>&nbsp;import { defineComponent } from 'vue'<br>&nbsp;​<br>&nbsp;import { ElButton } from 'element-plus'<br>&nbsp;​<br>&nbsp;export default defineComponent({<br>&nbsp; &nbsp;name: 'App',<br>&nbsp; &nbsp;components: {<br>&nbsp; &nbsp; &nbsp;ElButton<br>&nbsp;  }<br>&nbsp;})<br>&nbsp;&lt;/script&gt;<br>&nbsp;​<br>&nbsp;&lt;style lang="less"&gt;<br>&nbsp;&lt;/style&gt;</code></pre>



<p>但是我们会发现是没有对应的样式的，引入样式有两种方式：</p>



<ul class="wp-block-list">
<li>全局引用样式（像之前做的那样）；</li>



<li>局部引用样式（通过babel的插件）；</li>
</ul>



<p>1.安装babel的插件：</p>



<pre class="wp-block-preformatted">&nbsp;npm install babel-plugin-import -D</pre>



<p>2.配置babel.config.js</p>



<pre class="wp-block-code"><code>&nbsp;module.exports = {<br>&nbsp; &nbsp;plugins: &#91;<br>&nbsp; &nbsp;  &#91;<br>&nbsp; &nbsp; &nbsp; &nbsp;'import',<br>&nbsp; &nbsp; &nbsp;  {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;libraryName: 'element-plus',<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;customStyleName: (name) =&gt; {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return `element-plus/lib/theme-chalk/${name}.css`<br>&nbsp; &nbsp; &nbsp; &nbsp;  }<br>&nbsp; &nbsp; &nbsp;  }<br>&nbsp; &nbsp;  ]<br>&nbsp;  ],<br>&nbsp; &nbsp;presets: &#91;'@vue/cli-plugin-babel/preset']<br>&nbsp;}</code></pre>



<p>但是这里依然有个弊端：</p>



<ul class="wp-block-list">
<li>这些组件我们在多个页面或者组件中使用的时候，都需要导入并且在components中进行注册；</li>



<li>所以我们可以将它们在全局注册一次；</li>
</ul>



<pre class="wp-block-code"><code>&nbsp;import {<br>&nbsp; &nbsp;ElButton,<br>&nbsp; &nbsp;ElTable,<br>&nbsp; &nbsp;ElAlert,<br>&nbsp; &nbsp;ElAside,<br>&nbsp; &nbsp;ElAutocomplete,<br>&nbsp; &nbsp;ElAvatar,<br>&nbsp; &nbsp;ElBacktop,<br>&nbsp; &nbsp;ElBadge,<br>&nbsp;} from 'element-plus'<br>&nbsp;​<br>&nbsp;const app = createApp(App)<br>&nbsp;​<br>&nbsp;const components = &#91;<br>&nbsp; &nbsp;ElButton,<br>&nbsp; &nbsp;ElTable,<br>&nbsp; &nbsp;ElAlert,<br>&nbsp; &nbsp;ElAside,<br>&nbsp; &nbsp;ElAutocomplete,<br>&nbsp; &nbsp;ElAvatar,<br>&nbsp; &nbsp;ElBacktop,<br>&nbsp; &nbsp;ElBadge<br>&nbsp;]<br>&nbsp;​<br>&nbsp;for (const cpn of components) {<br>&nbsp; &nbsp;app.component(cpn.name, cpn)<br>&nbsp;}</code></pre>



<h3 class="wp-block-heading">2.5. axios集成</h3>



<p>安装axios：</p>



<pre class="wp-block-preformatted">&nbsp;npm install axios</pre>



<p>封装axios：</p>



<pre class="wp-block-code"><code>&nbsp;import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'<br>&nbsp;import { Result } from './types'<br>&nbsp;import { useUserStore } from '/@/store/modules/user'<br>&nbsp;​<br>&nbsp;class HYRequest {<br>&nbsp; &nbsp;private instance: AxiosInstance<br>&nbsp;​<br>&nbsp; &nbsp;private readonly options: AxiosRequestConfig<br>&nbsp;​<br>&nbsp; &nbsp;constructor(options: AxiosRequestConfig) {<br>&nbsp; &nbsp; &nbsp;this.options = options<br>&nbsp; &nbsp; &nbsp;this.instance = axios.create(options)<br>&nbsp;​<br>&nbsp; &nbsp; &nbsp;this.instance.interceptors.request.use(<br>&nbsp; &nbsp; &nbsp;  (config) =&gt; {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;const token = useUserStore().getToken<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if (token) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;config.headers.Authorization = `Bearer ${token}`<br>&nbsp; &nbsp; &nbsp; &nbsp;  }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return config<br>&nbsp; &nbsp; &nbsp;  },<br>&nbsp; &nbsp; &nbsp;  (err) =&gt; {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return err<br>&nbsp; &nbsp; &nbsp;  }<br>&nbsp; &nbsp;  )<br>&nbsp;​<br>&nbsp; &nbsp; &nbsp;this.instance.interceptors.response.use(<br>&nbsp; &nbsp; &nbsp;  (res) =&gt; {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// 拦截响应的数据<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if (res.data.code === 0) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return res.data.data<br>&nbsp; &nbsp; &nbsp; &nbsp;  }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return res.data<br>&nbsp; &nbsp; &nbsp;  },<br>&nbsp; &nbsp; &nbsp;  (err) =&gt; {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return err<br>&nbsp; &nbsp; &nbsp;  }<br>&nbsp; &nbsp;  )<br>&nbsp;  }<br>&nbsp;​<br>&nbsp; &nbsp;request&lt;T = any&gt;(config: AxiosRequestConfig): Promise&lt;T&gt; {<br>&nbsp; &nbsp; &nbsp;return new Promise((resolve, reject) =&gt; {<br>&nbsp; &nbsp; &nbsp; &nbsp;this.instance<br>&nbsp; &nbsp; &nbsp; &nbsp;  .request&lt;any, AxiosResponse&lt;Result&lt;T&gt;&gt;&gt;(config)<br>&nbsp; &nbsp; &nbsp; &nbsp;  .then((res) =&gt; {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;resolve((res as unknown) as Promise&lt;T&gt;)<br>&nbsp; &nbsp; &nbsp; &nbsp;  })<br>&nbsp; &nbsp; &nbsp; &nbsp;  .catch((err) =&gt; {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;reject(err)<br>&nbsp; &nbsp; &nbsp; &nbsp;  })<br>&nbsp; &nbsp;  })<br>&nbsp;  }<br>&nbsp;​<br>&nbsp; &nbsp;get&lt;T = any&gt;(config: AxiosRequestConfig): Promise&lt;T&gt; {<br>&nbsp; &nbsp; &nbsp;return this.request({ ...config, method: 'GET' })<br>&nbsp;  }<br>&nbsp;​<br>&nbsp; &nbsp;post&lt;T = any&gt;(config: AxiosRequestConfig): Promise&lt;T&gt; {<br>&nbsp; &nbsp; &nbsp;return this.request({ ...config, method: 'POST' })<br>&nbsp;  }<br>&nbsp;​<br>&nbsp; &nbsp;patch&lt;T = any&gt;(config: AxiosRequestConfig): Promise&lt;T&gt; {<br>&nbsp; &nbsp; &nbsp;return this.request({ ...config, method: 'PATCH' })<br>&nbsp;  }<br>&nbsp;​<br>&nbsp; &nbsp;delete&lt;T = any&gt;(config: AxiosRequestConfig): Promise&lt;T&gt; {<br>&nbsp; &nbsp; &nbsp;return this.request({ ...config, method: 'DELETE' })<br>&nbsp;  }<br>&nbsp;}<br>&nbsp;​<br>&nbsp;export default HYRequest</code></pre>



<h3 class="wp-block-heading">2.6. VSCode配置</h3>



<pre class="wp-block-code"><code>&nbsp;{<br>&nbsp; &nbsp;"workbench.iconTheme": "vscode-great-icons",<br>&nbsp; &nbsp;"editor.fontSize": 17,<br>&nbsp; &nbsp;"eslint.migration.2_x": "off",<br>&nbsp; &nbsp;"&#91;javascript]": {<br>&nbsp; &nbsp; &nbsp;"editor.defaultFormatter": "dbaeumer.vscode-eslint"<br>&nbsp;  },<br>&nbsp; &nbsp;"files.autoSave": "afterDelay",<br>&nbsp; &nbsp;"editor.tabSize": 2,<br>&nbsp; &nbsp;"terminal.integrated.fontSize": 16,<br>&nbsp; &nbsp;"editor.renderWhitespace": "all",<br>&nbsp; &nbsp;"editor.quickSuggestions": {<br>&nbsp; &nbsp; &nbsp;"strings": true<br>&nbsp;  },<br>&nbsp; &nbsp;"dhttps://markdown.cztcode.com/008i3skNgy1gsqwar8xp1j30fq00ya9x.jpgebug.console.fontSize": 15,<br>&nbsp; &nbsp;"window.zoomLevel": 1,<br>&nbsp; &nbsp;"emmet.includeLanguages": {<br>&nbsp; &nbsp; &nbsp;"javascript": "javascriptreact"<br>&nbsp;  },<br>&nbsp; &nbsp;"explorer.confirmDragAndDrop": false,<br>&nbsp; &nbsp;"workbench.tree.indent": 16,<br>&nbsp; &nbsp;"javascript.updateImportsOnFileMove.enabled": "always",<br>&nbsp; &nbsp;"editor.wordWrap": "on",<br>&nbsp; &nbsp;"path-intellisense.mappings": {<br>&nbsp; &nbsp; &nbsp;"@": "${workspaceRoot}/src"<br>&nbsp;  },<br>&nbsp; &nbsp;"hediet.vscode-drawio.local-storage": "eyIuZHJhd2lvLWNvbmZpZyI6IntcImxhbmd1YWdlXCI6XCJcIixcImN1c3RvbUZvbnRzXCI6W10sXCJsaWJyYXJpZXNcIjpcImdlbmVyYWw7YmFzaWM7YXJyb3dzMjtmbG93Y2hhcnQ7ZXI7c2l0ZW1hcDt1bWw7YnBtbjt3ZWJpY29uc1wiLFwiY3VzdG9tTGlicmFyaWVzXCI6W1wiTC5zY3JhdGNocGFkXCJdLFwicGx1Z2luc1wiOltdLFwicmVjZW50Q29sb3JzXCI6W1wiRkYwMDAwXCIsXCIwMENDNjZcIixcIm5vbmVcIixcIkNDRTVGRlwiLFwiNTI1MjUyXCIsXCJGRjMzMzNcIixcIjMzMzMzM1wiLFwiMzMwMDAwXCIsXCIwMENDQ0NcIixcIkZGNjZCM1wiLFwiRkZGRkZGMDBcIl0sXCJmb3JtYXRXaWR0aFwiOjI0MCxcImNyZWF0ZVRhcmdldFwiOmZhbHNlLFwicGFnZUZvcm1hdFwiOntcInhcIjowLFwieVwiOjAsXCJ3aWR0aFwiOjExNjksXCJoZWlnaHRcIjoxNjU0fSxcInNlYXJjaFwiOnRydWUsXCJzaG93U3RhcnRTY3JlZW5cIjp0cnVlLFwiZ3JpZENvbG9yXCI6XCIjZDBkMGQwXCIsXCJkYXJrR3JpZENvbG9yXCI6XCIjNmU2ZTZlXCIsXCJhdXRvc2F2ZVwiOnRydWUsXCJyZXNpemVJbWFnZXNcIjpudWxsLFwib3BlbkNvdW50ZXJcIjowLFwidmVyc2lvblwiOjE4LFwidW5pdFwiOjEsXCJpc1J1bGVyT25cIjpmYWxzZSxcInVpXCI6XCJcIn0ifQ==",<br>&nbsp; &nbsp;"hediet.vscode-drawio.theme": "Kennedy",<br>&nbsp; &nbsp;"editor.fontFamily": "Source Code Pro, 'Courier New', monospace",<br>&nbsp; &nbsp;"editor.smoothScrolling": true,<br>&nbsp; &nbsp;"editor.formatOnSave": true,<br>&nbsp; &nbsp;"editor.defaultFormatter": "esbenp.prettier-vscode",<br>&nbsp; &nbsp;"workbench.colorTheme": "Atom One Dark",<br>&nbsp; &nbsp;"vetur.completion.autoImport": false,<br>&nbsp; &nbsp;"security.workspace.trust.untrustedFiles": "open",<br>&nbsp; &nbsp;"eslint.lintTask.enable": true,<br>&nbsp; &nbsp;"eslint.alwaysShowStatus": true,<br>&nbsp; &nbsp;"editor.codeActionsOnSave": {<br>&nbsp; &nbsp; &nbsp;"source.fixAll.eslint": true<br>&nbsp;  }<br>&nbsp;}</code></pre>
]]></content:encoded>
					
					<wfw:commentRss>https://www.cztcode.com/2023/4275/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">4275</post-id>	</item>
		<item>
		<title>浅拷贝与深拷贝</title>
		<link>https://www.cztcode.com/2022/4133/</link>
					<comments>https://www.cztcode.com/2022/4133/#respond</comments>
		
		<dc:creator><![CDATA[Jellow]]></dc:creator>
		<pubDate>Sun, 30 Jan 2022 02:28:57 +0000</pubDate>
				<category><![CDATA[Vue]]></category>
		<guid isPermaLink="false">https://www.cztcode.com/?p=4133</guid>

					<description><![CDATA[浅拷贝 定义 浅拷贝是按位拷贝对象，它会创建一个新对象，这个对象有着原始对象属性值的一份精确拷贝。 如果属性是基本类型，拷贝的就是基本类型的值；如果属性是内存地址（引用类型），拷贝的就是内存地址，因此如果其中一个对象改变了这个地址，就会影响到另一个对象。 Object.assign方法实行的是浅拷贝，而不是深拷贝。也就是说，如果源对象某个属性的值是对象，那么目标对象拷贝得到的是这个对象的引用。 输 [&#8230;]]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div>
<h1 class="wp-block-heading">浅拷贝</h1>



<h2 class="wp-block-heading">定义</h2>



<p class="is-style-iw-2em"><strong>浅拷贝</strong>是按位<strong>拷贝</strong>对象，它会创建一个新对象，这个对象有着原始对象属性值的一份精确<strong>拷贝</strong>。 如果属性是基本类型，<strong>拷贝</strong>的就是基本类型的值；如果属性是内存地址（引用类型），<strong>拷贝</strong>的就是内存地址，因此如果其中一个对象改变了这个地址，就会影响到另一个对象。</p>



<p class="is-style-iw-2em"><code>Object.assign</code>方法实行的是浅拷贝，而不是深拷贝。也就是说，如果源对象某个属性的值是对象，那么目标对象拷贝得到的是这个对象的引用。</p>



<pre class="wp-block-code"><code>    const info={name:"why"} //属性的value是值，所以只是复制值
    const obj=Object.assign({},info)
    obj.name="he"
    console.log(info)

    const obj1 = {a: {b: 1}}//属性的value是对象，复制的是引用
    const obj2 = Object.assign({}, obj1)

    obj1.a.b = 2
    obj2.a.b // 2
    console.log(obj2)
</code></pre>



<p class="is-style-iw-2em">输出结果</p>



<pre class="wp-block-code"><code>{ name: 'why' }
{ a: { b: 2 } }
</code></pre>



<p class="is-style-iw-2em">这里也可以用es6语法展开运算符进行浅拷贝</p>



<div class="wp-block-jetpack-markdown"><pre><code>
    const obj1 = {a: {b: 1}}//属性的value是对象
    const obj2 = {...obj1}

    obj1.a.b = 2
    obj2.a.b // 2
    console.log(obj2.a===obj1.a)

</code></pre>
</div>



<p class="is-style-iw-2em">比较一下，结果为true，对象确实是同一个</p>



<h1 class="wp-block-heading">深拷贝</h1>



<p class="is-style-iw-2em">深拷贝会另外创造一个一模一样的对象，新对象跟原对象不共享内存，修改新对象不会改到原对象</p>



<p class="is-style-iw-2em">利用lodash库实现深拷贝</p>



<p class="is-style-iw-2em">Lodash 是一个一致性、模块化、高性能的 JavaScript 实用工具库</p>



<pre class="wp-block-code"><code>const _ = require('lodash');
const obj1 = {
    a: 1,
    b: {f: {g: 1}},
    c: &#91;1, 2, 3]
};
const obj2 = _.cloneDeep(obj1);

console.log(obj1.b.f === obj2.b.f);

</code></pre>



<p class="is-style-iw-2em">结果是false，深拷贝不是同一个对象</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.cztcode.com/2022/4133/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">4133</post-id>	</item>
		<item>
		<title>VUE3之VUEX</title>
		<link>https://www.cztcode.com/2021/4104/</link>
					<comments>https://www.cztcode.com/2021/4104/#comments</comments>
		
		<dc:creator><![CDATA[Jellow]]></dc:creator>
		<pubDate>Sun, 05 Sep 2021 15:04:13 +0000</pubDate>
				<category><![CDATA[Vue]]></category>
		<category><![CDATA[综合]]></category>
		<guid isPermaLink="false">https://www.cztcode.com/?p=4104</guid>

					<description><![CDATA[VUE3之VUEX
vuex的基本使用
state getters mutations actions
辅助函数
modules]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div>


<h2 class="wp-block-heading">vuex的基本使用</h2>



<p class="is-style-iw-2em">创建一个store：</p>



<pre class="wp-block-code"><code>import {createStore} from 'vuex'

const store = createStore();

export default store;</code></pre>



<p class="is-style-iw-2em">在Main.js中使用：</p>



<pre class="wp-block-code"><code>import&nbsp;store&nbsp;from&nbsp;'./store'

createApp(App).use(store).mount('#app')</code></pre>



<h2 class="wp-block-heading">state</h2>



<p class="is-style-iw-2em">在store中定义数据，需要在state属性中：</p>



<pre class="wp-block-code"><code>const store = createStore({
  state(){
    return{
      counter:0
    }
  }
});</code></pre>



<p class="is-style-iw-2em">在组件中使用时，需要从$store.state中获取：</p>



<pre class="wp-block-code"><code>&lt;h2&gt;{{$store.state.counter}}&lt;/h2&gt;</code></pre>



<h2 class="wp-block-heading">mutations</h2>



<p class="is-style-iw-2em">在vuex的开发模式中，不推荐直接对数据进行操作，而是应该通过commit来提交一次数据操作。在store中定义mutations属性：</p>



<pre class="wp-block-code"><code>&nbsp;&nbsp;mutations:{
&nbsp;&nbsp;&nbsp;&nbsp;increment(state){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;state.counter++
&nbsp;&nbsp;&nbsp;&nbsp;},
&nbsp;&nbsp;&nbsp;&nbsp;decrement(state){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;state.counter--
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;}</code></pre>



<p class="is-style-iw-2em">在组件中调用store的commit方法，参数是要执行的mutation的方法名：</p>



<pre class="wp-block-code"><code>  methods:{
    increment(){
      this.$store.commit("increment")
    },
    decrement(){
      this.$store.commit("decrement")
    }
  }</code></pre>



<h2 class="wp-block-heading">mutations的一些补充</h2>



<p class="is-style-iw-2em">mutations中的方法的第一个参数是state，可以获取state中的变量，第二个参数是payload，即从外部传入的参数：</p>



<pre class="wp-block-code"><code>&nbsp;&nbsp;mutations:{
&nbsp;&nbsp;&nbsp;&nbsp;incrementN(state,payload){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;state.counter+=payload
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;},</code></pre>



<pre class="wp-block-code"><code>    methods: {
      addTen(){
        this.$store.commit('incrementN',10)
      }
    },</code></pre>



<p class="is-style-iw-2em">另一种提交的风格是，将两个参数合并，即传入一个对象，当中有type来指明提交给某个函数：</p>



<pre class="wp-block-code"><code>this.$store.commit({
&nbsp;&nbsp;type:'incrementN',
&nbsp;&nbsp;incre:10
})</code></pre>



<p class="is-style-iw-2em">另外为了防止将方法名写错，可以使用常量的方式定义方法名：</p>



<pre class="wp-block-code"><code>&nbsp;&nbsp;const INCREMENT_N = "increment_n";
    mutations:{
&nbsp;&nbsp;&nbsp;&nbsp;&#091;INCREMENT_N](state,payload){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;state.counter+=payload
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;},</code></pre>



<h2 class="wp-block-heading">mapState辅助函数</h2>



<p class="is-style-iw-2em">可以通过计算属性来简化获取state中的数据：</p>



<pre class="wp-block-code"><code>&nbsp;&nbsp;computed:{
&nbsp;&nbsp;&nbsp;&nbsp;sCounter(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;this.$store.state.counter
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;}</code></pre>



<p class="is-style-iw-2em">不过vuex为我们提供了一个函数，可以更加快速地获取到state中的变量：</p>



<pre class="wp-block-code"><code>import { mapState } from 'vuex'
  export default {
    computed:{
      sCounter(){
        return this.$store.state.counter
      },
      ...mapState(&#091;"counter","name"])
    }
  }</code></pre>



<p class="is-style-iw-2em">mapState传入的是要获取的state中的变量名数组，返回值是变量的computed对象，所以需要用&#8230;展开；也可以传入一个对象，可以自定义名字：</p>



<pre class="wp-block-code"><code>...mapState({
  sCounter:state=&gt;state.counter,
  name:state=&gt;state.name
})</code></pre>



<p class="is-style-iw-2em"><strong>在composition API中使用</strong></p>



<p class="is-style-iw-2em">vuex提供了一个useStore方法让我们在setup中可以获取到store：</p>



<pre class="wp-block-code"><code>import { useStore } from 'vuex'
import { computed } from 'vue'
  export default {
    setup(props) {
      const store = useStore();

      const sCounter = computed(()=&gt;store.state.counter)

      return {
        sCounter
      }
    }
  }</code></pre>



<p class="is-style-iw-2em">如果要使用mapState，需要进行一些处理：</p>



<pre class="wp-block-code"><code>setup(props) {
      const store = useStore();

      const storeStateFns = mapState(&#091;"counter","name"]);
      const storeState = {};
      Object.keys(storeStateFns).forEach(fnKey =&gt;{
        const fn = storeStateFns&#091;fnKey].bind({$store:store});
        console.log(fnKey);
        storeState&#091;fnKey]=computed(fn);
      })

      return {
        ...storeState 
      }
    }</code></pre>



<p class="is-style-iw-2em">mapState返回的都是函数，在执行时需要用到$store属性，所以需要加上bind。</p>



<p class="is-style-iw-2em">对以上的内容进行封装以便使用：</p>



<pre class="wp-block-code"><code>      const storeStateFns = mapState(&#091;"counter","name"]);
      const storeState = {};
      Object.keys(storeStateFns).forEach(fnKey =&gt;{
        const fn = storeStateFns&#091;fnKey].bind({$store:store});
        console.log(fnKey);
        storeState&#091;fnKey]=computed(fn);
      })</code></pre>



<h2 class="wp-block-heading">getters</h2>



<p class="is-style-iw-2em">一些数据可能需要结果处理之后再进行显示（和computed类似，不用在每一个组件中写计算属性），定义方式如下：</p>



<pre class="wp-block-code"><code>const store = createStore({
  state(){},
  mutations:{},
  getters:{
    totalPrice(state){
      let totalPrice=0;
      for (const book of state.books){
        totalPrice+=book.count*book.price
      }
      return totalPrice;
    }
  }
});</code></pre>



<p class="is-style-iw-2em">使用方式：</p>



<pre class="wp-block-code"><code>&lt;h2&gt;总价值:{{$store.getters.totalPrice}}&lt;/h2&gt;</code></pre>



<p class="is-style-iw-2em">getters中定义的函数的第一个参数是state，可以获取state中定义的变量，第二个参数是getters，可以用其调用getters中其它的函数：</p>



<pre class="wp-block-code"><code>  getters:{
    totalPrice(state,getters){
      let totalPrice=0;
      for (const book of state.books){
        totalPrice+=book.count*book.price
      }
      return totalPrice * getters.currentDiscount;
    },
    currentDiscount(state){
      return state.discount*0.9;
    }
  }</code></pre>



<p class="is-style-iw-2em">getter函数的返回值可以是一个值，在使用时就应该如同上面所示：</p>



<pre class="wp-block-code"><code>&lt;h2&gt;总价值:{{$store.getters.totalPrice}}&lt;/h2&gt;</code></pre>



<p class="is-style-iw-2em">也可以返回一个函数，返回函数的一个目的是传入我们的自定义参数：</p>



<pre class="wp-block-code"><code>totalPriceForCountN(state,getters){
&nbsp;&nbsp;return&nbsp;function(n){
&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;totalPrice=0;
&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(const&nbsp;book&nbsp;of&nbsp;state.books){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(book.count&gt;=n){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;totalPrice+=book.count*book.price
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;totalPrice&nbsp;*&nbsp;getters.currentDiscount;
&nbsp;&nbsp;}
}</code></pre>



<p class="is-style-iw-2em">使用时需要在后面加上小括号表示函数调用：</p>



<pre class="wp-block-code"><code>&lt;h2&gt;总价值:{{$store.getters.totalPriceForCountN(4)}}&lt;/h2&gt;</code></pre>


]]></content:encoded>
					
					<wfw:commentRss>https://www.cztcode.com/2021/4104/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">4104</post-id>	</item>
		<item>
		<title>VUE3之vue-router</title>
		<link>https://www.cztcode.com/2021/4089/</link>
					<comments>https://www.cztcode.com/2021/4089/#respond</comments>
		
		<dc:creator><![CDATA[Jellow]]></dc:creator>
		<pubDate>Wed, 01 Sep 2021 15:28:42 +0000</pubDate>
				<category><![CDATA[Vue]]></category>
		<guid isPermaLink="false">https://www.cztcode.com/?p=4089</guid>

					<description><![CDATA[VUE3之vue-router
vue-router的基本使用和配置
vue-router知识点补充
路由懒加载
动态路由
NotFound
嵌套路由
编程式导航
router-link的v-slot
动态添加/删除路由
路由导航守卫]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div>


<h2 class="wp-block-heading">vue-router的基本使用和配置</h2>



<p class="is-style-iw-2em">首先要有两个组件Home.vue和About.vue，之后将这两个组件注册到路由中：</p>



<pre class="wp-block-code"><code>import Home from '../pages/Home.vue';
import About from '../pages/About.vue';

// 配置映射关系
const routes = &#091;
  {path: '/', component: Home},
  {path: '/home', component: Home},
  {path: '/about', component: About}
];</code></pre>



<p class="is-style-iw-2em">创建一个路由对象，并传入配置：</p>



<pre class="wp-block-code"><code>import {createRouter, createWebHashHistory, createWebHistory} from 'vue-router'
//&nbsp;创建一个路由对象router
const&nbsp;router&nbsp;=&nbsp;createRouter({
&nbsp;&nbsp;routes,
&nbsp;&nbsp;history:&nbsp;createWebHashHistory()
})</code></pre>



<p class="is-style-iw-2em">在main.js中使用router：</p>



<pre class="wp-block-code"><code>import&nbsp;{&nbsp;createApp&nbsp;}&nbsp;from&nbsp;'vue'
import&nbsp;router&nbsp;from&nbsp;'./router'
import&nbsp;App&nbsp;from&nbsp;'./App.vue'

const&nbsp;app=createApp(App);
app.use(router);
app.mount('#app');</code></pre>



<p class="is-style-iw-2em">此时路由已经添加成功，需要在app.vue中使用路由组件。</p>



<p class="is-style-iw-2em">router-view是用于显示路由中组件的地方，router-link是一个控制路由路径的a元素，使用如下：</p>



<pre class="wp-block-code"><code>&nbsp;&nbsp;&lt;div&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;router-link&nbsp;to="/home"&gt;首页&lt;/router-link&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;router-link&nbsp;to="/about"&gt;关于&lt;/router-link&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;router-view&gt;&lt;/router-view&gt;
&nbsp;&nbsp;&lt;/div&gt;</code></pre>



<h2 class="wp-block-heading">vue-router知识点补充</h2>



<p class="is-style-iw-2em">在路由关系中：</p>



<pre class="wp-block-code"><code>const routes = &#091;
  {path: '/', component: Home},
  {path: '/home', component: Home},
  {path: '/about', component: About}
];</code></pre>



<p class="is-style-iw-2em">默认的&#8217;/&#8217;，可以为其指定一个component，也可以重定向到一个页面：</p>



<pre class="wp-block-code"><code>&nbsp;&nbsp;{path:&nbsp;'/',&nbsp;redirect:&nbsp;'/home'},</code></pre>



<p class="is-style-iw-2em">route还有两个属性：name是为一个route定义一个名字，路由是可以通过这个name跳转的；meta定义了这个路由的内部数据，可以通过route.meta来获取到。</p>



<p class="is-style-iw-2em">对于route-link，默认使用的是history的popstate策略，为其增加replace属性后将使用replacestate策略。</p>



<pre class="wp-block-code"><code>&nbsp;&nbsp;&lt;div&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;router-link&nbsp;to="/home"&nbsp;replace&gt;首页&lt;/router-link&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;router-link&nbsp;to="/about"&nbsp;replace&gt;关于&lt;/router-link&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;router-view&gt;&lt;/router-view&gt;
&nbsp;&nbsp;&lt;/div&gt;</code></pre>



<p class="is-style-iw-2em">被选中的route-link，会自动添加上两个class属性：router-link-active和router-link-exact-active</p>



<figure class="wp-block-image size-large"><img decoding="async" src="https://www.cztcode.com/wp-content/uploads/2021/08/image-40.png" alt="" class="wp-image-4090" /></figure>



<p class="is-style-iw-2em">可以利用这个class为其配置样式。其中router-link-exact-active与router-link-active的区别是，router-link-exact-active只有在精准匹配时才会加上这个class（嵌套组件的嵌套路由），而router-link-active是任何父组件也会加上。</p>



<p class="is-style-iw-2em">这个默认的class可以通过active-class和extra-active-class来修改：</p>



<pre class="wp-block-code"><code>&nbsp;&nbsp;&lt;div&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;router-link&nbsp;to="/home"&nbsp;replace&nbsp;active-class="home-active"&gt;首页&lt;/router-link&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;router-link&nbsp;to="/about"&nbsp;replace&nbsp;active-class="about-active"&gt;关于&lt;/router-link&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;router-view&gt;&lt;/router-view&gt;
&nbsp;&nbsp;&lt;/div&gt;</code></pre>



<figure class="wp-block-image size-large"><img decoding="async" src="https://www.cztcode.com/wp-content/uploads/2021/08/image-41.png" alt="" class="wp-image-4092" /></figure>



<h2 class="wp-block-heading">路由懒加载</h2>



<p class="is-style-iw-2em">在路由配置的component属性中，将原来的组件替换为一个function（import的promise）：</p>



<pre class="wp-block-code"><code>//&nbsp;import&nbsp;Home&nbsp;from&nbsp;'../pages/Home.vue';
//&nbsp;import&nbsp;About&nbsp;from&nbsp;'../pages/About.vue';

const&nbsp;routes&nbsp;=&nbsp;&#091;
&nbsp;&nbsp;{path:&nbsp;'/',&nbsp;redirect:&nbsp;'/home'},
&nbsp;&nbsp;{path:&nbsp;'/home',&nbsp;component:&nbsp;()=&gt;{
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;import("../pages/Home.vue")
&nbsp;&nbsp;}},
&nbsp;&nbsp;{path:&nbsp;'/about',&nbsp;component:&nbsp;()=&gt;{
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;import("../pages/About.vue")
&nbsp;&nbsp;}}
];</code></pre>



<figure class="wp-block-image size-large"><img decoding="async" src="https://www.cztcode.com/wp-content/uploads/2021/08/image-42.png" alt="" class="wp-image-4096" /></figure>



<p class="is-style-iw-2em">利用webpack的魔法注释来为组件分包文件命名，格式为/* webpackChunkName: &#8220;&#8221; */：</p>



<pre class="wp-block-preformatted">const&nbsp;routes&nbsp;=&nbsp;[
&nbsp;&nbsp;{path:&nbsp;'/',&nbsp;redirect:&nbsp;'/home'},
&nbsp;&nbsp;{path:&nbsp;'/home',&nbsp;component:&nbsp;()=&gt;{
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;import(/*&nbsp;webpackChunkName:&nbsp;"home-chunk"&nbsp;*/"../pages/Home.vue")
&nbsp;&nbsp;}},
&nbsp;&nbsp;{path:&nbsp;'/about',&nbsp;component:&nbsp;()=&gt;{
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;import(/*&nbsp;webpackChunkName:&nbsp;"page-chunk"&nbsp;*/"../pages/About.vue")
&nbsp;&nbsp;}}
];</pre>



<figure class="wp-block-image size-large"><img decoding="async" src="https://www.cztcode.com/wp-content/uploads/2021/08/image-43.png" alt="" class="wp-image-4097" /></figure>



<h2 class="wp-block-heading">动态路由</h2>



<p class="is-style-iw-2em">在route中可以加上/:params来表示动态路由：</p>



<pre class="wp-block-code"><code>// route
  {
    path: "/user/:username",
    component: ()=&gt;{
      return import("../pages/User.vue")
    }
  }</code></pre>



<p class="is-style-iw-2em">在route-link中，必须要匹配到对应的格式才能正确路由：</p>



<pre class="wp-block-code"><code>// route-link
    &lt;router-link :to="'/user/'+name"&gt;用户&lt;/router-link&gt;</code></pre>



<p class="is-style-iw-2em">在组件中获取动态路由的参数：一是从this中获取，在this.$route中：</p>



<pre class="wp-block-code"><code>&lt;template&gt;
  &lt;div&gt;
    &lt;h2&gt;User: {{$route.params.username}}&lt;/h2&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
  export default {
    created() {
      console.log(this.$route.params.username);
    },
  }
&lt;/script&gt;</code></pre>



<p class="is-style-iw-2em">二是使用vue-route 4的钩子函数useRoute直接获取这个组件的route：</p>



<pre class="wp-block-code"><code>&lt;script&gt;
import {useRoute, useRouter} from "vue-router"
  export default {
    setup(props) {
      const route = useRoute();
      console.log(route.params.username);
    }
  }
&lt;/script&gt;</code></pre>



<p class="is-style-iw-2em">嵌套路由同理。</p>



<h2 class="wp-block-heading">NotFound</h2>



<p class="is-style-iw-2em">定义一个类似于动态路由中的route，不过path是固定写法：</p>



<pre class="wp-block-code"><code>  {
    // 固定写法pathMatch
    path: "/:pathMatch(.*)",
    component: ()=&gt;{
      return import("../pages/NotFound.vue")
    }
  }</code></pre>



<p class="is-style-iw-2em">由此可以导向我们编写的NotFound的组件。</p>



<p class="is-style-iw-2em">获取NotFound时的路径的方法：从route.params.pathMatch中获取：</p>



<pre class="wp-block-code"><code>&lt;h2&gt;{{$route.params.pathMatch}}&lt;/h2&gt;</code></pre>



<p class="is-style-iw-2em">如果在/:pathMatch(.*)后面再加上一个*，就会将路径按照每一个&#8221;/&#8221;为分隔符进行分割并返回一个数组。</p>



<h2 class="wp-block-heading">嵌套路由</h2>



<p class="is-style-iw-2em">现在home组件下还有两个子组件HomeShops和HomeMessage，分别应该使用/home/shops和/home/message来访问之，在配置路由时，在home的路由下的children属性来为这两个组件配置。</p>



<pre class="wp-block-code"><code>&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;path:&nbsp;'/home',&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;component:&nbsp;()=&gt;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;import(/*&nbsp;webpackChunkName:&nbsp;"home-chunk"&nbsp;*/"../pages/Home.vue")
&nbsp;&nbsp;&nbsp;&nbsp;},
&nbsp;&nbsp;&nbsp;&nbsp;name:&nbsp;"home",
&nbsp;&nbsp;&nbsp;&nbsp;meta:&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name:&nbsp;"shopkeeper"
&nbsp;&nbsp;&nbsp;&nbsp;},
&nbsp;&nbsp;&nbsp;&nbsp;children:&nbsp;&#091;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;path:'shops',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;component:&nbsp;()=&gt;&nbsp;import("../pages/HomeShops.vue")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;path:'message',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;component:()=&gt;&nbsp;import("../pages/HomeMessage.vue")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;]
&nbsp;&nbsp;},</code></pre>



<p class="is-style-iw-2em">可以发现在children中的route，path缺省了父组件的&#8221;/home&#8221;，并且也不需要加上&#8221;/&#8221;。</p>



<p class="is-style-iw-2em">在children中设置重定向，path直接填写空字符串即可，但是redirect内容要填写完整的重定向路径：</p>



<pre class="wp-block-code"><code>    children: &#091;
      {
        path:"",
        redirect:"/home/message"
      },
      {
        path:'shops',
        component: ()=&gt; import("../pages/HomeShops.vue")
      },
      {
        path:'message',
        component:()=&gt; import("../pages/HomeMessage.vue")
      }
    ]</code></pre>



<h2 class="wp-block-heading">编程式导航</h2>



<p class="is-style-iw-2em">编程式导航是指通过代码来实现跳转逻辑。例如我们需要点击一个按钮来跳转到“关于”页，假设有如下的button：</p>



<pre class="wp-block-code"><code>&nbsp;&nbsp;&nbsp;&nbsp;&lt;button&nbsp;@click="jumpToAbout"&gt;关于&lt;/button&gt;</code></pre>



<p class="is-style-iw-2em">对于jumpToAbout方法，如果是在methods的options中定义，可以直接使用this.$router对象：</p>



<pre class="wp-block-code"><code>  methods: {
    jumpToAbout(){
      // 首先要拿到router对象（不推荐直接导入）
      this.$router.push("/about");
    }
  },</code></pre>



<p class="is-style-iw-2em">如果是在setup中，需要使用一个和useRoute相似的钩子函数useRouter：</p>



<pre class="wp-block-code"><code>import&nbsp;{useRouter}&nbsp;from&nbsp;'vue-router'
export&nbsp;default&nbsp;{
&nbsp;&nbsp;components:&nbsp;{
&nbsp;&nbsp;},
&nbsp;&nbsp;setup(props)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;router&nbsp;=&nbsp;useRouter();
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;jumpToAbout(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;首先要拿到router对象（不推荐直接导入）
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;router.push("/about");
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name:&nbsp;"shopkeeper"
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;},</code></pre>



<p class="is-style-iw-2em">在这个push方法中还可以传入一个对象（router-link的to属性也可以传入对象），对象中可以包含其它的一些配置，例如：</p>



<pre class="wp-block-code"><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;router.push({
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;path:"/about",
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;query:{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name:&nbsp;"shopkeeper",
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;age:18
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});</code></pre>



<p class="is-style-iw-2em">参数可以在子组件的$route.query中获取：</p>



<pre class="wp-block-code"><code>&lt;h2&gt;About:&nbsp;{{$route.query.name}}-{{$route.query.age}}&lt;/h2&gt;</code></pre>



<p class="is-style-iw-2em">router还有的方法例如replace、go、forward、back等都和history中的用法相同。</p>



<h2 class="wp-block-heading">router-link的v-slot</h2>



<p class="is-style-iw-2em">router-link实际上可以看作是一个插槽，在这个标签的内部可以写入我们想要展示的元素或者组件：</p>



<pre class="wp-block-code"><code>&nbsp;&nbsp;&nbsp;&nbsp;&lt;router-link&nbsp;to="/home"&nbsp;replace&nbsp;active-class="home-active"&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;nav-bar&nbsp;title="首页"&gt;&lt;/nav-bar&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/router-link&gt;</code></pre>



<p class="is-style-iw-2em">route-link中定义v-slot属性，可以获取其内部传来的一个对象：</p>



<pre class="wp-block-code"><code>    &lt;!-- props：href 跳转的链接 --&gt;
    &lt;!-- props：route对象 --&gt;
    &lt;!-- props：navigate函数 --&gt;
    &lt;!-- props：isActive 当前是否处于活跃状态 --&gt;
    &lt;!-- props：isExactActive 是否是精确活跃状态 --&gt;
    &lt;router-link to="/home" replace active-class="home-active" v-slot="props" custom&gt;
      &lt;!-- &lt;nav-bar title="首页"&gt;&lt;/nav-bar&gt; --&gt;
      &lt;button&gt;{{props.href}}&lt;/button&gt;
      &lt;p&gt;{{props.route}}&lt;/p&gt;
      &lt;button @click="props.navigate"&gt;导航&lt;/button&gt;
      &lt;span :class="{'active': props.isActive}"&gt;{{props.isActive}}&lt;/span&gt;
    &lt;/router-link&gt;</code></pre>



<p class="is-style-iw-2em">如果再加上custom属性的话，router-link将不会给插槽中的组件外层嵌套一个a标签，即此时跳转需要我们手动执行（使用props.navigate函数）。</p>



<h2 class="wp-block-heading">router-view的v-slot</h2>



<p class="is-style-iw-2em">router-view也可以使用插槽，在v-slot中可以获取props.Component属性，即当前要显示的组件，通过这种方式就可以结合transition、component、keep-live等组件使用</p>



<h2 class="wp-block-heading">动态添加/删除路由</h2>



<p class="is-style-iw-2em">对于一些需要选择性注释的路由，可以动态添加：</p>



<pre class="wp-block-code"><code>// 动态添加路由
const categoryRoute = {
  path: "/category",
  component: ()=&gt;import("../pages/Category.vue") 
}
const momentRoute = {
  path: "moment",
  component: ()=&gt;import("../pages/HomeMoment.vue") 
}
// 添加顶级的路由对象
router.addRoute(categoryRoute);
// 添加二级的路由对象
router.addRoute("home",momentRoute);</code></pre>



<p class="is-style-iw-2em">动态删除一个路由有三种方式：</p>



<ul class="wp-block-list"><li>添加一个name相同的路由，之前的路由就会被替代</li><li>通过removeRoute方法，传入路由的名称</li><li>通过addRoute方法的返回值回调（返回的值是一个删除路由的函数）</li></ul>



<p class="is-style-iw-2em">路由的其它一些方法补充：</p>



<ul class="wp-block-list"><li>router.hasRoute() 检查路由是否存在</li><li>router.getRoutes() 获取一个包含所有路由记录的数组</li></ul>



<h2 class="wp-block-heading">路由导航守卫</h2>



<p class="is-style-iw-2em">路由的导航守卫有多种函数可以实现，现在以beforeEach为例，beforeEach种传入一个函数：</p>



<pre class="wp-block-code"><code>// to：Route对象，即将跳转到的route对象
// from：Route对象，从哪个路由对象导航过来的
/**
 * 返回值：
 * 1.false：不进行导航
 * 2.undefined或者不写返回值：进行默认的导航
 * 3.字符串：路径，跳转到对应的路径中
 * 4.对象：类似于router.push({path:"/login",component})
 */
router.beforeEach((to, from)=&gt;{
  console.log(to.path,from.path);
  if (to.path.indexOf("/home")!==-1){
    return "/login"
  }
})</code></pre>



<p class="is-style-iw-2em">使用导航守卫实现一个简单的登录逻辑：假定login组件中，按下登录按钮就会在localStorage中保存一个token，</p>



<pre class="wp-block-code"><code>&lt;template&gt;
  &lt;div&gt;
    &lt;button @click="loginClick"&gt;登录&lt;/button&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
import {useRouter} from 'vue-router'
  export default {
    setup(props) {
      const router=useRouter()
      const loginClick=()=&gt;{
        window.localStorage.setItem("token","shopkeper")
        router.push({
          path:"/home"
        })
      }
      return {loginClick}
    }
  }
&lt;/script&gt;</code></pre>



<p class="is-style-iw-2em">那么在导航守卫中，如果要跳转到一个非login的页面，都应该判断本地是否有token，如果没有就应该跳转到login组件中：</p>



<pre class="wp-block-code"><code>router.beforeEach((to, from)=&gt;{
  if (to.path!== "/login"){
    const token = window.localStorage.getItem("token");
    if (!token){
      return "/login"
    }
  }
})</code></pre>



<p class="is-style-iw-2em">其它的导航守卫可以参考<a href="https://next.router.vuejs.org/zh/guide/advanced/navigation-guards.html#%E5%85%A8%E5%B1%80%E5%89%8D%E7%BD%AE%E5%AE%88%E5%8D%AB" class="rank-math-link" target="_blank" rel="noopener">官网</a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.cztcode.com/2021/4089/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">4089</post-id>	</item>
		<item>
		<title>OpenLayers Workshop（六）Raster Operations</title>
		<link>https://www.cztcode.com/2021/4076/</link>
					<comments>https://www.cztcode.com/2021/4076/#respond</comments>
		
		<dc:creator><![CDATA[Jellow]]></dc:creator>
		<pubDate>Fri, 27 Aug 2021 09:36:34 +0000</pubDate>
				<category><![CDATA[Web]]></category>
		<guid isPermaLink="false">https://www.cztcode.com/?p=4076</guid>

					<description><![CDATA[OpenLayers Workshop（六）Raster Operations
Map setup 设置地图
Render elevation data 渲染高程数据
Render sea level 渲染海平面]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div>


<p class="is-style-iw-2em">到目前为止，当我们使用栅格数据（例如XYZ瓦片源）时，我们仅仅将其用于演示目的——即将数据直接渲染到地图上。然而对我们从数据中获取的像素值在渲染前进行处理也是可能的。Raster数据源提供一种对任意数量的输入的数据进行像素处理的方式。当数据源被使用在一个Image图层上市，栅格处理的结果可以被渲染到地图上。</p>



<p class="is-style-iw-2em">在本次练习中，我们将要使用高程数据来作为XYZ瓦片。我们将在数据被渲染前对其进行逐像素的操作，而不是直接渲染编码过的高程数据。</p>


]]></content:encoded>
					
					<wfw:commentRss>https://www.cztcode.com/2021/4076/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">4076</post-id>	</item>
		<item>
		<title>OpenLayers Workshop（五）Vector tiles and Mapbox styles</title>
		<link>https://www.cztcode.com/2021/4068/</link>
					<comments>https://www.cztcode.com/2021/4068/#respond</comments>
		
		<dc:creator><![CDATA[Jellow]]></dc:creator>
		<pubDate>Fri, 27 Aug 2021 05:58:11 +0000</pubDate>
				<category><![CDATA[Web]]></category>
		<guid isPermaLink="false">https://www.cztcode.com/?p=4068</guid>

					<description><![CDATA[OpenLayers Workshop（五）Vector tiles and Mapbox styles
The VectorTile layer VectorTile 图层Making things look bright 让地图看上去明亮一点
Interact with VectorTile features 与矢量瓦片特征交互]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div>


<p class="is-style-iw-2em">在这个模块中我们将要学习OpenLayers所有与vector tiles相关的内容，并使用 <a rel="noreferrer noopener" href="https://npmjs.com/package/ol-mapbox-style" target="_blank">ol-mapbox-style</a> 工具来处理Mapbox样式的文件。</p>


]]></content:encoded>
					
					<wfw:commentRss>https://www.cztcode.com/2021/4068/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">4068</post-id>	</item>
		<item>
		<title>OpenLayers Workshop（四）WebGL Meteor Shower</title>
		<link>https://www.cztcode.com/2021/4053/</link>
					<comments>https://www.cztcode.com/2021/4053/#respond</comments>
		
		<dc:creator><![CDATA[Jellow]]></dc:creator>
		<pubDate>Thu, 26 Aug 2021 13:45:52 +0000</pubDate>
				<category><![CDATA[Web]]></category>
		<guid isPermaLink="false">https://www.cztcode.com/?p=4053</guid>

					<description><![CDATA[OpenLayers Workshop（四）WebGL Meteor Shower
Rendering meteorites with Canvas 2D 用Canvas 2D渲染陨石
Rendering points with WebGL 用WebGL渲染点
Animating meteorite impacts 为陨石撞击添加动画效果]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div>


<p class="is-style-iw-2em">在这个模块中，我们将使用WebGL来对CSV文件的陨石撞击数据进行自定义渲染。</p>



<p class="is-style-iw-2em">这个模块使用Canvas 2D的上下文来渲染带有法向量图层的点，然后我们使用新的点渲染工具去使用WebGL来渲染同样的数据。最后我们将开发一个自定义的片段着色器来展示如何动态设置数据样式。</p>


]]></content:encoded>
					
					<wfw:commentRss>https://www.cztcode.com/2021/4053/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">4053</post-id>	</item>
		<item>
		<title>OpenLayers Workshop（三）Mobile Maps and Sensors</title>
		<link>https://www.cztcode.com/2021/4046/</link>
					<comments>https://www.cztcode.com/2021/4046/#respond</comments>
		
		<dc:creator><![CDATA[Jellow]]></dc:creator>
		<pubDate>Sun, 22 Aug 2021 12:51:58 +0000</pubDate>
				<category><![CDATA[Web]]></category>
		<guid isPermaLink="false">https://www.cztcode.com/?p=4046</guid>

					<description><![CDATA[OpenLayers Workshop（三）Mobile Maps and Sensors
A mobile map 制作一个移动端的地图
Geolocation 
Compass]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div>


<p class="is-style-iw-2em">在这个模块中,我们将创建一个显示用户地理位置与朝向的移动端地图.这个例子的目的是展示如何将OpenLayers与第三方工具结合.</p>



<p class="is-style-iw-2em">使用浏览器的Geolocation API来获取GPS位置,用第三方库<a rel="noreferrer noopener" href="https://npmjs.com/package/kompas" target="_blank">kompas</a>来获取用户设备陀螺仪的朝向,并将结果通过vector layer展现到地图上.</p>


]]></content:encoded>
					
					<wfw:commentRss>https://www.cztcode.com/2021/4046/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">4046</post-id>	</item>
	</channel>
</rss>
