Skip to content

Commit

Permalink
Merge pull request #3 from linxianxi/feat-refactor
Browse files Browse the repository at this point in the history
feat: refactor encode、decode
  • Loading branch information
linxianxi authored Feb 7, 2023
2 parents e623deb + 49b0582 commit 2315ec3
Show file tree
Hide file tree
Showing 17 changed files with 2,190 additions and 441 deletions.
40 changes: 40 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Release

on:
push:
branches:
- master

jobs:
release:
name: Release
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3

- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: 14

- name: Install modules
run: npm i

- name: Build
run: npm run build

- name: Build Examples
run: npm run build-examples

- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dist-examples

- name: Release
uses: cycjimmy/semantic-release-action@v3
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ lerna-debug.log*
node_modules
dist
dist-ssr
dist-examples
*.local
package-lock.json

Expand Down
3 changes: 0 additions & 3 deletions .vscode/extensions.json

This file was deleted.

245 changes: 91 additions & 154 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,29 @@ OR
yarn add vue-use-sync-url
```

## API

## useSyncUrl

| 属性 | 描述 | 类型 |
| --------------- | ----------------------------------------------------------------------------------- | ------------------------------- |
| configs | 配置 | [SyncUrlConfig](#SyncUrlConfig) |
| onDecodeSuccess | 页面第一次加载或浏览器前进回退, decode 结束会触发的函数,参数为是否由前进回退触发。 | (isPopstate: boolean) => void |

返回一个函数,可以传入在配置之外的值。例如 `syncToUrl({a: "1"})`

### SyncUrlConfig

| 属性 | 描述 | 类型 | 默认值 |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------- | ------ |
| name | 显示在 url 上的名称 | string | - |
| encode | 将值转换到 url 上的操作,不是 string 类型的会自动转换为 string 类型 | () => string \| number \| boolean \| undefined \| null \| (string \| number \| boolean \| undefined \| null)[] | - |
| decode | 将 url 上的值转换到页面上的操作,第一个参数为对应 name 的值,第二个参数为当前 url 上所有的值,第三个参数表示是否由前进回退触发 | (value: string \| string[], allValues: Record<string, string \| string[]>, isPopstate: boolean) => void | - |
| omitEmptyString | encode 时,值为空字符串 `""` 时是否忽略 | boolean | true |
| omitNull | encode 时,值为 null 时是否忽略 | boolean | true |
| omitUndefined | encode 时,值为 undefined 时是否忽略 | boolean | true |
| false |

## Usage

### url 参数的基础知识
Expand All @@ -25,7 +48,7 @@ yarn add vue-use-sync-url
假设 url 上的参数为 `?a=1&a=2&b=true`,来看看获取参数的方法

```js
const searchParams = new URLSearchParams(window.location.search);
const searchParams = new URL(location.href).searchParams;

// ["1", "2"]
searchParams.getAll("a");
Expand All @@ -49,66 +72,50 @@ searchParams.get(b);
```vue
<script setup>
import { reactive, onMounted } from "vue";
import useSyncUrl from "vue-use-sync-url";
import isDate from "lodash/isDate";
import useSyncUrl, { toBoolean } from "vue-use-sync-url";
// 筛选控件的组件值
const values = reactive({
keywords: "",
status: undefined,
enable: undefined, // boolean 类型
date: "",
status: "",
enable: "",
});
const booleanValues = {
true: true,
false: false,
};
const { searchParams, syncToUrl } = useSyncUrl({
configs: [
{
key: "keywords",
omitEmptyString: true,
},
{
key: "status"
},
{
key: "enable",
decode: (value) => {
const result = booleanValues[values];
return result === undefined ? null : result
},
},
{
// 根据 element-plus 日期组件值的格式来处理 encode 和 decode 逻辑
key: "date",
encode: (value) => (value ? new Date(value).toISOString() : {}),
decode: (value) => (isDate(new Date(value)) ? value : {}),
}
],
onDecode: (params, isPopstate) => {
Object.key(params).forEach(key => {
values[key] = params[key]
});
// 在这里获取数据
// 由浏览器前进回退触发
if(isPopstate) {
}
const syncToUrl = useSyncUrl({
configs: [
{
name: "keywords",
decode: (value) => {
values.keywords = value;
},
encode: () => values.keywords,
},
{
name: "status",
decode: (value) => {
values.status = value;
},
encode: () => values.status,
},
{
name: "enable",
decode: (value) => {
values.enable = toBoolean(value);
},
encode: () => values.enable,
},
],
onDecodeSuccess: (isPopstate) => {
//get data
fetch(....)
},
});
const handleSearch = () => {
syncToUrl(values);
// 存储到 storage,使用 router.push(`/example1${localStorage.getItem("search")}`)
localStorage.setItem("search", window.location.search);
// 或存储 searchParams router.push({ path: "/example1", query: JSON.parse(localStorage.getItem("search")) })
localStorage.setItem("search", JSON.stringify(searchParams));
}
syncToUrl();
// 你可以存储到 storage,比如在详情页使用 router.push(`/base${localStorage.getItem("search")}`)
localStorage.setItem("search", location.search);
};
</script>
<template>
Expand All @@ -121,57 +128,35 @@ const handleSearch = () => {
<el-option :value="true" label="true" />
<el-option :value="false" label="false" />
</el-select>
<el-date-picker v-model="values.date" />
<el-button @click="handleSearch">search</el-button>
</template>
```

