WEB
vue
组件
全局组件
在main.js中注册
//引入组件
import TypeNav from '@/components/TypeNav'
// 第一个参数:全局组件的名字 第二个参数:哪一个组件
Vue.component(TypeNav.name,TypeNav)
使用:无需引入,直接使用标签
<TypeNav />
节流和防抖
lodash
节流:
在规定的间隔时间范围内不会重复出发回调,只有大于这个时间间隔才会出发回调,把频繁出发变为少量触发。
//lodash
import throttle from "lodash/throttle";
testfuntion: throttle(funtion(){
console.log('每秒只执行一次')
},1000)
//使用定时器写法
function throttle(fn, delay) {
let flag = true
return function () {
if (flag) {
setTimeout(() => {
fn.call(this)
flag = true
}, delay)
}
flag = false
}
}
vue中使用
封装方法
// utils/index.js文件内
/**
* 节流
* @param {Function} fn
* @param {Number} delay
* @returns
*/
export function throttle(fn, delay) {
//距离上一次的执行时间
let lastTime = 0;
return function () {
let _this = this;
let _arguments = arguments;
let now = new Date();
//如果距离上一次执行超过了delay才能再次执行
if (now - lastTime > delay) {
fn.apply(_this, _arguments);
lastTime = now;
}
};
}
引入使用
import { throttle } from "@/utils/index";
//submit需要节流的函数事件
submit:throttle(function(){
console.log('delay后才能触发下一次')
},delay)
防抖:
前面的所有出发都被取消,最后一次执行在规定的时间之后才会触发,也就是说如果连续快速的触发,只会执行一次。
//使用定时器写法
function debounce(fn, delay) {
let t = null
return function () {
if (t !== null) {
clearTimeout(t)
}
t = setTimeout(() => {
fn.call(this); //改变this指向
}, delay)
}
}
//vue中使用时
// 鼠标滚动事件
handleScroll(e) {
let direction = e.deltaY > 0 ? "down" : "up";
if (direction == "down") {
// 下一页
this.debounce(this.getNext, 200);
} else {
// 上一页
this.debounce(this.getPrev, 200);
}
},
// 防抖
debounce(func, wait) {
let context = this; //this指向变化,在return之前获得实例
let args = arguments;
return function () {
if (context.timer) clearTimeout(context.timer);
context.timer = setTimeout(() => {
func.apply(context, args);
}, wait);
}(); //添加括号手动执行
},
事件委托
Event
$nextTick
解决需数据渲染完毕,再执行DOM操作
watch: {
// 监听bannerList数据变化
bannerList: {
// 执行handler方法,代表组件实例上属性的属性值已经有了
// 只能保证bannerList获取完毕,不能保证v-for渲染完毕
handler(newValue, oldValue) {
// 将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。
// 它跟全局方法 Vue.nextTick 一样,不同的是回调的 this 自动绑定到调用它的实例上
this.$nextTick(() => {
// 保证数据已经获取并且循环已经循环已经渲染完毕,
//再执行操作DOM
var mySwiper = new Swiper(
this.$refs.mySwiper,
{
loop: true, // 循环模式选项
// 如果需要分页器
pagination: {
el: ".swiper-pagination",
clickable: true,
},
// 如果需要前进后退按钮
navigation: {
nextEl: ".swiper-button-next",
prevEl: ".swiper-button-prev",
},
// 如果需要滚动条
scrollbar: {
el: ".swiper-scrollbar",
},
}
);
});
},
},
},
组件通信
props:
用于父子组件通信,父传子
自定义事件:
@on
@emit 可以实现子传父
父组件
<SearchSelector @trademarkInfo="trademarkInfo" />
trademarkInfo(trademark) {
this.searchParams.trademark = `${trademark.tmId}:${trademark.tmName}`;
this.getData();
},
子组件
tradeMatkHandler(trademark) {
this.$emit("trademarkInfo", trademark);
},
全局事件总线:
$bus 全能
main.js
new Vue({
router,
store,
render: h => h(App),
beforeCreate() {
Vue.prototype.$bus = this;
},
}).$mount('#app')
Header/index.js
mounted() {
// 全局事件总线清除关键字
this.$bus.$on("clear", () => {
this.keyword = "";
});
},
Search/index.js
// 面包屑删除(关键字)
removeKeyword() {
this.searchParams.keyword = undefined;
this.$bus.$emit("clear");
this.$router.push({ name: "search", query: this.$route.query });
},
插槽,vuex
Tips
请求
请求携带多个属性,且属性可有可无时,可赋值为undefined
发送请求时当属性值为undefined不会传给后台
数组去重
attrInfo(attrs, attrValue) {
let props = `${attrs.attrId}:${attrValue}:${attrs.attrName}`;
// 数组去重
if (this.searchParams.props.indexOf(props) == -1) {
this.searchParams.props.push(props);
this.getData();
}
},
Filter()检查数组
totalPrice() {
let sum = 0;
let list = this.cartInfoList;
// function checked(list) {
// return list.isChecked == 1;
// }
list
.filter((list) => {
//返回数组中满足条件的值
return list.isChecked == 1;
})
.forEach((item) => {
sum += item.skuNum * item.skuPrice;
});
return sum;
},
vue-router
路由
push和replace重写
call||apply区别
相同点:都可以调用函数一次,都可以篡改函数的上下文一次
不同点:call与apply传递参数:call传递参数用逗号隔开,apply方法执行,传递数组
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
// 重写push方法
// 保存push||replace原型
let originPush = VueRouter.prototype.push;
let originReplace = VueRouter.prototype.replace
// 第一个参数:告诉原来的push方法,往哪里跳转(传递哪些参数)
// 第二个参数:成功的回调
// 第三个参数:失败的回调
VueRouter.prototype.push = function(location,resolve,reject){
if(resolve && reject){
originPush.call(this,location,resolve,reject)
}else{
originPush.call(this,location,()=>{},()=>{})
}
}
VueRouter.prototype.replace = function(location,resolve,reject){
if(resolve && reject){
originReplace.call(this,location,resolve,reject)
}else{
originReplace.call(this,location,()=>{},()=>{})
}
}
滚动行为
const router = new VueRouter({
routes,
scrollBehavior(to, from, savedPosition) {
return { y: 0 }
},
})
Axios
API
二次封装request
自定义的 axios 实例添加拦截器。
import axios from 'axios';
// 1:利用axios对象的方法create,去创建一个axios实例
// 2:request 就是axios,只不过稍微配置了一下
const requests = axios.create({
// 配置对象
// 基础路径,发请求的时候,路径当中会出现api
baseURL:"/api",
// 代表请求超时的时间5s
timeout:5000,
})
// 请求拦截器:在发送请求之前,请求拦截器可以检测到,可以在请求发出去之前做一些事情
requests.interceptors.request.use((config)=>{
// config:配置对象,对象里面有一个属性很重要,header请求头
return config;
})
// 响应拦截器
requests.interceptors.response.use((res)=>{
// 成功的回调函数:服务器响应数据回来以后,响应拦截器可以检测到,可以做一些事情
return res.data;
},(error)=>{
// 响应失败的回调函数
return Promise.reject(new Error('faile'));
})
// 对外暴露
export default requests;
进度条
requests.interceptors.request.use((config)=>{
// nprogress开始
nprogress.start();
return config;
})
requests.interceptors.response.use((res)=>{
// 进度条结束
nprogress.done();
return res.data;
},(error)=>{
return Promise.reject(new Error('faile'));
})
跨域问题
proxy代理
src/vue.config.js文件
module.exports = {
devServer :{
proxy: {
"/api": {
target: "http://39.98.123.211",
// pathRewrite: {"^/api" : ""}
}
}
}
}
vuex
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
import home from './home'
import search from './search'
export default new Vuex.Store({
// state:仓库存储数据的地方
state: {},
// mutations: 修改state的唯一手段
mutations: {},
// actions:处理action,可以书写自己的业务逻辑,也可以处理异步
actions: {},
// getters: 理解为计算属性,用于简化仓库数据,让组件获取仓库的数据更加方便
getters: {},
// 实现Vuex仓库模块式开发存储数据
modules: {
home,
search
}
})
Tips
1.****多个字符串检查
通常,你可能需要检查string是否等于多个值之一,并且可能会非常快地变得疲惫。幸运的是,JavaScript有一个内置的方法来帮助您解决这个问题。
const isVowel = (letter) => {
if(
letter==='a'||
letter==='e'||
letter==='i'||
letter==='o'||
letter==='u'||
){
return true
}
return false;
}
//short-hand
const isvowel = (letter) =>
['a','e','i','o','u'].includes(letter);
2.For-of和For-in****循环
For-of和For-in循环是在array或object上迭代的好方法,而无需手动跟踪objectkeys的索引。
For-of
const arr = [1,2,3,4,5]
//Long-hand
for(let i = 0; i < arr.length; i++){
const element = arr[i]
}
//short-hand
for(const element of arr){
//...
}
For-in
const obj = {
a:1,
b:2,
c:3,
};
//Long-hand
const keys = object.keys(obj);
for(let i = 0; i<keys.length; i++){
const key = keys[i];
const value = obj[key];
//...
}
//short-hand
for(const key in obj){
const value = obj[key];
//...
}
3.Falsey****检查
如果你想检查变量是null、undefined、0、false、NaN还是空string,你可以使用逻辑(!)操作员一次检查所有条件,而无需编写多个条件。这使得检查变量是否包含有效数据变得容易。
//Long-hand
const isFalsey = (value) =>{
if(
value ===null||
value ===undefind||
value === 0||
value ===false||
value ===NaN||
value ===""
){
return true;
}
return false;
};
//short-hand
const isFalsey = (value) => !value;
4.****三元运算符
作为JavaScript开发人员,你必须遇到过ternary operator。这是编写简洁的if-else语句的好方法。但是,你也可以使用它来编写简洁的代码,甚至将其链接起来以检查多个条件。
//Long-hand
let info;
if(value < minValue){
info = "value is too small";
}else if(value > maxValue){
info = "value is too large";
}else{
info = "value is in range";
}
//short-hand
const info =
value < minValue ? "value is too small" : value > maxValue ? "value is too large" : "value is in range";
5.****函数调用
在ternary operator的帮助下,你还可以根据条件确定调用哪个函数。
重要附带说:函数的callsignature必须相同,否则你可能会遇到错误。
function Fn1(){
//...
}
function Fn2(){
//...
}
//Long-hand
if(condition){
Fn1();
}else{
Fn2();
}
//short-hand
(condition ? Fn1 : Fn2)();
6.****切换速记
长switch cases情况通常可以通过使用以键为switch,将值用作返回值的对象来优化。
cont dayNumber = new Date().getDay();
//Long-hand
let day
switch(dayNumber){
case 0:
day = "Sunday";
break;
case 1:
day = "Monday";
break;
case 2:
day = "Tuesday";
break;
case 3:
day = "Wednesday";
break;
case 4:
day = "Thursday";
break;
......
}
//short-hand
const days = {
0:'Sunday',
1:'Monday',
2:'Tuesday',
3:'Wednesday',
4:'Thursday',
5:'Friday',
6:'Saturday',
};
const day = day[dayNumber];
7.****回退值
||运算符可以为变量设置回退值。
//Long-hand
let name;
if(user?.name){
name = user.name;
}else{
name = "Anonymous";
}
//short-hand
const name = useer?.name || "Anonymous";
vue打印
1.引入打印main.js
"print-js": "^1.6.0",
// 引入打印
import print from 'print-js'
import 'print-js/dist/print.css';
//挂载
Vue.prototype.$print = print;
2.使用
this.$print({
printable: "el_id", //打印元素ID
type: "html", //类型
// header: this.ruleForm.name, // 内容标题
style:
"*{ font-weight: bold; color: black !important; font-size: 16px} .el-input__inner{font-weight:bold; color:black;} .textarea__inner{font-weight:bold; color:black; }",
css: "", //样式url
// scanStyles: true, // false当前页面样式不应用于打印
documentTitle: 'String', // 页眉内容
font_size: "auto",//字体大小自定义
maxWidth: 3000, //最大宽度
onPrintDialogClose: this.printClose(), //浏览器打印窗口打开后执行的函数
// ignoreElements: ["no-print"], // 不打印元素ID
iframe: false,
targetStyles: ["*"], // 打印内容使用所有HTML样式,没有设置这个属性/值,设置分页打印没有效果
});
获取图片信息转Base64
/**
* 获取图片文件转base64
* @param {File} file
* @returns {String}
*/
export function getFileToBase64(file) {
return new Promise(function (resolve, reject) {
const reader = new FileReader();
let imgResult = "";
reader.readAsDataURL(file);
reader.onload = function () {
imgResult = reader.result;
};
reader.onerror = function (error) {
reject(error);
};
reader.onloadend = function () {
resolve(imgResult);
};
});
}
this.getBase64(file.raw).then((res) => {
const params = res.split(",");
if (params.length > 0) {
this.picBase64 = params[1];
}
});
获取在线Url转Base64
/**
* 获取url文件转Base64
*/
export function getUrlToBase64(imageUrl) {
return new Promise(function (resolve, reject) {
// 画布
var canvas = document.createElement("canvas");
var context = canvas.getContext("2d");
var image = new Image();
var dataUrl = ""
image.setAttribute("crossOrigin", "anonymous");
image.src = imageUrl + "?v=" + Math.random();
image.onload = function () {
canvas.width = image.width;
canvas.height = image.height;
context.drawImage(image, 0, 0, image.width, image.height);
dataUrl = canvas.toDataURL("image/png");
resolve(dataUrl)
}
})
}
去除图片底色
/**
* 去除图片背景
* img 图片的base64编码
* rgba 需要去除的背景色
* tolerance 容差信息
*/
export function removeImgBg(img, rgba, tolerance) {
var imgData = null;
const [r0, g0, b0, a0] = rgba;
var r, g, b, a;
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
const w = img.width;
const h = img.height;
canvas.width = w;
canvas.height = h;
context.drawImage(img, 0, 0);
imgData = context.getImageData(0, 0, w, h);
for (let i = 0; i < imgData.data.length; i += 4) {
r = imgData.data[i];
g = imgData.data[i + 1];
b = imgData.data[i + 2];
a = imgData.data[i + 3];
const t = Math.sqrt((r - r0) ** 2 + (g - g0) ** 2 + (b - b0) ** 2 + (a - a0) ** 2);
if (t <= tolerance) {
imgData.data[i] = 0;
imgData.data[i + 1] = 0;
imgData.data[i + 2] = 0;
imgData.data[i + 3] = 0;
}
}
context.putImageData(imgData, 0, 0);
const newBase64 = canvas.toDataURL('image/png');
img.src = newBase64;
}
HTML转图片
引入npm i html2canvas
import html2canvas from "html2canvas";
注:页面内图片需转为base64,否则会丢失
// 导出图片
getPicture() {
html2canvas(this.$refs.pircute_ref,{backgroundColor:'#F6F6F6'}).then((canvas) => {
var imgData = canvas.toDataURL("image/jpeg");
this.fileDownload(imgData);
});
},
// 下载图片
fileDownload(downloadUrl) {
let alink = document.createElement("a");
alink.style.display = "none";
alink.href = downloadUrl;
alink.download = "图片.png";
document.body.appendChild(alink);
alink.click();
document.body.removeChild(alink);
},
HTML导出PDF
1.使用 html2Canvas + jsPDF 导出PDF
// 导出页面为PDF格式
import html2Canvas from 'html2canvas'
import JsPDF from 'jspdf'
function export_PdfAndSave(options) {
var title = options.pdfName
html2Canvas(options.pdfDom, {
allowTaint: true,
useCORS: true
}).then(function (canvas) {
let contentWidth = canvas.width
let contentHeight = canvas.height
let pageHeight = contentWidth / 592.28 * 841.89
let leftHeight = contentHeight
let position = 0
let imgWidth = 595.28
let imgHeight = 592.28 / contentWidth * contentHeight
let pageData = canvas.toDataURL('image/jpeg', 1.0)
let PDF = new JsPDF('', 'pt', 'a4')
if (leftHeight < pageHeight) {
PDF.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight)
} else {
while (leftHeight > 0) {
PDF.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)
leftHeight -= pageHeight
position -= 841.89
if (leftHeight > 0) {
PDF.addPage()
}
}
}
PDF.save(title + '.pdf')
}
)
}
export default {
export_PdfAndSave
}
2.调用浏览器自身的方法。window.print() 来打印(打印时可选下载)
HTML导出Word
1.插件
- "docxtemplater": "^3.36.1",
- "file-saver": "^2.0.5",
- "jszip": "^2.6.1",
- "jszip-utils": "^0.1.0",
- "docxtemplater-image-module-free": "^1.1.1",
2.方法函数
// htmlToDocx.JS
import { saveAs } from "file-saver";
import docxtemplater from "docxtemplater";
import JSZipUtils from "jszip-utils";
import JSZip from "jszip";
import ImageModule from "docxtemplater-image-module-free";
function exportWord(formData, companyData) {
// let _this = this
// 读取并获得模板文件的二进制内容
JSZipUtils.getBinaryContent('./static/exportDocx.docx', function (error, content) {
if (error) throw error // 抛出异常
function base64DataURLToArrayBuffer(dataURL) {
const base64Regex = /^data:image\/(png|jpg|svg|svg\+xml);base64,/;
if (!base64Regex.test(dataURL)) {
return false;
}
const stringBase64 = dataURL.replace(base64Regex, "");
let binaryString;
if (typeof window !== "undefined") {
binaryString = window.atob(stringBase64);
} else {
binaryString = new Buffer(stringBase64, "base64").toString("binary");
}
const len = binaryString.length;
const bytes = new Uint8Array(len);
for (let i = 0; i < len; i++) {
const ascii = binaryString.charCodeAt(i);
bytes[i] = ascii;
}
return bytes.buffer;
}
// 图片Base64
var opts = {
centered: false,
getImage(tagValue) {
return base64DataURLToArrayBuffer(tagValue)
// return new Promise(function (resolve, reject) {
// JSZipUtils.getBinaryContent(tagValue, function (error, content) {
// if (error) {
// return reject(error)
// } else {
//
// return resolve(content)
// }
// })
// })
},
getSize(img, tagValue, tagName) {
return [100,100]; // 图片固定大小
// let wid = 200; //最大值
// return new Promise(function (resolve, reject) {
// var image = new Image()
// image.src = tagValue
// let imgWidth, imgHeight, scale;
// image.onload = function () {
// imgWidth = image.width
// imgHeight = image.height
// scale = 0
// // 大小超出最大值,按比例缩放
// if (imgWidth > wid) {
// scale = wid / imgWidth
// imgWidth = wid
// imgHeight = imgHeight * scale
// }
// resolve([imgWidth, imgHeight])
// }
// image.onerror = function (e) {
//
// reject(e)
// }
// })
}
};
var imageModule = new ImageModule(opts)
// 创建一个JSZip实例,内容为模板的内容
let zip = new JSZip(content)
// 创建并加载docxtemplater实例对象
let doc = new docxtemplater()
doc.attachModule(imageModule)
doc.loadZip(zip)
// 去除null值导致的undefined
doc.setOptions({
nullGetter: function () {
return "";
}
});
// doc.compile();
doc.setData({ ...formData, ...companyData }) // 设置模板变量的值
try {
doc.render() // 用模板变量的值替换所有模板变量
} catch (error) {
let e = {
message: error.message,
name: error.name,
stack: error.stack,
properties: error.properties
}
throw error // 抛出异常
}
// 生成一个代表docxtemplater对象的zip文件(不是一个真实的文件,而是在内存中的表示)
let out = doc.getZip().generate({
type: 'blob',
mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
})
// 将目标文件对象保存为目标类型的文件,并命名
saveAs(out, formData.projectName + '.docx')
})
}
export default {
exportWord
}
3.使用
// 导出Word
getDocx() {
//数据处理后
htmlToDocx.exportWord(formData, this.companyMessage);
},
4.模板文件
文字:{text};图片:{%image};循环:{#table}{item}{/table}
css动画
1.箭头
<div class="container">
<div class="chevron"></div>
<div class="chevron"></div>
<div class="chevron"></div>
</div>
$base: 0.6rem;
.container {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100vh;
}
.chevron {
position: absolute;
width: $base * 3.5;
height: $base * 0.8;
opacity: 0;
transform: scale(0.3);
animation: move-chevron 3s ease-out infinite;
}
.chevron:first-child {
animation: move-chevron 3s ease-out 1s infinite;
}
.chevron:nth-child(2) {
animation: move-chevron 3s ease-out 2s infinite;
}
.chevron:before,
.chevron:after {
content: '';
position: absolute;
top: 0;
height: 100%;
width: 50%;
background: #2c3e50;
}
.chevron:before {
left: 0;
transform: skewY(30deg);
}
.chevron:after {
right: 0;
width: 50%;
transform: skewY(-30deg);
}
@keyframes move-chevron {
25% {
opacity: 1;
}
33.3% {
opacity: 1;
transform: translateY($base * 3.8);
}
66.6% {
opacity: 1;
transform: translateY($base * 5.2);
}
100% {
opacity: 0;
transform: translateY($base * 8) scale(0.5);
}
}
video标签
类似于所有其它HTML元素,video元素支持 全局属性 (en-US)。
autoplay
布尔属性;指定后,视频会马上自动开始播放,不会停下来等着数据载入结束。
autobuffer
布尔属性;指定后,视频会自动开始缓存,即使没有设置自动播放。该属性适用于视频被认为可能会播放(比如,用户导航到专门播放视频的页面,而不是那种嵌入视频还有其它内容的页面)。视频会一直缓存到媒体缓存满。
实现备注: 虽然是HTML5规范的早期草案的一部分, autobuffer
属性在稍晚的版本被去掉了。 Gecko 2.0 和其它浏览器中已经移除了这个属性,而且有些浏览器中从未实现。规范定义了一个新的枚举属性, preload
, 用不同的语法来取代 autobuffer
属性。
buffered
这个属性可以读取到哪段时间范围内的媒体被缓存了。该属性包含了一个 TimeRanges
对象。
controls
加上这个属性,Gecko 会提供用户控制,允许用户控制视频的播放,包括音量,跨帧,暂停/恢复播放。
controlslist
当浏览器显示自己的控件集(例如,当指定了Controls属性时),Controlslist属性将帮助浏览器选择在媒体元素上显示的控件。
允许接受的value有nodownload
,nofullscreen
和noremoteplayback
如果要禁用图片模式(和控件),请使用disablePictureInPicture
属性。
crossorigin
该枚举属性指明抓取相关图片是否必须用到CORS(跨域资源共享)。 支持CORS的资源 可在 `` 元素中被重用,而不会被污染。允许的值如下:
anonymous
跨域请求(即,使用 Origin:
的HTTP头)会被执行。但是不发送凭证(即,不发送cookie, X.509 证书或者 HTTP Basic 授权)。如果服务器不提供证书给源站点 (不设置 Access-Control-Allow-Origin:
HTTP头),图片会被 污染 并且它的使用会受限。
use-credentials
跨域请求A cross-origin request (i.e. with Origin:
HTTP header) 会被执行,且凭证会被发送 (即, 发送一个 cookie, 一个证书和HTTP Basic授权会被执行)。如果服务器不提供证书给源站点 (通过Access-Control-Allow-Credentials:
HTTP 头),图像会被 污染 且它的使用会受限。
不加这个属性时,抓取资源不会走CORS请求(即,不会发送 Origin:
HTTP 头),保证其在 `` 元素中使用时不会被污染。如果指定非法值,会被当作指定了枚举关键字 anonymous 一样使用。 查看 CORS 设置属性 (en-US) 获取更多信息。
currentTime
读取CurentTime
返回一个双精度浮点值,指示以秒为单位的媒体的当前播放位置。如果video尚未开始播放,则会在开始播放后返回偏移量。通过CurentTime
将当前播放位置设置为给定时间,会在加载媒体时将媒体查找到该位置(从指定的位置开始播放)。
媒体正在播放的情况下,如果媒体缓冲区的数据已经过期(视频已经播放完),则 user agent有可能无法正常拿到数据。有些媒体可能有一个不以0秒开始的媒体时间线(不是从头开始播放的),因此应该将currentTime
的时间设置在其数据失效之前。getStartDate()
这个方法可以用来确定媒体时间线起始的坐标。
disablePictureInPicture
防止浏览器建议图片中的上下文菜单或在某些情况下自动请求图片中的图片。该属性可以禁用 video
元素的画中画特性,右键菜单中的“画中画”选项会被禁用
disableRemotePlayback
- 一个布尔属性,用于禁用使用有线连接的设备(HDMI、DVI等)的远程播放功能。无线技术(Miracast、Chromecast、DLNA、AirPlay等)。
- 在Safari中,您可以使用x-webkit-airplay=“deny”作为后盾。
duration只读
一个双精度浮点值,它指示媒体的持续时间(总长度),以秒为单位,在媒体的时间线上。如果元素上没有媒体,或者媒体无效,则返回的值为NaN。如果媒体没有已知终点(例如时间未知的实时流、网络广播、来自WebRTC的媒体等等),那么这个值就是Infinity。
height
视频展示区域的高度,单位是CSS像素。
intrinsicsize
这个属性告诉浏览器忽略图像的实际内在大小,并假装它是属性中指定的大小。具体来说,图像将在这些维度上展开,图像上的naturalWidth
/naturalHeight
将返回此属性中指定的值。Explainer,examples
loop
布尔属性;指定后,会在视频结尾的地方,自动返回视频开始的地方。
muted
布尔属性,指明了视频里的音频的默认设置。设置后,音频会初始化为静音。默认值是false,意味着视频播放的时候音频也会播放 。
playsinline
一个布尔属性,标志视频将被“inline”播放,即在元素的播放区域内。请注意,没有此属性并不意味着视频始终是全屏播放的。
played
一个 TimeRanges
对象,指明了视频已经播放的所有范围。
preload
该枚举属性旨在告诉浏览器作者认为达到最佳的用户体验的方式是什么。可能是下列值之一:
- none: 提示作者认为用户不需要查看该视频,服务器也想要最小化访问流量;换句话说就是提示浏览器该视频不需要缓存。
- metadata: 提示尽管作者认为用户不需要查看该视频,不过抓取元数据(比如:长度)还是很合理的。
- auto: 用户需要这个视频优先加载;换句话说就是提示:如果需要的话,可以下载整个视频,即使用户并不一定会用它。
- 空字符串:也就代指 auto 值。
假如不设置,默认值就是浏览器定义的了 (即,不同浏览器会选择自己的默认值),即使规范建议设置为 metadata。
使用备注:
autoplay
属性优先于preload
假如用户想自动播放视频,那么很明显浏览器需要下载视频。同时设置autoplay
和preload
属性在规范里是允许的。- 规范没有强制浏览器去遵循该属性的值;这仅仅只是个提示。
poster
一个海报帧的URL,用于在用户播放或者跳帧之前展示。如果属性未指定,那么在第一帧可用之前什么都不会展示;之后第一帧就像海报帧一样展示。
src
要嵌到页面的视频的URL。可选;你也可以使用video块内的 `` 元素来指定需要嵌到页面的视频。
width
视频显示区域的宽度,单位是CSS像素。
时间偏移量目前是指定为float类型的值,表示偏移的秒数。
<video
class="myVideo"
ref="myVideo"
preload
controls
src="./public/video/pwr_video.mp4"
type="video/mp4"
></video>
JS
类
extends
super
关键字
class Person {
constructor(surname,x,y){
this.surname= surname;
this.x = x;
this.y = y;
}
sum(){
return this.x+this.y
}
}
class Student extends Person{ //子类继承父类
constructor(surname,firstname,x,y){
super(surname,x,y); //调用父类的constructor(surname)
this.firstname= firstname; //定义子类独有的属性
this.x = x;
this.y = y;
}
subtract(){
return this.x-this.y;
}
}
子类在构造函数中使用super,必须放到this前面(必须先调用父类的构造方法,再使用子类的构造方法)
utilsFun
1.数组删除
// 需要删除数组 arr
// 需要删除元素集合 list
arr = arr.filter(
(item) => !list.includes(item)
);
Element-UI
踩坑
1.tree
setCurrentKey方法需要在this.$nextTick()内部或者在setTimout()内部
并设置node-key="id"
this.$nextTick(()=>{
// 树节点高亮
this.$refs.tree_ref.setCurrentKey(id);
})
2.el-row
el-row在span之和超出24之后可能会导致排序混乱,排版错乱等问题;
解决方式:
.el-row{
display:flex;
flex-wrap:wrap;
}
MxGraph
1.引用
Api文档:https://tbouffard.github.io/typed-mxgraph
https://www.jianshu.com/p/6234a1dc7685
mxgraph插件包
import mx from "mxgraph";
const mxgraph = mx({});
const { mxGraph, mxClient, mxCodec, mxUtils, mxEvent } = mxgraph;
2.初始化
<!-- 容器 -->
<div id="graphCenter" ></div>
// 初始化mxGraph组件
initMxGraph() {
if (!mxClient.isBrowserSupported()) {
// 判断是否支持mxgraph
mxUtils.error("浏览器不支持!", 200, false);
} else {
// 在容器中创建图表
let container = document.getElementById("graphCenter");
let MxCodec = mxCodec;
let MxGraph = mxGraph;
var graph = new MxGraph(container);
// 是否只读
graph.setEnabled(false);
// 将节点内容标识为html
graph.setHtmlLabels(true);
// 节点大小不允许更改
graph.setCellsResizable(false);
// 是否允许Cells通过其中部的连接点新建连接
graph.setConnectable(false);
// 边被拖动时始终保持连接
graph.setDisconnectOnMove(true);
// 连接线整体不可拖动
graph.setEdgeLabelsMovable(true);
//自适应
// graph.fit();
// 画布大小
// graph.setResizeContainer(true);
// graph.minimumContainerSize = new mxRectangle(0, 0, 800, 500);
// graph.maximumContainerSize = new mxRectangle(0, 0, 1000, 600);
// 生成标签
var parent = graph.getDefaultParent();
//mxGraph画布
this.v_graph = graph;
// 父节点
this.v_parent = parent;
try {
graph.getModel().beginUpdate();
} finally {
graph.getModel().endUpdate();
}
// 打包XML文件
let encoder = new MxCodec();
let xx = encoder.encode(graph.getModel());
// 保存到getXml参数中
this.getXml = mxUtils.getXml(xx);
//自定义事件
// 基础函数
this.eventCenter();
// 鼠标事件
this.configMouseEvent();
}
},
3.数据渲染
①节点
// 初始化节点
let toNode = this.v_graph.insertVertex(
this.v_parent, //节点父级
element.ID, //节点ID
contentBox, //节点内容 HTML String
element.CellX, //节点X坐标
element.CellY, //节点Y坐标
element.CellWidth, //盒子(contentBox)宽度;
element.CellHeight, //盒子(contentBox)高度;
"align=left;fillColor=rgba(235,235,235,0.5);fontColor=#02132a;fontSize=18;strokeColor=rgba(9,215,27,0);"
);
②线条
线条部分样式
// orthogonalEdgeStyle 正交边
// ElbowConnector 直线
// 初始化线
this.v_graph.insertEdge(
this.v_parent, //父级
element.ID, //唯一ID
"", //线条上文字
toNode, //起始位置 元素
toNode2, //终止位置 元素
"edgeStyle=ElbowConnector;endArrow=none;strokeColor=#01A50E;strokeWidth=2;sourcePerimeterSpacing=5;targetPerimeterSpacing=2;dashed=1;"
);
4.Api
// 刷新面板graph
this.v_graph.refresh(cell);
// 删除mxgraph所有的分组
var childVertices = this.v_graph.getChildVertices(this.v_parent);
this.v_graph.removeCells(childVertices);
// 面板放大
this.v_graph.zoomIn();
// 面板缩小
this.v_graph.zoomOut();
// 是否只读,不可进行操作
this.v_graph.setEnabled(true);
// 销毁画板
this.v_graph.destroy();
//鼠标事件监听
this.v_graph.addMouseListener({
currentState: null,
previousStyle: null,
//鼠标按下
mouseDown: (sender, evt) => {
//TODO
},
//鼠标移动
mouseMove: (sender, me) => {
//TODO
},
//鼠标松开
mouseUp: (sender, evt) => {
//TODO
},
});
//节点拖动事件 ps:线条仅整体拖动可触发
this.v_graph.addListener(mxEvent.CELLS_MOVED, (sender, evt) => {
//TODO
}
//获取组并删除
var portCell = this.v_graph.getModel().getCell(groupID);
portCell.removeFromParent();
jsencryptKey
1.安装插件
npm i jsencrypt --save
2.封装函数
jsencryptKey.js文件
import JSEncrypt from 'jsencrypt'
let publicKey = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJEzBDzBqJ/7gKtTZmSrtgz6QGeoCHy2NiPjCslVVr92/oWoglq5gh+tnlS4tqd0TFW+otA3AxHILSiy1D0zoHECAwEAAQ=="
let privateKey = "MIIBOgIBAAJBAJEzBDzBqJ/7gKtTZmSrtgz6QGeoCHy2NiPjCslVVr92/oWoglq5gh+tnlS4tqd0TFW+otA3AxHILSiy1D0zoHECAwEAAQJABSeI+nkrecZtWmejBmbcFxjZKXTbHEZBpMN+EgigBDrwdi11K6AgRtYCfFG6SYtRe2ddNKDHuxX2vN/zNBIQswIhAJI9m/1U0rvevkqWJeG5wSxffbVwNZcGYcEkOWP+bnJzAiEA/i1Ro6i5EKR8hgzJO6w3YsjhZ0ve1MJQfTNwdj1rlIsCIEeHyx0GuG0cboedGbpnWY2Sx7JPyGauwHHwfgHjGbLxAiEAoZ2hRmW23q0n/HhOz+GOCgLex7aHRlMTqLg3bwdYy0cCICX/zKmyB+WXYIpagDnaotTKN7aXiEGdo3cNDET6h2yt"
// 加密方法 公钥
export function getCode(content) {
let encrypt = new JSEncrypt()
encrypt.setPublicKey(publicKey)
let data = encrypt.encrypt(content)
return data
}
// 解密方法 私钥
export function decryptCode(content) {
let encrypt = new JSEncrypt()
encrypt.setPublicKey(privateKey)
let data = encrypt.decrypt(content)
return data
}
3.使用
加密
注:加密字符中‘+’号会被转译为空格 encodeURIComponent将密文编码为新的字符串
import { decryptCode } from "@/utils/jsencryptKey"
let url = "http://192.168.1.5:9530/#/",
token = "ahpwr",
account = "admin"; //user account
// 加密token
token = getCode(token);
window.open(url + "?token=" + encodeURIComponent(token) + "&account=" + encodeURIComponent(account), "_blank");
解密
decodeURIComponent解码后再解密
import { decryptCode } from "@/utils/jsencryptKey"
// 解密taoken
let token = decryptCode(decodeURIComponent(to.query.token))
百度地图SDK
1.BMapGL.js 文件
export function BMPGL(ak) {
return new Promise((resolve, reject) => {
window.init = function () {
resolve(BMapGL)
}
const script = document.createElement('script')
script.type = 'text/javascript'
script.src = `https://api.map.baidu.com/api?type=webgl&v=1.0&ak=${ak}&callback=init`
script.onerror = reject
document.head.appendChild(script)
})
}
2.Demo
<template>
<div id="MapContainer" style="width: 100%; height: 100%">
</div>
</template>
<script>
import { BMPGL } from "@/utils/BMapGL.js";
export default {
data() {
return {
ak: "百度Api的AK",
};
},
mounted() {
this.$nextTick(() => {
this.initData();
});
},
methods: {
initData() {
BMPGL(this.ak)
.then((BMapGl) => {
var map = new BMapGl.Map("MapContainer");
var point = new BMapGl.Point(117.233443, 31.826578);
map.centerAndZoom(point, 17.5); // 初始化地图,设置中心点坐标和地图级别
map.enableScrollWheelZoom(true); //开启鼠标滚轮缩放
map.setMapType(BMAP_EARTH_MAP); // 设置地图类型为地球模式
})
.catch((error) => {
console.log(error);
});
},
},
};
</script>
<style lang="scss" scoped>
.map {
width: 100%;
height: 100%;
}
</style>
标签:function,Web,return,graph,笔记,let,new,const
From: https://www.cnblogs.com/Rking28/p/RKINGVUE.html