技术标签: 前端 vue.js javascript
效果:
由于我本地开发环境的原因需要修改webpack服务端口
修改:x-spreadsheet\build\webpack.dev.js
const merge = require('webpack-merge');
const common = require('./webpack.config.js');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = merge(common, {
mode: 'development',
plugins: [
new CleanWebpackPlugin(['dist']),
// you should know that the HtmlWebpackPlugin by default will generate its own index.html
new HtmlWebpackPlugin({
template: './index.html',
title: 'x-spreadsheet',
}),
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: '[name].[contenthash].css',
// chunkFilename: devMode ? '[id].[hash].css' : '[id].css',
}),
],
output: {
filename: '[name].[contenthash].js',
},
devtool: 'inline-source-map',
devServer: {
disableHostCheck: true,
host: '0.0.0.0',
port: 3000, // 暴露端口
contentBase: '../dist',
},
});
重点来了
修改:x-spreadsheet\src\locale\en.js增加菜单重命名
export default {
toolbar: {
undo: 'Undo',
redo: 'Redo',
print: 'Print',
paintformat: 'Paint format',
clearformat: 'Clear format',
format: 'Format',
fontName: 'Font',
fontSize: 'Font size',
fontBold: 'Font bold',
fontItalic: 'Font italic',
underline: 'Underline',
strike: 'Strike',
color: 'Text color',
bgcolor: 'Fill color',
border: 'Borders',
merge: 'Merge cells',
align: 'Horizontal align',
valign: 'Vertical align',
textwrap: 'Text wrapping',
freeze: 'Freeze cell',
autofilter: 'Filter',
formula: 'Functions',
more: 'More',
},
contextmenu: {
copy: 'Copy',
cut: 'Cut',
paste: 'Paste',
pasteValue: 'Paste values only',
pasteFormat: 'Paste format only',
hide: 'Hide',
insertRow: 'Insert row',
insertColumn: 'Insert column',
deleteSheet: 'Delete',
deleteRow: 'Delete row',
deleteColumn: 'Delete column',
deleteCell: 'Delete cell',
deleteCellText: 'Delete cell text',
validation: 'Data validations',
cellprintable: 'Enable export',
cellnonprintable: 'Disable export',
celleditable: 'Enable editing',
cellnoneditable: 'Disable editing',
rename: 'Rename', // 菜单重命名
},
print: {
size: 'Paper size',
orientation: 'Page orientation',
orientations: ['Landscape', 'Portrait'],
},
format: {
normal: 'Normal',
text: 'Plain Text',
number: 'Number',
percent: 'Percent',
rmb: 'RMB',
usd: 'USD',
eur: 'EUR',
date: 'Date',
time: 'Time',
datetime: 'Date time',
duration: 'Duration',
},
formula: {
sum: 'Sum',
average: 'Average',
max: 'Max',
min: 'Min',
_if: 'IF',
and: 'AND',
or: 'OR',
concat: 'Concat',
},
validation: {
required: 'it must be required',
notMatch: 'it not match its validation rule',
between: 'it is between {} and {}',
notBetween: 'it is not between {} and {}',
notIn: 'it is not in list',
equal: 'it equal to {}',
notEqual: 'it not equal to {}',
lessThan: 'it less than {}',
lessThanEqual: 'it less than or equal to {}',
greaterThan: 'it greater than {}',
greaterThanEqual: 'it greater than or equal to {}',
},
error: {
pasteForMergedCell: 'Unable to do this for merged cells',
},
calendar: {
weeks: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
},
button: {
next: 'Next',
cancel: 'Cancel',
remove: 'Remove',
save: 'Save',
ok: 'OK',
},
sort: {
desc: 'Sort Z -> A',
asc: 'Sort A -> Z',
},
filter: {
empty: 'empty',
},
dataValidation: {
mode: 'Mode',
range: 'Cell Range',
criteria: 'Criteria',
modeType: {
cell: 'Cell',
column: 'Colun',
row: 'Row',
},
type: {
list: 'List',
number: 'Number',
date: 'Date',
phone: 'Phone',
email: 'Email',
},
operator: {
be: 'between',
nbe: 'not betwwen',
lt: 'less than',
lte: 'less than or equal to',
gt: 'greater than',
gte: 'greater than or equal to',
eq: 'equal to',
neq: 'not equal to',
},
},
};
修改:Z:\x-spreadsheet\src\locale\zh-cn.js增加中文重命名
export default {
toolbar: {
undo: '撤销',
redo: '恢复',
print: '打印',
paintformat: '格式刷',
clearformat: '清除格式',
format: '数据格式',
fontName: '字体',
fontSize: '字号',
fontBold: '加粗',
fontItalic: '倾斜',
underline: '下划线',
strike: '删除线',
color: '字体颜色',
bgcolor: '填充颜色',
border: '边框',
merge: '合并单元格',
align: '水平对齐',
valign: '垂直对齐',
textwrap: '自动换行',
freeze: '冻结',
autofilter: '自动筛选',
formula: '函数',
more: '更多',
},
contextmenu: {
copy: '复制',
cut: '剪切',
paste: '粘贴',
pasteValue: '粘贴数据',
pasteFormat: '粘贴格式',
hide: '隐藏',
insertRow: '插入行',
insertColumn: '插入列',
deleteSheet: '删除',
deleteRow: '删除行',
deleteColumn: '删除列',
deleteCell: '删除',
deleteCellText: '删除数据',
validation: '数据验证',
cellprintable: '可打印',
cellnonprintable: '不可打印',
celleditable: '可编辑',
cellnoneditable: '不可编辑',
rename: '重命名', // 增加重命名
},
print: {
size: '纸张大小',
orientation: '方向',
orientations: ['横向', '纵向'],
},
format: {
normal: '正常',
text: '文本',
number: '数值',
percent: '百分比',
rmb: '人民币',
usd: '美元',
eur: '欧元',
date: '短日期',
time: '时间',
datetime: '长日期',
duration: '持续时间',
},
formula: {
sum: '求和',
average: '求平均值',
max: '求最大值',
min: '求最小值',
concat: '字符拼接',
_if: '条件判断',
and: '和',
or: '或',
},
validation: {
required: '此值必填',
notMatch: '此值不匹配验证规则',
between: '此值应在 {} 和 {} 之间',
notBetween: '此值不应在 {} 和 {} 之间',
notIn: '此值不在列表中',
equal: '此值应该等于 {}',
notEqual: '此值不应该等于 {}',
lessThan: '此值应该小于 {}',
lessThanEqual: '此值应该小于等于 {}',
greaterThan: '此值应该大于 {}',
greaterThanEqual: '此值应该大于等于 {}',
},
error: {
pasteForMergedCell: '无法对合并的单元格执行此操作',
},
calendar: {
weeks: ['日', '一', '二', '三', '四', '五', '六'],
months: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],
},
button: {
next: '下一步',
cancel: '取消',
remove: '删除',
save: '保存',
ok: '确认',
},
sort: {
desc: '降序',
asc: '升序',
},
filter: {
empty: '空白',
},
dataValidation: {
mode: '模式',
range: '单元区间',
criteria: '条件',
modeType: {
cell: '单元格',
column: '列模式',
row: '行模式',
},
type: {
list: '列表',
number: '数字',
date: '日期',
phone: '手机号',
email: '电子邮件',
},
operator: {
be: '在区间',
nbe: '不在区间',
lt: '小于',
lte: '小于等于',
gt: '大于',
gte: '大于等于',
eq: '等于',
neq: '不等于',
},
},
};
修改:Z:\x-spreadsheet\src\locale\locale.js切换到中文
/* global window */
import en from './en';
import zh from './zh-cn';
// Defines the fallback language as English
let $languages = ['zh'];
const $messages = {
zh
};
function translate(key, messages) {
if (messages) {
// Return the translation from the first language in the languages array
// that has a value for the provided key.
for (const lang of $languages) {
if (!messages[lang]) break;
let message = messages[lang];
// Splits the key at '.' except where escaped as '\.'
const keys = key.match(/(?:\\.|[^.])+/g);
for (let i = 0; i < keys.length; i += 1) {
const property = keys[i];
const value = message[property];
// If value doesn't exist, try next language
if (!value) break;
if (i === keys.length - 1) return value;
// Move down to the next level of the messages object
message = value;
}
}
}
return undefined;
}
function t(key) {
let v = translate(key, $messages);
if (!v && window && window.x_spreadsheet && window.x_spreadsheet.$messages) {
v = translate(key, window.x_spreadsheet.$messages);
}
return v || '';
}
function tf(key) {
return () => t(key);
}
// If clearLangList is set to false, lang will be added to the front of the
// languages array. The languages in the language array are searched in order
// to find a translation. This allows the use of other languages as a fallback
// if lang is missing some keys. The language array is preloaded with English.
// To set the languages array to only include lang, set clearLangList to true.
function locale(lang, message, clearLangList = false) {
if (clearLangList) {
$languages = [lang];
} else {
// Append to front of array.
// Translation method will use the first language in the list that has a
// matching key.
$languages.unshift(lang);
}
if (message) {
$messages[lang] = message;
}
}
export default {
t,
};
export {
locale,
t,
tf,
};
修改:x-spreadsheet\src\component\bottombar.js文件
思路:
1.保留原有双击修改sheet名称;
2.右键sheet时,激活(active)当前sheet;
3.点击菜单时判断功能,如果是重命名,则根据active获取index索引,实现重命名功能
import { h } from './element';
import { bindClickoutside, unbindClickoutside } from './event';
import { cssPrefix } from '../config';
import Icon from './icon';
import FormInput from './form_input';
import Dropdown from './dropdown';
// Record: temp not used
// import { xtoast } from './message';
import { tf } from '../locale/locale';
class DropdownMore extends Dropdown {
constructor(click) {
const icon = new Icon('ellipsis');
super(icon, 'auto', false, 'top-left');
this.contentClick = click;
}
reset(items) {
const eles = items.map((it, i) => h('div', `${cssPrefix}-item`)
.css('width', '150px')
.css('font-weight', 'normal')
.on('click', () => {
this.contentClick(i);
this.hide();
})
.child(it));
this.setContentChildren(...eles);
}
setTitle() {}
}
const menuItems = [
{ key: 'delete', title: tf('contextmenu.deleteSheet') },
{ key: 'rename', title: tf('contextmenu.rename') }, // 增加菜单重命名
];
function buildMenuItem(item) {
return h('div', `${cssPrefix}-item`)
.child(item.title())
.on('click', () => {
this.itemClick(item.key);
this.hide();
});
}
function buildMenu() {
return menuItems.map(it => buildMenuItem.call(this, it));
}
class ContextMenu {
constructor() {
this.el = h('div', `${cssPrefix}-contextmenu`)
.css('width', '160px')
.children(...buildMenu.call(this))
.hide();
this.itemClick = () => {};
}
hide() {
const { el } = this;
el.hide();
unbindClickoutside(el);
}
setOffset(offset) {
const { el } = this;
el.offset(offset);
el.show();
bindClickoutside(el);
}
}
export default class Bottombar {
constructor(addFunc = () => {},
swapFunc = () => {},
deleteFunc = () => {},
updateFunc = () => {}) {
this.swapFunc = swapFunc;
this.updateFunc = updateFunc;
this.dataNames = [];
this.activeEl = null;
this.deleteEl = null;
this.items = [];
this.moreEl = new DropdownMore((i) => {
this.clickSwap2(this.items[i]);
});
const that = this;
this.contextMenu = new ContextMenu();
// eslint-disable-next-line func-names
this.contextMenu.itemClick = function (p) {
if (p === 'delete') { // 删除
deleteFunc();
} else if (p === 'rename') { // 重命名
// eslint-disable-next-line no-plusplus
for (let index = 0; index < that.items.length; index++) {
if (that.items[index].el.getAttribute('class').includes('active') === true) {
const item = that.items[index];
that.sheetRenameItem(item);
break;
}
}
}
};
this.el = h('div', `${cssPrefix}-bottombar`).children(
this.contextMenu.el,
this.menuEl = h('ul', `${cssPrefix}-menu`).child(
h('li', '').children(
new Icon('add').on('click', () => {
addFunc();
}),
h('span', '').child(this.moreEl),
),
),
);
}
addItem(name, active, options) {
this.dataNames.push(name);
const item = h('li', active ? 'active' : '').child(name);
item.on('click', () => {
this.clickSwap2(item);
}).on('contextmenu', (evt) => {
if (options.mode === 'read') return;
const { offsetLeft, offsetHeight } = evt.target;
this.contextMenu.setOffset({ left: offsetLeft, bottom: offsetHeight + 1 });
this.deleteEl = item;
this.clickSwap2(item); // 右键激活当前sheet
}).on('dblclick', () => {
if (options.mode === 'read') return;
this.sheetRenameItem(item); // 双击重命名
});
if (active) {
this.clickSwap(item);
}
this.items.push(item);
this.menuEl.child(item);
this.moreEl.reset(this.dataNames);
}
renameItem(index, value) {
this.dataNames.splice(index, 1, value);
this.moreEl.reset(this.dataNames);
this.items[index].html('').child(value);
this.updateFunc(index, value);
}
clear() {
this.items.forEach((it) => {
this.menuEl.removeChild(it.el);
});
this.items = [];
this.dataNames = [];
this.moreEl.reset(this.dataNames);
}
deleteItem() {
const { activeEl, deleteEl } = this;
if (this.items.length > 1) {
const index = this.items.findIndex(it => it === deleteEl);
this.items.splice(index, 1);
this.dataNames.splice(index, 1);
this.menuEl.removeChild(deleteEl.el);
this.moreEl.reset(this.dataNames);
if (activeEl === deleteEl) {
const [f] = this.items;
this.activeEl = f;
this.activeEl.toggle();
return [index, 0];
}
return [index, -1];
}
return [-1];
}
clickSwap2(item) {
const index = this.items.findIndex(it => it === item);
this.clickSwap(item);
this.activeEl.toggle();
this.swapFunc(index);
}
clickSwap(item) {
if (this.activeEl !== null) {
this.activeEl.toggle();
}
this.activeEl = item;
}
sheetRenameItem(item) {
const v = item.html();
const input = new FormInput('auto', '');
input.val(v);
input.input.on('blur', (key) => {
this.renameSwitch(key, v);
}).on('keydown', (key) => {
const code = key.keyCode || key.which || key.charCode;
if (code === 13 || code === 27) { // 回车、ESC
this.renameSwitch(key, v);
}
});
item.html('').child(input.el);
input.focus();
}
renameSwitch(key, v) {
let { value } = key.target;
const nindex = this.dataNames.findIndex(it => it === v);
if (value === '') {
value = v;
}
if (nindex > -1 && value !== '') {
this.renameItem(nindex, value);
}
}
}
文章浏览阅读1.6k次。安装配置gi、安装数据库软件、dbca建库见下:http://blog.csdn.net/kadwf123/article/details/784299611、检查集群节点及状态:[root@rac2 ~]# olsnodes -srac1 Activerac2 Activerac3 Activerac4 Active[root@rac2 ~]_12c查看crs状态
文章浏览阅读1.3w次,点赞45次,收藏99次。我个人用的是anaconda3的一个python集成环境,自带jupyter notebook,但在我打开jupyter notebook界面后,却找不到对应的虚拟环境,原来是jupyter notebook只是通用于下载anaconda时自带的环境,其他环境要想使用必须手动下载一些库:1.首先进入到自己创建的虚拟环境(pytorch是虚拟环境的名字)activate pytorch2.在该环境下下载这个库conda install ipykernelconda install nb__jupyter没有pytorch环境
文章浏览阅读5.2k次,点赞19次,收藏28次。选择scoop纯属意外,也是无奈,因为电脑用户被锁了管理员权限,所有exe安装程序都无法安装,只可以用绿色软件,最后被我发现scoop,省去了到处下载XXX绿色版的烦恼,当然scoop里需要管理员权限的软件也跟我无缘了(譬如everything)。推荐添加dorado这个bucket镜像,里面很多中文软件,但是部分国外的软件下载地址在github,可能无法下载。以上两个是官方bucket的国内镜像,所有软件建议优先从这里下载。上面可以看到很多bucket以及软件数。如果官网登陆不了可以试一下以下方式。_scoop-cn
文章浏览阅读4.5k次,点赞2次,收藏3次。首先要有一个color-picker组件 <el-color-picker v-model="headcolor"></el-color-picker>在data里面data() { return {headcolor: ’ #278add ’ //这里可以选择一个默认的颜色} }然后在你想要改变颜色的地方用v-bind绑定就好了,例如:这里的:sty..._vue el-color-picker
文章浏览阅读640次。基于芯片日益增长的问题,所以内核开发者们引入了新的方法,就是在内核中只保留函数,而数据则不包含,由用户(应用程序员)自己把数据按照规定的格式编写,并放在约定的地方,为了不占用过多的内存,还要求数据以根精简的方式编写。boot启动时,传参给内核,告诉内核设备树文件和kernel的位置,内核启动时根据地址去找到设备树文件,再利用专用的编译器去反编译dtb文件,将dtb还原成数据结构,以供驱动的函数去调用。firmware是三星的一个固件的设备信息,因为找不到固件,所以内核启动不成功。_exynos 4412 刷机
文章浏览阅读2w次,点赞24次,收藏42次。Linux系统配置jdkLinux学习教程,Linux入门教程(超详细)_linux配置jdk
文章浏览阅读3.3k次,点赞5次,收藏19次。xlabel('\delta');ylabel('AUC');具体符号的对照表参照下图:_matlab微米怎么输入
文章浏览阅读119次。顺序读写指的是按照文件中数据的顺序进行读取或写入。对于文本文件,可以使用fgets、fputs、fscanf、fprintf等函数进行顺序读写。在C语言中,对文件的操作通常涉及文件的打开、读写以及关闭。文件的打开使用fopen函数,而关闭则使用fclose函数。在C语言中,可以使用fread和fwrite函数进行二进制读写。 Biaoge 于2024-03-09 23:51发布 阅读量:7 ️文章类型:【 C语言程序设计 】在C语言中,用于打开文件的函数是____,用于关闭文件的函数是____。
文章浏览阅读3.4k次,点赞2次,收藏13次。跟随鼠标移动的粒子以grid(SOP)为partical(SOP)的资源模板,调整后连接【Geo组合+point spirit(MAT)】,在连接【feedback组合】适当调整。影响粒子动态的节点【metaball(SOP)+force(SOP)】添加mouse in(CHOP)鼠标位置到metaball的坐标,实现鼠标影响。..._touchdesigner怎么让一个模型跟着鼠标移动
文章浏览阅读178次。项目运行环境配置:Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot + mybatis + Maven +mysql5.7或8.0+html+css+js等等组成,B/S模式 + Maven管理等等。环境需要1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。_基于java技术的停车场管理系统实现与设计
文章浏览阅读3.5k次。前言对于MediaPlayer播放器的源码分析内容相对来说比较多,会从Java-&amp;gt;Jni-&amp;gt;C/C++慢慢分析,后面会慢慢更新。另外,博客只作为自己学习记录的一种方式,对于其他的不过多的评论。MediaPlayerDemopublic class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal..._android多媒体播放源码分析 时序图
文章浏览阅读2.4k次,点赞41次,收藏13次。java 数据结构与算法 ——快速排序法_快速排序法