在线地址:https://www.bookstack.cn/read/element2.9.1/809e8cbaaa611318.md
链接: https://pan.baidu.com/s/1nZLjmG_qoQ3y_n4BbGTFfA 提取码: jhq8 复制这段内容后打开百度网盘手机App,操作更方便哦
在线地址:https://www.bookstack.cn/read/element2.9.1/809e8cbaaa611318.md
链接: https://pan.baidu.com/s/1nZLjmG_qoQ3y_n4BbGTFfA 提取码: jhq8 复制这段内容后打开百度网盘手机App,操作更方便哦
js html5九宫格拼图小游戏

链接: https://pan.baidu.com/s/1ZLM0ZXOFnW7SDjgRmyWLHg 提取码: 4yf1 复制这段内容后打开百度网盘手机App,操作更方便哦

效果1:根节点1和2里面的子节点全勾选返回的是[1,10,11,12,2,20,21]
效果2:当我们重新编辑时如果只选中了[2,21],那么返回的效果是只有根节点2和它自己的子节点21被选中,如上图
效果3:当勾选任意一个子节点时,它的根节点也被勾选
效果4:如果子节点都没被勾选,根节点也自动取消选中
效果5,当点击根节点时,它的所有子节点都自动全选,反选。
<el-tree ref="tree" :data="treeMenus" :props="multiProps" :show-checkbox="true" node-key="id" highlight-current :expand-on-click-node="true" :default-checked-keys="checkedId" :check-strictly="true" @check="clickDeal"> </el-tree>
//注意根节点的id值要跟子节点里面的parentId值一致,且跟节点的parentId都是-1
return {
checkedId: [],
treeMenus: [{
id: 1,
parentId: -1,
label: '一级 1',
children: [{
id: 4,
parentId: 1,
label: '二级 1-1',
children: [{
id: 9,
parentId: 4,
label: '三级 1-1-1',
children: [{
id: 1000,
parentId: 9,
label: '三级 1000-1-1',
children: []
}, {
id: 1001,
parentId: 9,
label: '三级 1001-1-1',
children: [{
id: 2000,
parentId: 1001,
label: '三级 2000-1-1',
children: []
},{
id: 2001,
parentId: 1001,
label: '三级 2001-1-1',
children: []
}]
}]
}, {
id: 10,
parentId: 4,
label: '三级 1-1-2',
children: []
}]
}, {
id: 20,
parentId: 1,
label: '123',
children: []
}, {
id: 25,
parentId: 1,
label: '12456',
children: []
}]
}, {
parentId: -1,
id: 2,
label: '一级 2',
children: [{
parentId: 2,
id: 5,
label: '二级 2-1',
children: []
}, {
parentId: 2,
id: 6,
label: '二级 2-2',
children: []
}]
}, {
parentId: -1,
id: 3,
label: '一级 3',
children: [{
parentId: 3,
id: 7,
label: '二级 3-1',
children: []
}, {
parentId: 3,
id: 8,
label: '二级 3-2',
children: []
}]
}],
multiProps: {
children: 'children',
label: 'label'
}
}
methods: {
clickDeal(currentObj, treeStatus){
this.clickCheck(currentObj, treeStatus,this.$refs.tree)
},
/**
* 树形菜单复选框父子节点不关联实现父子节点联动回显
*
* @see selectedParent - 处理父节点为选中
* @see uniteChildSame - 处理子节点为相同的勾选状态
* @see removeParent - 子节点全没选中取消父级的选中状态
*
* @param {Object} currentObj - 当前勾选节点的对象
* @param {Object} treeStatus - 树目前的选中状态对象
* @param {Object} ref - this.$refs.xxx
**/
clickCheck(currentObj, treeStatus, ref) {
// 用于:父子节点严格互不关联时,父节点勾选变化时通知子节点同步变化,实现单向关联。
let selected = treeStatus.checkedKeys.indexOf(currentObj.id); // -1未选中
// 选中
if (selected !== -1) {
// 子节点只要被选中父节点就被选中
this.selectedParent(currentObj, ref);
// 统一处理子节点为相同的勾选状态
this.uniteChildSame(currentObj, true, ref);
} else {
// 取消子节点的选中状态触发
if (currentObj.parentId !== -1) {
this.removeParent(currentObj, ref);
}
// 未选中 处理子节点全部未选中
if (currentObj.children.length !== 0) {
this.uniteChildSame(currentObj, false, ref);
}
}
},
/** 统一处理子节点为相同的勾选状态 **/
uniteChildSame(treeList, isSelected, ref) {
let treeListData = treeList.children;
let len = treeListData.length;
ref.setChecked(treeList.id, isSelected);
for (let i = 0; i < len; i++) {
this.uniteChildSame(treeListData[i], isSelected, ref);
}
},
/** 统一处理父节点为选中 **/
selectedParent(currentObj, ref) {
let currentNode = ref.getNode(currentObj);
if (currentNode.parent.key !== undefined) {
ref.setChecked(currentNode.parent, true);
return this.selectedParent(currentNode.parent, ref);
}
},
/** 子节点全没选中取消父级的选中状态 **/
removeParent(currentObj, ref) {
let a = 0;
let b = 0;
let currentNode = ref.getNode(currentObj);
if (currentNode.parent !== null) {
if (currentNode.parent.key !== undefined) {
ref.setChecked(currentNode.parent, true); //根节点
this.removeParent(currentNode.parent, ref); //递归判断子节点
}
}
//不为0表示为父节点
if (currentNode.childNodes.length !== 0) {
//循环判断父节点下的子节点
for (let i = 0; i < currentNode.childNodes.length; i++) {
//判断父节点下的子节点是否全为false
if (currentNode.childNodes[i].checked === false) {
++a;
//a === currentNode.childNodes.length 表明子节点全为false
if (a === currentNode.childNodes.length) {
//等于 undefined 跳过,不等于继续执行
if (currentNode.childNodes[i].parent.key !== undefined) {
ref.setChecked(currentNode.childNodes[i].parent, false); //父元素设置为false
//循环上级父节点下的子节点
for (let i = 0; i < currentNode.parent.childNodes.length; i++) {
//判断父节点下的子节点是否全为false
if (currentNode.parent.childNodes[i].checked === false) {
++b;
//b === currentNode.parent.childNodes.length 表明子节点全为false
if (b === currentNode.parent.childNodes.length) {
ref.setChecked(currentNode.parent.key, false); //父元素设置为false
return this.removeParent(currentNode.parent, ref); //继续递归循环判断
}
}
}
}
}
}
}
}
},
}
获取最终勾选的数组
获取最终选中id值this.$refs.tree.getCheckedKeys().concat(this.$refs.tree.getHalfCheckedKeys())返回数组
//小细节的问题,如果el-tree是放在el-dialog弹窗里面,那就必须点击弹窗的时候也即使dom加载后才执行以下代码
this.$nextTick(function() {
this.$refs.tree.setCheckedKeys(self.menus); //将已经选中的节点,打上沟
})
jquery 解析 blob 二进制流 导出 下载 excel 接口
下载:jquery-ajax-blob-arraybuffer
情景:当我们请求接口返回来的是一堆二进制流乱码,例如:(相当于我们用记事本方式去打开文件一样,其实文件是有的)

