# 监听屏幕尺寸变化

Vue中可以使用window的所有方法

mounted() {
    this.screenWidth = document.body.clientWidth
	window.onresize = () => {
	  return (() => {
		this.screenWidth = document.body.clientWidth
	  })()
	}
}

# 自定义全局变量

  • main.js中,全局方法挂载
Vue.prototype.videoPreUrl = videoPreUrl
  • 在需要用的地方直接取值就行
console.log( this.videoPreUrl )

# template 占位符

template可以起到block的作用,但是v-for时不能加key

在vue3的项目中,不免会遇到v-if和v-for一起使用,但我们知道,这两个是不可以一起使用的,v-for 具有比 v-if 更高的优先级,所以我们需要把v-for写到template中,但是控制台会提示:

'<template v-for>' cannot be keyed. Place the key on real elements instead

# 解决方法

在 Vue2中,template 标签不能拥有 key,不过,你可以为其每个子节点分别设置 key

<template v-for="i in list">
  <div :key="'index-' + i.id"></div>
</template>

在 Vue3 中,key 则应该被设置在 template 标签上

 <template v-for="(i, index) in list" :key="index">
  <div>...</div>
  <span>...</span>
</template>

但是我在使用的时候VScode总是一直报错冒红,但是程序是可以运行的,但总看着不舒服,可以尝试将:key="index"写在我们循环的节点上面,程序也是可以运行的。

<template v-for="i in list">
  <div v-if="true" :key="item.id"></div>
  <span v-else></span>
</template>

按照官网说的key 则应该被设置在 template 标签上的话,可以修改.eslintrc.js的配置,在rules的规则上添加:

'vue/no-v-for-template-key': 'off'

或者将将template标签改为div等其他标签,这样的话会多出一个多余的div标签。

# 出现data-v-xxx的原因及解决

在Vue开发中,会遇到html被浏览器解析后,在标签中出现'data-v-xxxxx'标记,如下:

<div data-v-fcba8876 class="xxx"> aaa</div>

这是在标记vue文件中css时使用scoped标记产生的,因为要保证各文件中的css不相互影响,给每个component都做了唯一的标记,所以每引入一个component就会出现一个新的'data-v-xxx'标记

# 深度作用选择器

<style scoped>
  //v-html中设置img的方法 
  .content >>> .img {
    max-width: 100%;
    height: auto;
  }
  //
</style>

# node/node-sass/sass-loader版本兼容

node16+ 对应的node-sass,sass-loader版本

"sass-loader": "^10.2.0",
"node-sass": "^6.0.1",

sass-loader 4.1.1,node-sass 4.3.0
sass-loader 7.0.3,node-sass 4.7.2
sass-loader 7.3.1,node-sass 4.7.2
sass-loader 7.3.1,node-sass 4.14.1

node18+ 对应的版本

"node-sass": "^8.0.0",
"sass-loader": "^10.4.1",

# vue 清除浏览器自动填充表单账号密码

普通文本框添加 autocomplete="off",密码输入框添加autocomplete="new-password"

<input type="text" autocomplete="off" name="username"/>
<input type="password" autocomplete="new-password" name="password"/>

# npm ERR! ERESOLVE could not resolve

从代码仓库拉取代码到本地,执行npm install 命令安装项目依赖,提示ERESOLVE could not resolve
问题出现的原因由于npm版本问题,npm不同版本库之间命令不兼容

//解决办法
npm install --legacy-peer-deps

# 如何修改title标签中的htmlWebpackPlugin.options.title

//在vue.config.js中添加如下代码
chainWebpack(config) {
	config.plugin('html').tap((args) => { 
		args[0].title = '你的标题';
		return args;
	})
}

# 加载public和src/assets下文件的区别

public 文件夹

  • 路径设置时无需添加 public,默认加载 public下的文件
  • 不需要使用 require,否则就变成在 src/assets 下寻找
  • 系统编译后,文件可替换
this.imgUrl = 'images/test.jpg';
// 或
this.imgUrl = './images/test.jpg';

src/assets 文件夹

  • 需要使用 require、import、new URL(),运行时就加载
  • 系统编译后,不能替换,因为被内部编译管理
//仅支持在webpack环境中使用,vite中无法支持
this.imgUrl = require('../assets/images/test.jpg');
import imageIcon from '../../../assets/billboard.png'

//vite中支持
const url = new URL('./src', import.meta.url)

# v-model为空时placeholder不显示

<a-select v-model='a' placeholder="请选择"  >

//解决方案是将a设置为undefined
data() {
  return {
    a:''
  };
}

# 修改checkbox值没有触发change事件

用 js 去修改 checkbox 的 checked 属性,不会触发change事件,所以想要监听 checkbox 的变化,只能:

  • 用户的操作用 change 事件监听
  • 自己用 js 修改的时候,自己在后面写处理函数
<!DOCTYPE html>
<html>
<head>
	<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
	<section id="app">
		<button @click="flag=!flag">切换!</button>
		<input type="checkbox" v-model="flag" @change="handleChange">
	</section>
	<script>
		var app = new Vue({
			el: '#app',
			watch: {
				flag(val) {
					console.log("监听到flag变化:", val);
				}
			},
			data: {
				flag: true,
			},
			methods: {
				handleChange() {
					console.log("触发change事件");
				}
			}
		})
	</script>
</body>
</html>

# props传递数据有延迟如何解决

先判断是否为空再渲染

<footView :details="details" v-if="Object.keys(details).length>0"></footView>

# 适配屏幕的缩放比

# 在外部创建一个detectZoom.js文件,我是在utils文件夹下

