首页
工具
心境语句
相册
建站轨迹
关于
Search
1
微信小程序:计算属性的两种体现方式及应用场景
1,689 阅读
2
Antd Upload 组件上传文件接收数据流并下载
1,231 阅读
3
unlock-music工具介绍
809 阅读
4
[C#]使用dnSpy对目标程序(EXE或DLL)进行反编译修改并编译运行
718 阅读
5
C#插件火车头采集器动态切换代理IP,及自动切换UserAgent
673 阅读
react
typecho
ASP
Centos
MYSQL
PHP
Sql server
Javascript
nodejs
数据采集
.NET
git
编程算法
管理及流程
Vue
微信小程序
android
python
mongodb
登录
Search
标签搜索
kotlin
node-sass
nuxtjs
C#火车头插件
火车头采集器
火车头代理
C#反编译
程序逆向
dnSpy教程
Antd
InputNumber
NPM教程
NPM命令
rrweb教程
git慢
git镜像
vim命令
git命令
网页音乐插件
网页播放器
Elysian
累计撰写
77
篇文章
累计收到
0
条评论
首页
栏目
react
typecho
ASP
Centos
MYSQL
PHP
Sql server
Javascript
nodejs
数据采集
.NET
git
编程算法
管理及流程
Vue
微信小程序
android
python
mongodb
页面
工具
心境语句
相册
建站轨迹
关于
搜索到
77
篇与
Elysian
的结果
2022-01-07
Nuxtjs,SSR解决服务端用户登录鉴权
Nuxt.js是基于在Vue.js的服务端渲染框架,能完美的解决SEO的问题,但同时权限认证成为了一大痛点,需要解决用户登录后,保存token,来验证后续的权限的问题。该处主要使用如下解决方法使用 nuxt/axios/proxy 代理,使前端和后端的接口的域名统一,因为需要使前后端的cookie共用。在登录的时候将登录信息的token和用户信息写入 cookie ,然后通过cookie传递给nuxtjs的服务端。服务端在 store/index.js 中,构建actions的nuxtServerInit,然后通过context参数中的request的headers拿到cookie中的登录信息。这样就可以实现nuxt的服务端用户信息。具体的部分核心代码提供如下,可以做下参考:store/index.jsconst store = new Vuex.Store({ modules, actions: { nuxtServerInit({ commit }, { req }) { let cookie = req.headers.cookie || ""; if (cookie.indexOf("token") > -1) { let token = ""; try { token = cookie.split(';').map(a => { var arr = a.split('='); return { key: arr[0], value: arr[1] }; }).filter(a => a.key === 'token')[0].value; } catch (e) { } if (token) { ajax.defaults.headers["token"] = token; } } } } }) export default () => store登录逻辑async loginIn() { if (!this.phone) { Toast("请输入验证码"); return; } const data = await this.$api.requestLoginInApi(this.phone, this.code); if (data.status === 0) { Toast(data.msg); return; } ajax.defaults.headers["token"] = data.token; window.localStorage.setItem("token", data.token); window.localStorage.setItem("userinfo", JSON.stringify(data.user)); document.cookie = "token=" + data.token; Toast("登陆成功"); this.onClose(); }以上代码中的ajax使用的是axios
2022年01月07日
554 阅读
0 评论
0 点赞
2021-12-28
vue继承vant实现支持下拉刷新上拉加载更多的瀑布流组件
组件背景需要实现瀑布流效果、使用的前端框架是基于vant的。瀑布流内容多种形式,除了图文还有标签形式。项目需要SSR。片寻网络,找到一个不错的瀑布流组件,基于它修改了部分内容(优化了数据获取方式,传递列表支持ssr,传递promise参数支持下拉刷新和上拉加载更多,修改内容部分,使用slot支持组件外部自定义内容格式)实现效果组件源码:<template> <div class="flow-box"> <div class="type-box" v-if="typeList && typeList.length"> <ul class="type-list"> <li @click="changeType(index)" v-for="(item, index) in typeList" :class="['type-item', typeIndex == index ? 'type-item-on' : '']" :key="index" > <div class="text">{{ item.name }}</div> <div class="line"></div> </li> </ul> </div> <van-pull-refresh v-model="isLoading" @refresh="onRefresh" style="min-height: 100vh" :success-duration="800" success-text="加载成功" loading-text="加载中..." > <van-list v-if="haveData == 2" v-model="loading" :finished="finished" finished-text="没有更多了" @load="onBottomLoad" :offset="150" :immediate-check="false" > <div class="data-list-box" id="data-list-box"> <div class="data-item" v-for="(item, index) in dataList" :style="{ width: boxWidth + 'px' }" :key="index" > <slot :item="item" :index="index"></slot> </div> </div> </van-list> </van-pull-refresh> </div> </template> <script> export default { props: ["dataSource", "promisefunc"], data() { return { typeList: [ //分类列表 // { name: "全部" }, // { name: "手机数码" }, // { name: "家用电器" }, // { name: "酒水饮料" }, // { name: "钟表珠宝" }, // { name: "美妆护肤" }, // { name: "运动户外" }, // { name: "汽车生活" }, ], typeIndex: 0, //分类索引 dataList: this.dataSource || [], //列表数据 haveData: 0, //是否有数据,1=无,2=有,0=页面还未初始化 pageIndex: 1, //页码 pageSize: 8, //每页加载数据数量 isLoading: false, //下拉刷新进行中,请求开始true, 请求完成false,用于下拉刷新组件van-pull-refresh loading: false, //上拉加载更多中,上拉触底时自动变成true, 请求完成设置为false, 用于列表组件van-list finished: false, //上拉加载是否加载完最后一页数,用于组件van-list itemCount: 0, //上一次加载完成后的瀑布流item个数 lastRowHeights: [0, 0], //最后一行标签的顶部间距+高度,2列 boxMargin: 15, //每个item之间的边距 boxWidth: 165, //每个item宽度 }; }, created() { if (process.server) { return; } this.$toast.loading({ message: "加载中...", duration: 0, }); //当前瀑布流设置为两列,计算瀑布流每个item和图片的宽度 //console.log("load", window.innerWidth); let screenWidth = window.innerWidth || 375; //屏幕宽度 this.boxWidth = (screenWidth - this.boxMargin * 3) / 2; //每个item的宽度 if (this.dataSource == null || !this.dataSource.length) { this.onRefresh(); //刷新数据 } else { this.pageIndex = 1; //重置第一页 this.finished = false; //上拉加载"所有数据已经完成"标识 重置为false this.dataList = []; this.loadImagesHeight(this.dataSource); } }, methods: { changeType(index) { //切换类型 if (this.typeIndex == index) return; this.$toast.loading({ message: "加载中...", duration: 0, }); this.typeIndex = index; this.onRefresh(); }, onRefresh() { //下拉刷新 // if (this.isLoading) return; //还在请求中,返回 this.pageIndex = 1; //重置第一页 this.finished = false; //上拉加载"所有数据已经完成"标识 重置为false //接口请求 this.getDataList(); }, onBottomLoad() { //上拉加载更多 if (this.finished) return; //说明所有数据已经加载完毕,返回 this.getDataList(); //下一页数据请求中 }, //数据请求 getDataList() { this.promisefunc({ page: this.pageIndex }) .then((res) => { let list = res ? res : []; if (list.length > 0) { //从list中取pageSize条数据出来 var tempList = []; for (let i = 0; i < this.pageSize; i++) { if (list.length > 0) { let tempIndex = parseInt(Math.random() * 1000) % list.length; tempList.push(list[tempIndex]); list.splice(tempIndex, 1); } } this.loadImagesHeight(tempList); //模拟预加载图片,获取图片高度 } else { this.loadImagesHeight(list); //处理数据 } }) .catch((res) => { //console.log("..fail: ", res); this.$toast.clear(); this.isLoading = false; //下拉刷新请求完成 this.loading = false; //上拉加载更多请求完成 }); }, loadImagesHeight(list) { var count = 0; //用来计数,表示是否所有图片高度已经获取 list.forEach((item, index) => { //创建图片对象,加载图片,计算图片高度 var img = new Image(); img.src = item.cover; img.onload = img.onerror = (e) => { count++; if (e.type == "load") { //图片加载成功 //计算图片缩放后的高度:图片原高度/原宽度 = 缩放后高度/缩放后宽度 list[index].imgHeight = Math.round( (img.height * this.boxWidth) / img.width ); // console.log('index: ', index, ', load suc, imgHeiht: ', list[index].imgHeight); } else { //图片加载失败,给一个默认高度50 list[index].imgHeight = 50; //console.log("index: ", index, ", 加载报错:", e); } //加载完成最后一个图片高度,开始下一步数据处理 if (count == list.length) { this.resolveDataList(list); } }; }); }, resolveDataList(list) { //处理数据 //下拉刷新,清空原数据 if (this.pageIndex <= 1) { this.itemCount = 0; this.dataList = []; this.lastRowHeights = [0, 0]; //存储每列的最后一行高度清0 } if (list.length >= this.pageSize) { this.pageIndex++; //还有下一页 } else { this.finished = true; //当前tab类型下所有数据已经加载完成 } //合并新老两个数组数据 this.dataList = [...this.dataList, ...list]; //判断页面是否有数据 this.haveData = this.dataList.length > 0 ? 2 : 1; // this.isLoading = false; //下拉刷新请求完成 // this.loading = false; //上拉加载更多请求完成 //console.log("...datalist: ", this.dataList); //console.log("...this.isLoading: ", this.isLoading); this.$nextTick(() => { setTimeout(() => { //渲染完成,计算每个item宽高,设置标签坐标定位 this.setItemElementPosition(); this.isLoading = false; //下拉刷新请求完成 this.loading = false; //上拉加载更多请求完成 }, 100); }); }, //获取每个item标签高度,设置item的定位 setItemElementPosition() { if (process.server) { return; } let parentEle = document.getElementById("data-list-box"); let boxEles = parentEle.getElementsByClassName("data-item"); for (let i = this.itemCount; i < boxEles.length; i++) { let tempEle = boxEles[i]; //上一个标签最小高度的列索引 let curColIndex = this.getMinHeightIndex(this.lastRowHeights); let boxTop = this.lastRowHeights[curColIndex] + this.boxMargin; let boxLeft = curColIndex * (this.boxWidth + this.boxMargin) + this.boxMargin; tempEle.style.left = boxLeft + "px"; tempEle.style.top = boxTop + "px"; this.lastRowHeights[curColIndex] = boxTop + tempEle.offsetHeight; // console.log('i = ', i, ', boxTop: ', boxTop, ', eleHeight: ', tempEle.offsetHeight); } this.itemCount = boxEles.length; //修改父级标签的高度 let maxHeight = Math.max.apply(null, this.lastRowHeights); parentEle.style.height = maxHeight + "px"; this.$toast.clear(); //console.log("...boxEles: ", boxEles.length, ", maxH: ", maxHeight); }, //获取数组中最小值的索引 getMinHeightIndex(arr) { var minHeight = Math.min.apply(null, arr); for (let i = 0; i < arr.length; i++) { if (arr[i] == minHeight) { return i; } } }, }, }; </script> <style lang="scss" scoped> .flow-box { background-color: #ffffff; width: 100vw; height: 100vh; } .flow-box .type-box { width: 100%; height: 40px; position: fixed; top: 0; font-size: 14px; background: #fff; color: rgba(0, 0, 0, 0.4); z-index: 99; border-bottom: 0.5px solid #dddddd; padding: 0 5px; } .type-box .type-list { white-space: nowrap; overflow-x: scroll; } .type-list .type-item { display: inline-block; padding: 0 12.5px; height: 40px; text-align: center; } .type-list .type-item .text { line-height: 37.5px; font-size: 14px; color: rgba(0, 0, 0, 0.4); margin: 0; } .type-list .type-item .line { background-color: #ffffff; } .type-list .type-item-on .text { font-size: 16px; color: #f0142d; } .type-list .type-item-on .line { width: 19px; height: 2px; margin: 0 auto; background-color: #f0142d; border-radius: 2px; } /* 隐藏滚动条 */ .type-list::webkit-scrollbar { display: none; } /* 列表数据样式 */ @keyframes data-item-ani { 0% { transform: scale(0.5); } 100% { transform: scale(1); } } .flow-box .data-list-box { position: relative; height: 100vh; /* margin-top: 40px; */ } .data-list-box .data-item { height: auto; position: absolute; background-color: #ffffff; /* box-shadow: 0px 0px 5px 2px rgba(0, 0, 0, 0.5); */ left: -1000px; animation: data-item-ani 0.4s; transition: left 0.6s, top 0.6s; transition-delay: 0.1s; } </style>使用方法<template> <Waterfall :dataSource="anlilist" :promisefunc="this.requestFunc || this.$api.requestZhuangxiuCase" > <template slot-scope="child"> <div class="hot-list" v-if="child.index === 5 && hotlist && hotlist.length" > <lookall :list="hotlist" /> </div> <div class="item-box"> <a href="/shop/" class="a"> <img :src="child.item.cover" class="data-cover" :alt="child.item.title" :style="{ width: '100%', height: child.item.imgHeight + 'px' }" /> <p class="p">{{ child.item.sign }}</p> <h3 class="h3">{{ child.item.title }}</h3> <i class="icon icon-an"></i> </a> <div class="news-list-info cf"> <a href="/shop/" class="source" ><img :src="child.item.iconimg" alt="" />{{ child.item.icontitle }}</a ><a href="" class="btn-zan">{{ child.item.count }}赞</a> </div> </div> </template> </Waterfall> </template> <script> import lookall from "~/components/jiajuhao/lookall.vue"; export default { components: { lookall, }, props: ["dataSource", "requestFunc", "hotlist"], data() { return { anlilist: this.dataSource || [], }; }, }; </script> <style lang="scss"> /* 全局样式 */ .hot-list { border-radius: 0.1rem; border: 1px solid #e5e5e5; overflow: hidden; background: #fff; padding: 0.35rem 0.2rem; margin-bottom: 0.25rem; .news-block { padding: 0; border: 0; h2 { border: 0; margin: 0; } ul { li { width: 100%; } } } } </style> <style lang="scss" scoped> .item-box { border-radius: 0.1rem; border: 1px solid #e5e5e5; overflow: hidden; background: #fff; .a { position: relative; display: block; height: auto; padding-bottom: 0.2rem; } .data-cover { margin-bottom: 0.1rem; display: block; } .p { padding: 0.05rem 0.2rem 0.1rem; font-size: 0.2rem; color: #999; } .h3 { padding: 0 0 0 0.2rem; font-size: 0.26rem; } .icon-an { width: 0.59rem; height: 0.33rem; background-position: 0 -2.5rem; position: absolute; top: 0; left: 0; } .data-name { font-size: 14px; padding: 5px 10px; text-align: left; } .news-list-info { margin: 0 0.1rem 0.1rem; } } </style>组件原地址转至:https://www.cnblogs.com/tandaxia/p/12189301.html
2021年12月28日
407 阅读
0 评论
0 点赞
2021-12-24
Nuxtjs优化建议
样式提取(将样式输出到一个样式文件中,ssr不显示在页面中)//nuxt.config.js配置文件修改配置 //官网介绍地址:https://www.nuxtjs.cn/api/configuration-build (搜索extractCSS) build: { extractCSS: true, },去掉多余的window.__NUXT__内容hooks: { 'vue-renderer:ssr:context'(context) { if (context?.nuxt?.error?.statusCode === 200) { const routePath = JSON.stringify(context.nuxt.routePath); context.nuxt = { serverRendered: true, routePath }; } } },该方法存在副作用,因为去掉了__NUXT__里面的内容,原本服务端传递给客户端的状态和数据都存在该位置,清除后页面再加载后客户端会再次请求asyncData里的请求,可能还会存在一些状态的问题,建议时候后多测试调优。
2021年12月24日
414 阅读
0 评论
0 点赞
2021-12-20
自动创建sftp站点账号shell
#!/bin/bash #站点目录,用户名根据站点目录生成,多个站点用空格隔开 #例web="test1 test2",生成的用户为sftp_test1 sftp_test2 web="chinaoa sgj" user_dir="/home/public_html/" ssh_dir="/etc/ssh/sshd_config" #配置权限,属主必须为root,权限必须为755,facl也不行 chown root.root ${user_dir} chmod 755 ${user_dir} #设置sebool值 if [[ `getenforce` == "Enforcing" ]];then setsebool ssh_chroot_full_access 1 fi #配置ssh,开启internal-sftp if [[ `grep -w internal-sftp ${ssh_dir} | wc -l` -eq 0 ]];then sed -i "s/Subsystem/#Subsystem/g" ${ssh_dir} echo "Subsystem sftp internal-sftp" >>${ssh_dir} fi for user in ${web};do if [[ `grep -w "Match user sftp_${user}" ${ssh_dir} | wc -l` -eq 0 ]];then #!/bin/bash #站点目录,用户名根据站点目录生成,多个站点用空格隔开 #例web="test1 test2",生成的用户为sftp_test1 sftp_test2 web="chinaoa sgj" user_dir="/home/public_html/" ssh_dir="/etc/ssh/sshd_config" #配置权限,属主必须为root,权限必须为755,facl也不行 chown root.root ${user_dir} chmod 755 ${user_dir} #设置sebool值 if [[ `getenforce` == "Enforcing" ]];then setsebool ssh_chroot_full_access 1 fi #配置ssh,开启internal-sftp if [[ `grep -w internal-sftp ${ssh_dir} | wc -l` -eq 0 ]];then sed -i "s/Subsystem/#Subsystem/g" ${ssh_dir} echo "Subsystem sftp internal-sftp" >>${ssh_dir} fi for user in ${web};do if [[ `grep -w "Match user sftp_${user}" ${ssh_dir} | wc -l` -eq 0 ]];then Match user sftp_${user} ChrootDirectory ${user_dir} X11Forwarding no AllowTcpForwarding no ForceCommand internal-sftp ### END ### EOF fi #添加用户 if [[ `grep -w "sftp_${user}" /etc/passwd | wc -l` -eq 0 ]];then useradd -M -s /bin/false sftp_${user} read -s -t 30 -p "请在30S内输入站点${i}用户密码: " password echo "${password}" |passwd --stdin sftp_${user} echo "用户生成完毕,用户名为: sftp_${user}" else echo "用户sftp_${user}已存在,请检查" fi #赋权对应目录给用户 setfacl -R -d -m u:sftp_${user}:rwx ${user_dir}${user} setfacl -R -m u:sftp_${user}:rwx ${user_dir}${user} #去掉不该有的目录权限,增加安全 cd ${user_dir} setfacl -R -d -m u:sftp_${user}:--- `ls ${user_dir} | grep -v "${user}"` setfacl -R -m u:sftp_${user}:--- `ls ${user_dir} | grep -v "${user}"` done #重启ssh服务 service sshd restart #人性化输出 echo "请使用sftp进行连接,端口号:`netstat -anltp | grep LISTEN | grep sshd | grep "0.0.0.0" | awk '{print $4}' | awk -F: '{print $2}'`"
2021年12月20日
195 阅读
0 评论
0 点赞
2021-12-20
CentOS文件权限查看和修改
文件权限查看查看目录的文件,输入命令:ls查看 token.txt 文件的权限,输入命令:ls -l token.txt那么就会出现相类似的信息-rw-r--r-- 1 root root 48 Jan 8 20:14 token.txt最开始的10位数 -rw-rw-r-- 最前面那个 - 代表的是类型第一个 rw- 代表的是所有者(user)第二个 rw- 代表的是组群(group)第三个 r-- 代表的是其他人(other) 其中: r 表示文件可以被读(read) w 表示文件可以被写(write) x 表示文件可以被执行(如果它是程序的话) - 表示相应的权限还没有被授予通过上面的解释,就可以看出 token.txt 文件的权限是:当前用户本身:可读可写,没有可执行权限当前用户组群:可读不可写,没有可执行权限其他用户:可读不可写,没有可执行权限rwx 也可以用数字来代替r ------------4 w ------------2 x ------------1 - ------------0所以我们总结出权限对应的数字-rw------- (600) 只有所有者才有读和写的权限 -rw-r--r-- (644) 只有所有者才有读和写的权限,组群和其他人只有读的权限 -rwx------ (700) 只有所有者才有读,写,执行的权限 -rwxr-xr-x (755) 只有所有者才有读,写,执行的权限,组群和其他人只有读和执行的权限 -rwx--x--x (711) 只有所有者才有读,写,执行的权限,组群和其他人只有执行的权限 -rw-rw-rw- (666) 每个人都有读写的权限 -rwxrwxrwx (777) 每个人都有读写和执行的权限修改文件权限现在我们把 token.txt 文件修改为 所有用户可读可写可执行 , 也就是对应编号为 777chmod 777 token.txt效果如下:转至:http://blog.csdn.net/zhaoyanjun6/article/details/79067442
2021年12月20日
288 阅读
0 评论
0 点赞
1
...
6
7
8
...
16