像这样的调用接口下载文件,请求方式必须是get。
如何下载:
1,get请求不到任何token
<a href="http://localhost:3000/upload/api" download="xxx">下载11</a> //href换成自己接口,下载后是xxx.gif
2,post请求不带token
exportExcel() { //导出
this.exportDisabled = true;
var url = basePath + '/act/excel/data/ranking';
var exportForm = $("<form action=" + url + " method='post'></form>")
exportForm.append("<input type='hidden' name='roomNumber' value='" + this.queryData.roomNumber + "'/>")
exportForm.append("<input type='hidden' name='type' value='" + this.queryData.type + "'/>")
$(document.body).append(exportForm);
exportForm.submit();
exportForm.remove();
this.exportDisabled = false;
},
3,通过base64下载 带token
如果要带token验证才能下载就使用以下方法:(思路:二进制流 转 blob 转 base64 )
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/1.8.3/jquery.js"></script>
<script src="https://greasyfork.org/scripts/20389-jquery-ajax-blob-arraybuffer/code/jquery-ajax-blob-arraybuffer.js"></script>
$.ajax({
type:'get',
url:`${process.env.VUE_APP_BASE_API}/wucg/cms/downloadStudent`,
headers:{
"userToken":store.getters.token,
"Content-Type":"application/json"
},
dataType: "blob", //jquery 没有解析blob类型要进入 jquery-ajax-blob-arraybuffer.js
success(data){
var blob = data;
var reader = new FileReader();
reader.readAsDataURL(blob); // 转换为base64,可以直接放入a表情href
reader.onload = function (e) {
// 转换完成,创建一个a标签用于下载
var a = document.createElement('a');
a.href = e.target.result;
self.$nextTick(function() {
$('#dowBtn').html( $(a).text('导出') )
})
}
},
})
或者 通过blob下载 带token
//下载
downloadFile(fileName,blob) {
let aLink = document.createElement('a');
var blob = blob; //new Blob([content]);
let evt = document.createEvent("HTMLEvents");
evt.initEvent("click", true, true);//initEvent 不加后两个参数在FF下会报错 事件类型,是否冒泡,是否阻止浏览器的默认行为
aLink.download = fileName;
aLink.href = URL.createObjectURL(blob);
// aLink.dispatchEvent(evt);
//aLink.click()
aLink.dispatchEvent(new MouseEvent('click', {bubbles: true, cancelable: true, view: window}));//兼容火狐
},
//获取导出战队blob
exportTeam(){
var self =this
console.log(self.seachData)
// return
this.$axios({
method: 'post',
url: `${process.env.VUE_APP_BASE_API}/wucg/cms/downloadTeamList`,
headers: {
'Content-Type': 'application/json',
"userToken":store.getters.token
},
data: {
matchId:self.seachData.matchId,
division:self.seachData.division,
cityCodes:self.seachData.cityCodes,
schoolCodes:self.seachData.schoolCodes,
teamName:self.seachData.teamName,
gameId:self.seachData.gameId,
teamStatus:self.seachData.teamStatus
},
responseType: 'blob'
}).then((res)=>{
var blob = res.data;
var filName = decodeURIComponent(res.headers['content-disposition'].split(';')[1].split('\'\'')[1])
self.downloadFile(filName || '战队列表.xls',blob) //直接通过blob数据下载
})
},
//base64转blob
base64ToBlob(code) {
let parts = code.split(';base64,');
let contentType = parts[0].split(':')[1];
let raw = window.atob(parts[1]);
let rawLength = raw.length;
let uInt8Array = new Uint8Array(rawLength);
for (let i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i);
}
return new Blob([uInt8Array], {type: contentType});
},
参考:https://www.jb51.net/article/88972.htm
———————–以下是原生写法———————————–
后台直接提供下载接口,直接用a标签请求接口即可。但是考虑安全,在用get请求下载的同时要带上token验证。
代码经过实践可行:
var xhh = new XMLHttpRequest();
xhh.open("get", `${process.env.VUE_APP_BASE_API}/wucg/cms/downloadStudent` ); //请求地址
xhh.setRequestHeader("Authorization", "Bearer "+token); //token设置
xhh.setRequestHeader("Content-Type","application/json");
xhh.responseType = 'blob';
// xhh.onreadystatechange = function () {
// if (xhh.readyState === 4 && xhh.status === 200) {
// var mimeType = xhh.getResponseHeader("ajax-mimeType");
// var blob = new Blob([xhh.response], {type: mimeType});
// var csvUrl = URL.createObjectURL(blob);
// var link = document.createElement('a');
// document.body.appendChild(link); //创建的标签添加到body,解决Firefox下无法打开页面的问题
// link.href = csvUrl;
// link.target = '_blank';
// link.id = 'linkId',
// link.className = 'linkId',
// link.download = fileName;
// document.getElementById("linkId").click();
// // link.remove(); //将a标签移除
// $('.linkId').remove()
// }
// };
xhh.onload = function () {
// 请求完成
if (this.status === 200) {
// 返回200
var blob = this.response;
var reader = new FileReader();
reader.readAsDataURL(blob); // 转换为base64,可以直接放入a表情href
reader.onload = function (e) {
// 转换完成,创建一个a标签用于下载
var a = document.createElement('a');
a.href = e.target.result;
self.$nextTick(function() {
$('#dowBtn').html( $(a).text('导出') )
})
}
}
};
xhh.send();
要想实现,点击链接有另存为效果参看:https://sdeno.com/?p=7553
npm install xxx --save
–save:将保存配置信息到pacjage.json的dependencies节点中 ,上生产依然使用该模块
–save-dev:将保存配置信息到pacjage.json的devDependencies节点中,仅仅在开发调试时使用,上生产不需要。