winney

It is never too old to learn.

0%
winney

layui表格中的复选框

在实现全选所有页面的数据之前,先看一下layui表格中的复选框能实现的功能。

HTML:

1
<table id="testTable" lay-filter="testTable"></table>

JavaScript:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
layui.use(['table', 'jquery', 'form'], function () {
var table = layui.table
, form = layui.form
, $ = layui.jquery
, list = []
, selectedIds = []; // 存放已选中行的id数组

function getRandomName() {
var letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
var name = '';
for (var i = 0; i < 5; i++) {
name += letters.charAt(Math.floor(Math.random() * letters.length));
}
return name;
}

for (var i = 1; i <= 100; i++) {
list.push({ id: i, name: getRandomName(), score: Math.floor(Math.random() * 1000) + 1 });
}


table.render({
elem: '#testTable'
, data: list
, page: true // 开启分页
, limit: 10
, cols: [[
// { checkbox: true }
{ type:'checkbox' }
, { field: 'id', title: 'ID' }
, { field: 'name', title: '用户名' }
, { field: 'score', title: '评分' }
]]
, done: function (res) {
// console.log(res);
}
});


// 监听table复选框的选择事件
table.on('checkbox(testTable)', function (obj) {
// console.log(obj); // 当前行的一些常用操作集合
// console.log(obj.checked); // 当前是否选中状态
// console.log(obj.data); // 选中行的相关数据
// console.log(obj.type); // 如果触发的是全选,则为:all,如果触发的是单选,则为:one

// var selectedData; // 选中行的相关数据
// selectedData = table.checkStatus('testTable').data;
// selectedIds = selectedData.map(item => item.id);
// // 进行排序
// selectedIds.sort(function (a, b) {
// return a - b;
// });

selectedIds = table.checkStatus('testTable').data.map(item => item.id).sort(function (a, b) {
return a - b;
});

console.log('selectedIds');
console.log(selectedIds);

});

});

在表格中,添加复选框:在cols中添加{ checkbox: true }{ type:'checkbox' }

获取选中行的数据:table.checkStatus('testTable').data;

这里使用sort,是为了方便看数据,如果没有这个要求,可以不加。

layui-table-checkbox1.png (1216×508) (raw.githubusercontent.com)

layui-table-checkbox2.png (1117×506) (raw.githubusercontent.com)

如果需求中,按表头的复选框进行全选的时候需要获取到所有页面的数据。根据上面的展示,layui表格中默认的复选框的全选,获取不到所有页面的数据。

layui表格中表头的复选框实现全选所有页面的数据-多次操作

完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
layui.use(['table', 'jquery', 'form'], function () {
var table = layui.table
, form = layui.form
, $ = layui.jquery
, list = []
, temp = [] // 当前页的数据
, selectedIds = []; // 存放已选中行的id数组

function getRandomName() {
var letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
var name = '';
for (var i = 0; i < 5; i++) {
name += letters.charAt(Math.floor(Math.random() * letters.length));
}
return name;
}

for (var i = 1; i <= 100; i++) {
list.push({ id: i, name: getRandomName(), score: Math.floor(Math.random() * 1000) + 1 });
}

table.render({
elem: '#testTable'
, data: list
, page: true //开启分页
, limit: 10
, cols: [[
{ checkbox: true }
, { field: 'id', title: 'ID' }
, { field: 'name', title: '用户名' }
, { field: 'score', title: '评分' }
]]
, done: function (res) {
// 切换页面时,获取当前页的数据
temp = res.data.map(function (item) {
return item.id;
})
}
});

// 监听table复选框的选择事件
table.on('checkbox(testTable)', function (obj) {
if (obj.type === 'all') { // 表头的全选复选框
if (obj.checked) { // 选中状态
for (var i = 0; i < temp.length; i++) {
var valueToAdd = temp[i];
// 检查 arr 数组是否已经包含当前值,如果没有则追加
if (!selectedIds.includes(valueToAdd)) {
// 追加
selectedIds.push(valueToAdd);
}
}
} else { // 未选中状态
// 减去
selectedIds = selectedIds.filter(function (item) {
return !temp.includes(item);
});
}

} else { // 每行上的复选框
if (obj.checked) { // 选中状态
// 追加
selectedIds.push(obj.data.id);
} else { // 未选中状态
// 减去
var index = selectedIds.indexOf(obj.data.id);
selectedIds.splice(index, 1);
}
}

// 进行排序
selectedIds.sort(function (a, b) {
return a - b;
});
});

});