也可以使用 [encodeURIComponent](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent)[decodeURIComponent](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent) 编码复杂的数据结构

```js
const values = reactive({
obj: { a: { b: { c: 1 } } },
});

const { syncToUrl } = useSyncUrl({
configs: [
{
key: "obj",
encode: (value) => encodeURIComponent(JSON.stringify(value)),
decode: (value) => JSON.parse(decodeURIComponent(value)),
},
],
});
```

**configs**

配置需要进行 url 同步的 key 值,key 值与组件 `values` 的 key 值相对应。在你需要进行同步的时候将所有组件值传入 `syncToUrl` 并执行。

**key**

同步到 url 上的 key 值,执行 `syncToUrl` 时必须传入包含此 key 的值。

**decode**

自定义将 url 参数转换成组件值的方法。第一个参数的值为 url 上 key 的值。如果设置了 [decodeKeys](#decodeKeys),则第一个参数为其对象值。
**encode 例子**

**encode**

自定义将组件值转成 url 参数的方法。例子中判断 `date` 的值是否为 `null` 来处理结果。如果返回空对象 `{}` 则会被忽略,不会同步到 url。每个选项返回的值最后会被收集到 [onDecode](#onDecode) 中的第一个参数中。
自定义将组件值转成 url 参数的方法。如果返回空对象 `{}` 则会被忽略,不会同步到 url。

```js
// 转换成 test=1
// 转换成 name=1
{
key: "test",
name: "name",
encode: () => {
return "1"
}
}

// 转换成 name=undefined
{
name: "name",
omiUndefined: false,
encode: () => {
return undefined
}
}

// 转换成 a=1&b=2
{
key: "test",
name: "name",
encode: () => {
return {
a: "1",
Expand All @@ -182,7 +167,7 @@ const { syncToUrl } = useSyncUrl({

// 转换成 a=1&b=2&b=3
{
key: "test",
name: "name",
encode: () => {
return {
a: "1",
Expand All @@ -193,80 +178,32 @@ const { syncToUrl } = useSyncUrl({

// 忽略
{
key: "test",
name: "name",
encode: () => {
return {}
}
}
```

<span id="decodeKeys">**decodeKeys**</span>

`encode` 返回的是对象,需要设置 `decodeKeys` 为返回对象的 key 值数组。这样 `decode` 的第一个参数才会解析成返回对象,否为会返回设置的 key 的值。

```js
// 转换成 a=1
{
key: "test",
decodeKeys: ["a", "b"],
encode: (value: string[]) => ({
a: value[0],
b: value[1],
}),
decode: (value) => {
// value 为 url 参数中 decodeKeys 的对象值 { a: "1", b: "2" },如果 url 参数中 没有则为空对象 {}
...
name: "name",
encode: () => {
return {
a: "1",
b: undefined,
}
}
}
```

**omitEmptyString**

执行 `syncToUrl` 时,值为空字符串 `""` 时是否忽略,如果设置了 `encode` 则无效,`encode` 优先级高。默认为 `true`

**omitUndefined**

执行 `syncToUrl` 时,值为 `null` 时是否忽略,如果设置了 `encode` 则无效,`encode` 优先级高。默认为 `true`

**omitNull**

执行 `syncToUrl` 时,值为 `null` 时是否忽略,如果设置了 `encode` 则无效,`encode` 优先级高。默认为 `true`

<span id="onDecode">**onDecode** (params: Record<string, any>, isPopState: boolean) => void</span>

页面第一次加载或浏览器前进回退时会触发的函数,`params` 为各个配置项 decode 返回的值的集合,`isPopState` 判断是否由浏览器前进回退触发,为 `false` 则为页面第一次加载触发,加载触发时在 `onMounted` 之前执行。

##

## Type Declarations

```ts
type EncodeResult = string | number | boolean | (string | number | boolean)[];

interface useSyncUrlConfig {
key: string;
decodeKeys?: string[];
/**
* @default true
*/
omitEmptyString?: boolean;
/**
* @default true
*/
omitUndefined?: boolean;
/**
* @default true
*/
omitNull?: boolean;
decode?: (value: any) => any;
encode?: (value: any) => EncodeResult | Record<string, EncodeResult>;
}

interface useSyncUrlOptions {
/**
* @default "history"
*/
mode?: "history" | "hash";
configs: useSyncUrlConfig[];
onDecode: (params: Record<string, any>, isPopState: boolean) => void;
// 转换成 a=1&b=undefined
{
name: "name",
omitUndefined: false,
encode: () => {
return {
a: "1",
b: undefined,
}
}
}
```
Loading

0 comments on commit 2315ec3

Please sign in to comment.