todo
文本无法不换行问题
vscode快捷键
1, command + p 类文件名搜索
2, Ctrl + tab 切换已经打开的导航文件,长按是所有打开的文件列表
@media媒体查询和移动端适配方案
setInterval()和setTimeout()区别
/**
* 只会执行一次
* 延迟2s执行一次run1()
* 注意第一个参数是字符串函数
* */
setTimeout('run1()',2000);
function run1() {
console.log(1)
}
/**
* 不停的执行
* 每隔2s执行一次run2()
* 注意第一个参数是字符串函数
* */
var inter = setInterval('run2()',2000);
function run2() {
console.log(2)
let result = confirm("是否取消定时器?"); //确认返回true, 取消返回false
if (result)
{
alert('取消成功')
clearInterval(inter);
}
}
Math.floor()、Math.ceil()和Math.round()
Math.floor()取最大整数、
Math.ceil()取最小整数
Math.round()四舍五入取整数
常用的第三方功能
1, 安装:
npm install --save vue-pdf
2, 使用方式:
<template>
//可传递URL
<pdf src="./static/relativity.pdf"></pdf>
</template>
<script>
import pdf from 'vue-pdf'
export default {
components: {
pdf
}
}
1, 在浏览器和微信小程序中是支持的FormData(),
2, 放到APP加载vue, FormData()不兼容(在iPhone7-ios11支持), formdata为空,所以后台接收不到formdata对象, 但在苹果浏览器中直接访问vue页面却可以接收到formdata对象.(神奇, 先用base64解决)
vue部署问题
部署vue项目注意事项:
本地开发环境请求正常, 打包(部署)后,访问页面正常,请求接口404
原因:
1, 本地开发环境会使用代理,
`请求网络路径:`
http://172.16.14.39:8082/coalURL/AdminServer/Api/queryEncyclopediInfo
2, 打包(部署)后,前端请求的URL路径是不需要经过代理的,如果要做跨域出来,是需要后端在Nginx上做处理.
`请求的网络路径应该为:`
http://172.16.14.39:8082/AdminServer/Api/queryEncyclopediInfo
图解: devServer只对本地开发环境有效(dev即代表开发环境)
padding和margin的区别
padding是内边距,是与元素相关联的边距,会和元素显示相同的背景色.margin是外边距,是元素之外的边距,不会显示元素的背景色.padding的内边距可以用box-sizing:border把内边距计算到元素指定的宽高中width是100%,元素margin的左右外边距都是10px,此时可以把width写成calc(100%-20px)
padding、margin,失效
如果标签设置了width:100%,可能导致padding或margin失效,这时候应该添加box-sizing:border-box;
什么是BFC?
Box:CSS布局的基本单位
Formatting context: 格式化上下文 / 格式化范围
Formatting context 是 W3C CSS2.1 规范中的一个概念。
它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用。
最常见的 Formatting context 有 Block fomatting context (简称BFC)和 Inline formatting context (简称IFC)。
CSS2.1 中只有 BFC 和 IFC, CSS3 中还增加了 GFC 和 FFC。
BFC:块级格式化范围
BFC提供了一个环境,HTML元素在这个环境中按照一定规则进行布局。
一个环境中的元素不会影响到其它环境中的布局。
比如浮动元素会形成BFC,浮动元素内部子元素,主要受该浮动元素影响,两个浮动元素之间是互不影响的。
浮动元素会尽量接近往左上方(或右上方)
BFC的约束规则
- BFC里面的box都会以垂直方向排列
- Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠。
➤p1和p2的margin都是10,那么我们看到p1和p2的实际间距为10.
➤需要把p1或p2用div包裹,然后给div激活BFC. 不能只把p1、p2激活BFC,因为他们还是在同一个BFC
- 每个盒子(块盒与行盒)的margin box的左边,与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。
➤无论是块级元素还是行级元素或设置了浮动的元素,都会与包含它们的容器(元素)的左边或右边相接触。
- BFC的区域不会与float box重叠。
➤所有的元素默认都不属于BFC、float,非BFC的p1和设置float的p2会重叠在父容器的左上角,当把p1设置为BFC时,
➤由于BFC和float盒子(元素)不会重叠,就会一个一个排列。又因为浮动元素会尽量接近左上或右上方,所以就会形成两列布局
- BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
- 计算BFC的高度时,浮动元素也参与计算。
➤父容器中如有没有设置高度,子元素如果存在浮动,会导致父容器高度塌陷。
➤如果激活父容器的BFC,父容器高度会把浮动子元素的高度计算在内,正常显示。
怎么形成BFC?
- float的值不为none
- position的值不是static或者relative
- display的值是inline-block、table-cell、flex、table-caption或者Inline-flex
- overflow的值不是visible
BFC实际使用场景
①②③处的margin都生效了
前提知识:
(元素指标签view;box是元素的单位,可理解为元素本身),
BFC的约束规则其一:
Box垂直方向的距离由margin决定。
属于同一个BFC的两个相邻Box的margin会发生重叠。
注意:view1和view2是相邻box, 就算它们各自都激活了BFC
还是会发生margin重叠,因为它们始终是相邻的box,
所以应该给view1或view2外层套一层<view>,然后激活BFC。
<view class="view1"></view>
<view class="view2"></view>
为了使c1-view和c2-view设置的margin上下边距都生效,
需要给其中一个box激活BFC,
这样,c1-view和c2-view就不在同一个BFC环境中了,
他们各自的margin也就不会发生重叠了。
box-sizing
box-sizing: content-box;
前提知识:
1, rpx是微信自适应的单位,px = rpx/2
2, 谷歌浏览器,box-sizing默认为content-box;
结论:
view1和view2,
css指定宽高都是50px,
padding都是25px,
border边框宽度都是5px.
由于box-sizing为content-box,
padding,border都会计算到实际宽高中,但是margin不会计算到实际宽高中!!!
所以,view1和view2的实际宽高都是110px
box-sizing: border-box;如果指定宽高不够减的, 那么,实际宽高=padding+border
//如果指定宽高不够减的,
那么,实际宽高=padding+border
view1和view2实际指定宽高都是50px, 但box-sizing设置为border-box时
padding和border都会计算到指定宽高中, margin不计算到指定宽高,
padding左右总宽为50,上下总高为50,已经占了指定宽高的总宽高, 所以实际宽高都为0。
元素的padding(内边距)和宽高都会显示相同的背景色,而 margin(外边距)不会显示元素设置的背景色
Vue.use内部会自动寻找install方法进行调用,接收的第一个参数是Vue(Vue可以理解为一个类或构造函数)
自动化引入模块
require.context 参数:
1. 文件夹路径
2. 是否递归查找子文件夹下的模块
3. 模块匹配规则,一般匹配文件后缀名
在开发中大型项目时,会将一个大功能拆分成一个个小功能,除了能便于模块的复用,也让模块条理清晰,后期项目更好维护。
require.context 一次引入文件夹所有的模块文件,而不需要逐个模块文件去引入。每当新增模块文件时,就只需要关注逻辑的编写和模块暴露,require.context 会帮助我们自动引入。
需要注意 require.context 并不是天生的,而是由 webpack 提供。在构建时,webpack 在代码中解析它。
对象生成新对象
var a = {name:'mrhan'}
var b = {
...a,
'age':29
}
console.log(`b:${JSON.stringify(b)}`); //b:{"name":"mrhan","age":29}
路由懒加载(动态chunkName)
常见用法
import Home from "../views/Home.vue";
let router = new Router({
routes: [
{
path: "/",
name: "Home",
component: Home
},
// 通常我们还会为延迟加载的路由添加“魔法注释”(webpackChunkName)来自定义包名,在打包时,js文件会以魔法注释开头。
{
path:'/login',
name:'login',
component: import(/* webpackChunkName: "login" */ `@/views/login.vue`) //魔法注释
},
{
path: "/about",
name: "About",
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () =>
import(/* webpackChunkName: "about" */ "../views/About.vue") //魔法注释
}
]
})
自动注入方式
const routeOptions = [
{
path: "/",
name: "Home",
},
{
path:'/login',
name:'login',
},
{
path: "/about",
name: "About",
}
];
// 假如routeOptions的对象中只有path和name属性,那么可以用下面的方法统一自动添加component
const routes = routeOptions.map(route => {
if (!route.component) {
route = {
...route,
component: () => import(/* webpackChunkName: "[request]" */ `@/views/${route.name}.vue`)
}
}
return route
})
函数组件
样式穿透
使用场景:在某个界面想要修改第三方库中的样式,由于style设置了scoped会导致样式没有生效的情况
原因:因为第三方组件的默认样式优先级比scoped中样式的优先级高!!但不完全都高,不生效的时候肯定是高.
解决方案:在需要穿透的样式前,添加>>>或/deep/
<style lang="less" scoped>
.van-circle {
/deep/ .van-circle__text {
color: blue;
}
//>>> .van-circle__text {
// color: blue;
//}
}
</style>
监听组件生命周期
方式1:
在子组件的生命周期函数中,使用$emit调用父类的方法名
方式2:
使用@hook监听组件生命周期(created、updated、mounted)
<template>
<child @hook:mounted="listenMounted" ></child>
</template>
页面销毁时清除定时器
方式1:定义全局变量timer
export default {
mounted() {
this.timer = setInterval(() => {
console.log(Date.now())
}, 1000)
},
beforeDestroy() {
clearInterval(this.timer)
}
}
方式2:通过$on或$once监听页面生命周期销毁,清除定时器
export default {
mounted() {
this.creatInterval('hello')
this.creatInterval('world')
},
creatInterval(msg) {
let timer = setInterval(() => {
console.log(msg)
}, 1000)
this.$once('hook:beforeDestroy', function() {
clearInterval(timer)
})
}
}
VSCode代码自动补全html标签、css属性及值
setting文件内容,替换为:
{
"window.zoomLevel": 0,
"terminal.integrated.rendererType": "dom",
"editor.suggest.snippetsPreventQuickSuggestions": false,
"files.associations": {
"*.vue":"html"
}
}
consoles用法
- 输出内容: console.log('test')
- 把数组以表格形式输出:console.table([1, 2, 3])
- 输出当前界面的堆栈信息:console.trace('Test')
一套目前主流的前端技术栈。
(1)Node.js:服务器端的 JavaScript 运行环境,不管哪种前端开发,都必不可少的底层环境。
(2)Webpack:语法转换工具,把 ES6/TypeScript/JSX 语法转成浏览器可以运行的代码。
(3)Koa2:一个非常流行、简洁强大的 Node.js 后端的 Web 开发框架。
(4)MongoDB:目前应用最广泛的非关系数据库之一,功能丰富,用法较简单。
(5)Vue 全家桶:
Vue:前端基础框架
Vuex:配套的前端状态管理库。
Vue Router:官方的路由插件,构建单页面应用必不可少。
Vue CLI:脚手架工具,帮你快速上手 Vue 开发,无需再花多余时间去实现项目架构。
Vant:有赞前端团队开发的轻量级移动端 Vue 组件库,让你快速使用已经封装好的各种页面组件。
vue-router钩子beforeRouteEnter函数获取到this实例
官方文档:
const Foo = {
template: `...`,
beforeRouteEnter (to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当钩子执行前,组件实例还没被创建
},
beforeRouteUpdate (to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave (to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
}
export default {
data(){
return {
num: 18
}
},
beforeRouteEnter(to, from, next){
next(vm=>{
vm.num=19;
})
}
}
vue的keep-alive组件清除缓存
//使用方法:
import { h_keepalivePath } from '@/components/global/toolway'
beforeRouteLeave(to, from, next) {
h_keepalivePath(to,from,next,this,'/otherlistpagedetail');
}
//toolway.js
/* to, from, next为路由默认参数,that是调用者的this(因为要用到当前页的对象方法) path是跳转到下一页需要缓存当前页的路径(下一页的路由) */
export function h_keepalivePath(to, from, next, that, path) {
if (to.path == path) { //去详情页的时候, 需要缓存列表, 否则不需要缓存走else
from.meta.keepAlive = true;
} else {
let vnode = that.$vnode
let parentVnode = vnode && vnode.parent;
if (parentVnode && parentVnode.componentInstance && parentVnode.componentInstance.cache) {
var key = vnode.key == null
? vnode.componentOptions.Ctor.cid + (vnode.componentOptions.tag ? `::${vnode.componentOptions.tag}` : '')
: vnode.key;
var cache = parentVnode.componentInstance.cache;
var keys = parentVnode.componentInstance.keys;
if (cache[key]) {
that.$destroy()
// remove key
if (keys.length) {
var index = keys.indexOf(key)
if (index > -1) {
keys.splice(index, 1)
}
}
cache[key] = null
}
}
}
next();
}
export、export default、import
在 ES6 前,实现模块化使用的是 RequireJS 或者 seaJS(分别是基于AMD规范的模块化库,和基于CMD规范的模块化库)。
commonjs规范的 require(导入) module.exports(导出)
ES6 引入了模块化,化分为导出(export) 、导入(import)两个模块。
export 导出的语法有两种:
➤export 命名导出(每个模块包含任意数量)
➤export default 默认导出(每个模块只包含一个)
- 在一个文件或模块中,export、import可以有多个,export default仅有一个。
- 通过export方式导出,在导入时要加{},导入的变量名,须和导出的变量名相同,顺序可以不一致。
//test.js
export var a = "My name is Tom!";
export var b = "My name is Tom!";
//上面两行可以优化为:export {a,b}
注意:
const c = 66;
// export c; //error, 导出内容:应为声明或语句
export {c}; //export导出变量时,必须要加{}
//test2.js
//这里的a,b,c必须和test.js中的a,b,c名称保持一致,要想改变名称参考下面【练习】中的as用法
import {a,b,c} from './test.js'
- export default方式导出,在导入时不需要{}
//test.js
var a = "My name is Tom!";
export default a;
//test2.js
//x表示:任意变量名
import x from './test.js'; //x不需要{}包裹
- import多个文件,变量重名时,可以使用as改变变量名称
export & export default练习
要导出的文件(test.js)
//test.js
export var a = 1;
export const b = 2;
export let c = 2;
export let d = {
name:'mrhan'
};
// 上面等价于下面这一行,注意:不能重复export相同的变量!
// export {a,b,c,d}
var e = 11;
export default e; //export default只能存在一个.
导入的文件(test2.js)
//这里修改了f的名称为f1, f失效.
import e,{ a,b,c,d,f as f1 } from "./test.js";
// 下面写法是错误的,{}后面必须紧跟from
// import { a,b,c,d },e from "../../api/api";
➤下面是使用导入变量的场景👇
//a:1, b:2, c:2, d:{"name":"mrhan"}, e:11, f:undefined, f1:55
console.log(`a:${a}, b:${b}, c:${c}, d:${JSON.stringify(d)}, e:${e}, f:${f}, f1:${f1}`);
// a = 10; //error,只读
// b = 20; //error,只读
// c = 30; //error,只读
// d = {}; //error,不能改变d的引用指向,但可以改变d的属性
d.name = 'age'; //可以修改对象d的属性
// e = 22; //error
// f = 4; //f失效后变为undefined,这里相当于创建了个变量f=4
// f1 = 5; //error,只读
// a:1, b:2, c:2, d:{"name":"age"}, e:11, f:4, f1:55
console.log(`a:${a}, b:${b}, c:${c}, d:${JSON.stringify(d)}, e:${e}, f:${f}, f1:${f1}`);
export 函数、 import 函数
//导入&用法
import { test2 } from '@/components/global/toolway'
test2('我是参数params');
//导出函数的用法1:
export function test2(params) {
console.log('diaoyong le' + params);
}
//导出函数的用法2:
export const test2 = (params)=>{
console.log('diaoyong le' + params);
}
Promise用法
resolve和reject用法
resolve()和reject(), 只能传递一个参数,其余参数默认undefined 可以传一个对象Promise对象的then和catch方法, 会默认返回Promise.resolve(data); data是then中的参数,默认传递
Promise.resolve().then(() => {
return new Error('error!!!')
}).then(res => {
console.log("then: ", res)
}).catch(err => {
console.log("catch: ", err)
})
多个网络请求顺序执行
多个网络请求异步执行完成, 再执行最后一个网络请求
this.$router.back()失效
原因: 使用了禁用安卓物理返回键导致
//禁止安卓的物理返回键
if (window.history && window.history.pushState) {
//禁止侧滑返回
history.pushState(null, null, document.URL);
window.addEventListener('popstate', function () {
history.pushState(null, null, document.URL);
});
}
☆☆☆☆☆☆☆☆☆☆vue工具☆☆☆☆☆☆☆☆☆☆
页面中显示控制台日志插件(vconsole)
//在package.json中添加开发依赖:
"dependencies": {
"vconsole": "^3.3.4"
}
//在main.js中引用
import Vconsole from 'vconsole'
let vConsole = new Vconsole()
Vue.use(vConsole)