这里代码没有进行优化和封装,是为了大家更方便地看清它的逻辑

难点

全选时,怎么去记住不同页面中的数据,如何实现追加数据和减去数据的过程。

刚好在done中可以获取到渲染当前页的数据。

1
2
3
4
5
6
done: function (res) {
// 切换页面时,获取当前页的数据
temp = res.data.map(function (item) {
return item.id;
})
}

缺点与不足:需要每页都要点一次表头的全选复选框,不能一步到位。

layui表格中表头的复选框实现全选所有页面的数据-一次全选

使用渲染表格时的templettitle,手动创建复选框,不使用table默认添加复选框的方法({ type:'checkbox' })添加复选框。

完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
layui.use(['table', 'jquery', 'form'], function () {
var table = layui.table
, form = layui.form
, $ = layui.jquery
, list = []
, selectedIds = []; // 存放已选中行的id数组

function getRandomName() {
var letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
var name = '';
for (var i = 0; i < 5; i++) {
name += letters.charAt(Math.floor(Math.random() * letters.length));
}
return name;
}

for (var i = 1; i <= 100; i++) {
list.push({ id: i, name: getRandomName(), score: Math.floor(Math.random() * 1000) + 1 });
}

var adTable = {
/*
* 获取表格当前页码
* @param key:缓存中pages的key值
* @param data:填充表格的数据数组
* @param limit:每页显示条数
*/
getPageCur: function(key, data, limit) {
var cur, // 当前页码
obj = JSON.parse(localStorage.getItem("pages")), // 缓存中的pages对象
totalPage = Math.ceil(data.length/limit); // 总页数
// 存在缓存变量pages
if(obj) {
// 缓存中是否有当前表格的页码记录(没有该页码记录,重置为1)
cur = obj[key] ? obj[key] : 1;
} else {
// 不存在缓存变量pages
cur = 1;
}
// 总页数小于当前页码(解决表格删除最后一页最后一条数据)
if(totalPage < cur) {
cur = 1;
}
return cur;
}
/*
* 设置当前表格页码
* @param key:key值
* @param val:value值
*/
, setPageCur: function(key, val) {
// 使用对象缓存,是因为有些页面有多层页面,记住多个页面的页码
var pages = JSON.parse(localStorage.getItem("pages")) || {}; // 缓存中pages对象
pages[key] = val; // 设置页码
pages = JSON.stringify(pages);
localStorage.setItem("pages", pages); // 重新放到缓存中
}
}

var page_curr = adTable.getPageCur("testTable", list, 10); // 10是分页的limit值
table.render({
elem: '#testTable'
, data: list
, page: {
curr: page_curr
, limit: 10
}
, cols: [[
{
field: 'checkbox', title: '<input type="checkbox" id="checkAll" lay-filter="checkAll" lay-skin="primary">', width: 66, templet: function (res) {
return '<input type="checkbox" class="rowCheck" data-id="' + res.id + '" lay-filter="rowCheck" lay-skin="primary">';
}
}
, { field: 'id', title: 'ID' }
, { field: 'name', title: '用户名' }
, { field: 'score', title: '评分' }

]]
, done: function (res, curr, count) {
// 重置表格的样式
if(selectedIds.length > 0) {
// 根据已选selectedIds集合,修改复选框的样式(表头的复选框针对所有行数据,layui框架的全选只针对当前页)
selectedIds.map(function(item) {
$('.layui-table input[data-id="'+ item +'"]').prop('checked', true);
})
// 重新渲染
form.render('checkbox');
}

// 记录当前页面
adTable.setPageCur("testTable", curr);
}
});

// 监听表格中表头全选复选框的选择事件
form.on('checkbox(checkAll)', function (data) {
if (!list.length) {
$('input[lay-filter="checkAll"]').prop('checked', false);
}
// 是否全选
var isAllChecked = data.elem.checked ? true : false;

// 是否被选中
if (isAllChecked) {
selectedIds = list.map(function (item) {
return item.id;
})
} else {
selectedIds = [];
}

console.log(selectedIds);

// 更新表格中的复选框样式
$('.rowCheck').prop('checked', isAllChecked);
form.render('checkbox');
});

// 监听表格中的复选框
form.on('checkbox(rowCheck)', function (data) {
var isChecked = data.elem.checked // 是否被选中
, isAllChecked = false // 是否全选
, _id = $(data.elem).data("id");// 当前项的id

if (isChecked) {
// 追加
selectedIds.push(_id);
isAllChecked = (selectedIds.length == list.length) ? true : false;
} else {
// 减去
var index = selectedIds.indexOf(_id);
selectedIds.splice(index, 1);

isAllChecked = false;
}
// 进行排序
selectedIds.sort(function (a, b) {
return a - b;
});

console.log('selectedIds');
console.log(selectedIds);

// 更新全选复选框的样式
$('#checkAll').prop('checked', isAllChecked);
form.render('checkbox');

});
});