export const detectZoom = () => {
  let ratio = 0,
    screen = window.screen,
    ua = navigator.userAgent.toLowerCase();
  if (window.devicePixelRatio !== undefined) {
    ratio = window.devicePixelRatio;
  } else if (~ua.indexOf('msie')) {
    if (screen.deviceXDPI && screen.logicalXDPI) {
      ratio = screen.deviceXDPI / screen.logicalXDPI;
    }
  } else if (
    window.outerWidth !== undefined &&
    window.innerWidth !== undefined
  ) {
    ratio = window.outerWidth / window.innerWidth;
  }
  if (ratio) {
    ratio = Math.round(ratio * 100);
  }
  return ratio;
};

# 在main.js中引用

m是获取的当前屏幕的缩放比,在通过zoom属性对应缩放。zoom属性用于设置或检索对象的缩放比例。

import { detectZoom } from '@/utils/detectZoom.js';
const m = detectZoom();
document.body.style.zoom = 100 / Number(m);

# ob: Observer 取值

注意这种类型的数据不能直接通过对象或者数组的方式进项获取,需要格式转换

//方法一
JSON.parse(JSON.stringify(this.list))

//方法二
Object.assign({},this.list)

两种方式都可以,推荐第一种

# 背景图片路径

# css外设置background-image

在css外设置background-image时,不能直接使用url,应该使用

<li  :style="'background-image:url(require('./../assets/banner_top2.png'))'"></li>

# css内设置background-image

background: url('~@/assets/images/nav/broadcast@2x.png') no-repeat center;

# 深拷贝与浅拷贝

# Object.assign()对象的拷贝

Object.assign() //方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象
Object.assign(target, ...sources) //【target:目标对象】 【souce:源对象(可多个)】
  • 如果目标对象中的属性具有相同的键,则属性将被源对象中的属性覆盖
  • Object.assign 方法只会拷贝源对象自身的并且可枚举的属性到目标对象
const object1 = {
  a: 1,
  b: 2,
  c: 3
};
 
const object2 = Object.assign({c: 4, d: 5}, object1);
 
console.log(object1)  // { a: 1, b: 2, c: 3 }
console.log(object2)  // { c: 3, d: 5, a: 1, b: 2 }

注意

对于Object.assign()而言
如果对象的属性值为简单类型string,number,通过Object.assign,得到的新对象为深拷贝
如果属性值为对象或其他引用类型,那对于这个对象而言其实是浅拷贝的

# 深拷贝

针对深拷贝,需要使用其他办法,因为 Object.assign()拷贝的是属性值。假如源对象的属性值是一个对象的引用,那么它也只指向那个引用


















 
 
 
 
 
 

let obj1 = { a: 0 , b: { c: 0}}; 
let obj2 = Object.assign({}, obj1); 
console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}} 
 
obj1.a = 1; 
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}} 
console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}} 
 
obj2.a = 2; 
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}} 
console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 0}}
 
obj2.b.c = 3; 
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 3}} 
console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 3}} 
//最后一次赋值的时候,b是值是对象的引用,只要修改任意一个,其他的也会受影响
 
// Deep Clone (深拷贝)
obj1 = { a: 0 , b: { c: 0}}; 
let obj3 = JSON.parse(JSON.stringify(obj1)); 
obj1.a = 4; 
obj1.b.c = 4; 
console.log(JSON.stringify(obj3)); // { a: 0, b: { c: 0}}

# 对象的合并

其实就是对象的拷贝,o1就是目标对象,后面的是源对象,后面的属性等会拷贝到目标对象

const o1 = { a: 1 };
const o2 = { b: 2 };
const o3 = { c: 3 };
 
const obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1);  // { a: 1, b: 2, c: 3 }, 注意目标对象自身也会改变。

# nginx部署vue到二级目录

# 修改conf文件夹中的nginx.conf

#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    server {
        listen       80;
        server_name  localhost;
       
        location / {
            root  dist;#这里存放的是你根目录的网站文件,可以不用管
            try_files $uri $uri/ /index.html;
            index  index.html index.htm;
        }

        location /admin {
            alias  你新打包的带二级目录的dist文件夹;
            try_files $uri $uri/ /admin/index.html;#这里要加上你的二级目录名称
            index  index.html index.htm;
        }
        
        location /prod-api/{
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header REMOTE-HOST $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_pass http://localhost:8080/;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }

}

# vue的修改

  • 修改router/index.js

 





export default new Router({
  base:'admin',//添加二级目录的名称
  mode: 'history', // 去掉url中的#
  scrollBehavior: () => ({ y: 0 }),
  routes: constantRoutes
})
  • 修改vue.config。添加admin二级目录名称
publicPath: process.env.NODE_ENV === "production" ? "/admin/" : "/admin/",

# resetFields()重置按钮生效的2个条件

form 要设置 ref 属性
# 且 ref 属性值要和 this.$refs[formName].resetFields() 中的 formName 一致

表单域 el-form-item 上需要设置 prop 属性
# 表单 rules 规则校验、resetFields() 重置文件清理的都是 prop 属性绑定的字段

# 样式穿透的区别

  • /deep/:在vue3.0之前可使用,例如(复写样式前加/deep/),vue3.0及后使用就会报错
& /deep/ .el-input {
    width: 60px;
}
  • ::v-deep:在vue3.0及后使用,替代/deep/
&::v-deep .el-input {
    width: 60px;
}
  • >>>:只作用于css,对于less和scss不起作用,如果是less和scss的话需要用到/deep/或::v-deep