说明

  1. 获取页面当前页码的方法adTable.getPageCur,大家可以根据自己的实际情况来实现。因为这里有多个表格,所以我放在pages对象中,不同的表格,根据表格名称来缓存对应的页码。

  2. 难点和关键代码:

    1
    2
    3
    4
    5
    {
    field: 'checkbox', title: '<input type="checkbox" id="checkAll" lay-filter="checkAll" lay-skin="primary">', width: 66, templet: function (res) {
    return '<input type="checkbox" class="rowCheck" data-id="' + res.id + '" lay-filter="rowCheck" lay-skin="primary">';
    }
    }
    1. title属性一定要配置。
    2. .rowCheck一定要记得配置对应的id: data-id="' + res.id + '"

如果有问题,可以留言联系。

使用宝塔和wordpress搭建个人博客

1.宝塔的安装

1.1安装方式

  1. 编程导航 搜”宝塔“
  2. 选择”Linux面板“(选择安装
  3. 选“安装脚本”
  4. 复制 “Centos安装脚本” 的代码
  5. 粘贴命令,直接安装【在git上登录服务器,切换到opt目录(cd /opt)】
  6. 把面板地址和用户名密码记住

1.2 8888端口不可以访问-要做以下两个配置

  1. 在腾讯云控制台,配置安全组

    配置安全组

  2. 在腾讯云控制台,配置防火墙

    配置防火墙

2.登录面板地址后

2.1注册宝塔账号

2.2安装推荐套件(使用默认推荐即可)

备注:安装LNMP(推荐)

配置防火墙

3.网站-添加站点

4. WordPress安装

备注:1.先把刚建的站点删除,以免冲突;

4.1wordpress官网下载安装包( .tar.gz格式的)

4.2将 .tar.gz文件上传到站点根目录

4.3鼠标放上 .tar.gz文件,选择“解压”

4.4进入解压后的文件夹,将里面的文件全部复制到站点根目录

4.5安装包和解压后的文件夹可以删掉了

宝塔wordpress安装及使用(宝塔wordpress建站教程)

宝塔面板安装wordpress详细教程

添加子域名

在阿里云-控制台-域名解析-解析设置,添加记录值

注:需要等10分钟,才生效

VuePress

极简静态网站生成器

可以直接 云开发

https://github.com/Tencent/cloudbase-framework?site=vuepress#%E9%A1%B9%E7%9B%AE%E7%A4%BA%E4%BE%8B

配置文件:vite.config.ts

1.配置打包公共路径-base

1
base:'./'

2.配置地址别名-alias

使用简短的别名去替代一个较长的路径

__dirname:项目的绝对路径

  1. 安装

    1
    npm install --save path
  2. 引入

    1
    import { resolve } from 'path'
  3. 配置

    1
    2
    3
    4
    5
    6
    7
    8
    export default defineConfig({
    resolve:{
    alias: {
    test: resolve(__dirname, 'src/components/test/'),
    icon: resolve(__dirname, './src/assets/images/')
    }
    }
    })
  4. 使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // 修改前:
    import ViteSet from '../../components/test/ViteSet.vue';
    <img src="../../assets/images/zhangyu.svg" alt="章鱼小丸子">

    // 修改后:
    import ViteSet2 from 'test/ViteSet.vue';
    <img src="icon/zhangyu.svg" alt="章鱼小丸子">


    <ViteSet></ViteSet>
    <ViteSet2></ViteSet2>

2.1图片的地址的别名-特殊处理

图片使用icon: resolve(__dirname, './src/assets/images/')这种配置,打包上线后,页面可以正常显示图片,但本地测试是加载不出图片的。

所以不能直接写 名称:resolve(...),要使用引号加斜杠开头的别名

2.1.1配置
1
2
3
4
5
resolve:{
alias: {
'/icon':'./src/assets/images/'
}
}
2.1.2使用
1
2
3
4
// 修改前:
<img src="../../assets/images/zhangyu.svg" alt="章鱼小丸子">
// 修改后:
<img src="/icon/zhangyu.svg" alt="章鱼小丸子">

这样本地环境和正式环境都能正常显示

参考:vite vue3.0 配置拦截,路由跳转

3.生产环境去除console.log的配置

build.terserOptions

1
2
3
4
5
6
7
8
9
10
11
12
export default defineConfig({
build:{
minify: 'terser', // 必须配置'terser',不然terserOptions不生效,因为minify默认不是'terser'
terserOptions: {
compress: {
//生产环境时移除console
drop_console: true,
drop_debugger: true,
},
},
}
})

3.1报错处理

打包上线会出现报错:

[vite:terser] terser not found. Since Vite v3, terser has become an optional dependency. You need to install it.

解决:Vite V3需要安装terser依赖包

1
cnpm i terser

4.mock数据的配置

1
npm i vite-plugin-mock mockjs  -D

vite-plugin-mock

使用

4.1引入

1
2
3
4
5
6
7
8
9
import { viteMockServe } from 'vite-plugin-mock'

plugins: [
vue(),
viteMockServe({
// default
mockPath: 'mock',
}),
],

4.2使用

在根目录新建mock目录

示例

4.2.1mock/index.ts:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// test.ts
import { MockMethod } from 'vite-plugin-mock'
export default [
{
url: '/api/get',
method: 'get',
response: ({ query }) => {
return {
code: 0,
data: {
name: 'vben',
},
}
},
},
{
url: '/api/post',
method: 'post',
timeout: 2000,
response: {
code: 0,
data: {
name: 'vben',
},
},
},
{
url: '/api/text',
method: 'post',
rawResponse: async (req, res) => {
let reqbody = ''
await new Promise((resolve) => {
req.on('data', (chunk) => {
reqbody += chunk
})
req.on('end', () => resolve(undefined))
})
res.setHeader('Content-Type', 'text/plain')
res.statusCode = 200
res.end(`hello, ${reqbody}`)
},
},
] as MockMethod[]
4.2.2引入axios
1
cnpm i axios
1
2
3
4
5
6
7
import axios from 'axios'

async function fn() {
const { data } = await axios.get('/api/get')
console.log(data);
}
fn()
使用mock来模拟更多数据
1
npm install mockjs --save-dev

使用示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import Mock from 'mockjs'

// 定义数据类型
var data = Mock.mock({
// 20条数据
"data|20": [{
// 商品种类
"goodsClass": "女装",
// 商品Id
"goodsId|+1": 1,
//商品名称
"goodsName": "@ctitle(10)",
//商品地址
"goodsAddress": "@county(true)",
//商品等级评价★
"goodsStar|1-5": "★",
//商品图片
"goodsImg": "@Image('100x100','@color','小甜甜')",
//商品售价
"goodsSale|30-500": 30
}]
})
// 输出结果随机生成的数据(node index.js)
console.log(data);
将mock模拟的数据放到接口返回中

mock/index.ts:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// test.ts
import { MockMethod } from 'vite-plugin-mock'
import Mock from 'mockjs'
var list = Mock.mock({
// 20条数据
"data|20": [{
// 商品种类
"goodsClass": "女装",
// 商品Id
"goodsId|+1": 1,
//商品名称
"goodsName": "@ctitle(10)",
//商品地址
"goodsAddress": "@county(true)",
//商品等级评价★
"goodsStar|1-5": "★",
//商品图片
"goodsImg": "@Image('100x100','@color','小甜甜')",
//商品售价
"goodsSale|30-500": 30

}]
})
export default [
{
url: '/api/get',
method: 'get',
response: ({ query }) => {
return {
code: 0,
data: list
}
},
},
},
] as MockMethod[]

5.配置前端跨域代理

proxy

1
2
3
4
5
6
7
8
9
server: {
proxy: {
'/ss': {
target: 'https://saucenao.com/search.php?db=999&output_type=2&url=https://pica.zhimg.com/v2-178387c7e8e907910d715e890bfd7519_1440w.jpg?source=172ae18b&api_key=33d4bee5c19583cd3756ee47f2ebef8edd5bef7e',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/ss/, ''),
},
},
},
1
2
3
axios.get('/ss').then(res => {
console.log(res);
})
1
2
3
4
5
6
7
8
9
10
11
12
13
export default defineConfig({
plugins:[vue()],
server:{ //中转服务器
proxy:{ //通过代理实现跨域
// https://i.maoyan.com
'/path':{
target:'https://i.maoyan.com', //替换的服务端地址
changeOrigin:true, //开启代理,允许跨域
rewrite: path=>path.replace(/^\/path/,'') //设置重写的路径
}
}
}
})

6.env环境变量的配置

6.1环境变量配置

.env.development

可配置多个

1
2
3
VITE_BASE_API = /api
VITE_BASE_API = /api2
VITE_BASE_API = /api3

.env.production

1
VITE_BASE_API = https://www.manga2020.com/api/v3/comic/hydxjxrwgb/chapter/cb321fca-c608-11e8-879b-024352452ce0?timeout=10000

6.2修改请求链接

1
2
3
4
5
async function fn() {
const { data } = await axios.get(import.env.VITE_BASE_API as string)
console.log(data);
}
fn()

本地环境使用mock数据: /api 正式环境使用正式的api链接

这样本地可以使用mock数据,正式使用正式的api数据。互不影响。

7.CDN的配置

备注:暂时配置不成功

vite-plugin-cdn-import

vue使用示例

1
npm install vite-plugin-cdn-import --save-dev
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import importToCDN, { autoComplete } from 'vite-plugin-cdn-import'

export default {
plugins: [
vue(),
importToCDN({
modules: [
autoComplete('vue'), // vue2 use autoComplete('vue2')
autoComplete('@vueuse/shared'),
autoComplete('@vueuse/core')
],
}),
],
}

8.代码压缩的配置-gzip

vite-plugin-compression

1
npm i vite-plugin-compression -D
1
2
3
4
5
6
7
import viteCompression from 'vite-plugin-compression';

export default () => {
return {
plugins: [viteCompression()],
};
};

9.打包图片

vite-plugin-imagemin

1
cnpm i vite-plugin-imagemin@0.4.6 -D
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import viteImagemin from 'vite-plugin-imagemin'
export default () => {
return {
plugins: [
viteImagemin({
gifsicle: {
optimizationLevel: 7,
interlaced: false,
},
optipng: {
optimizationLevel: 7,
},
mozjpeg: {
quality: 20,
},
pngquant: {
quality: [0.8, 0.9],
speed: 4,
},
svgo: {
plugins: [
{
name: 'removeViewBox',
},
{
name: 'removeEmptyAttrs',
active: false,
},
],
},
}),
],
}
}

以上代码,本地会报错,需重启一下

参考:搭建vite2.0+vue3.0+ts+多页面打包+多环境+gzip+图片压缩框架

Vite图片压缩(vite-plugin-imagemin) imagemin error: XXXX解决办法

10.element plus按需引入

做个开源博客学习Vite2 + Vue3 (二)设置别名、代理和ESLint