前端学习笔记

笔记

小知识

V-ON绑定事件 V-BIND绑定属性

Network中可以查看当前发起的请求

XHR这个标签出现在Chrome浏览器的开发者工具Network选项卡中

XHR类型即通过XMLHttpRequest方法发送的请求即AJAX请求

外部JS引入当前Vue实例 函数中传this指向就好了

forEach没有返回值要有返回值的话用map

git checkout -b dev origin/dev 建立分支并且从远程拉取

APP的组件生命周期与小程序有出入

scroll view 有滑动时间并把scrollTop返回给scroll view 滑动会有抖动

页面滑动最好用

Console.log() 一个对象 浏览器显示出来的是最后结果 如果其中属性是有异步函数返回的,你将读不到那个属性

CCS3 中的Calc()函数

await等的是Promise对象

通过data-xx 绑定一个值 可以通过event获取

z-index只有在设置了position为relative,absolute,fixed时才会有效。

z-index的“从父原则”。设置了z-index的元素要在相同的根元素下菜有效

微信小程序的Console.log()可以字符串加数据也会显示对象

如果需要在页面进入时设置标题,可以在onReady内执行,以避免被框架内的修改所覆盖。如果必须在onShow内执行需要延迟一小段时间

小程序 组件CSS优先 APP 页面CSS优先

transition 触发条件是当属性变化的时候触发

闭包是指有权访问另外一个函数作用域中的变量的函数。可以理解为(能够读取另一个函数作 用域的变量的函数)

src用于替代这个元素,而href用于建立这个标签与外部资源之间的关系。

hasOwnProperty(property)
判断对象是否有某个特定的属性。必须用字符串指定该属性。(例如,o.hasOwnProperty(“name”))
IsPrototypeOf(object)
判断该对象是否为另一个对象的原型。

setData无法使用

//重写setData使uniapp支持setData写法
import Mixin from “./common/mixins.js”;
Vue.mixin(Mixin);

require和import区别

Nodejs用require 和 export.moudle 其他用Import 和export

require 是赋值过程并且是运行时才执行
import 是解构过程并且是编译时执行

require可以理解为一个全局方法,就意味着可以在任何地方执行。
而import必须写在文件的顶部。

require的性能相对于import稍低,因为require是在运行时才引入模块并且还赋值给某个变量,
而import只需要依据import中的接口在编译时引入指定模块所以性能稍高

子传父

子传父通过自定义事件,emit 触发自定义事件传值,再通过自定义事件绑定一个函数进行取值

双位数转换为一位

parseInt(‘01’);

抖和最简单的节流

var obj = {};
function searchResult(){
	clearTimeOut(obj.g);
	obj.g = setTimeout(function(){
	   //这里发送请求
	},1000)
 
}
var pre = new Date();
function trol(fn,delay){
    return function () {
        var now = new Date();
        if(now-pre >= delay){
            fn();
            pre = new Date();
        }
    }

防抖

在连续的操作中,无论进行了多长时间,只有某一次的操作后在指定的时间内没有再操作,这一次才被判定有效

节流

规定时间内,只触发一次,可以通过设置immediate来决定触发的时机在这个时间的开始,还是结束的时候执行。

filter

filters: {
ellipsis (value) {
      if (!value) return ''
      if (value.length > 32) {
        return value.slice(0,32) + '...'
      }
      return value
    }
  }

抽象类和接口的不同

前端学习笔记_第1张图片

枚举

//enum 枚举

enum Gender {

  Male = 0,

  Female = 1,

}

let i: { name: string, gender: Gender }

i = {

  name: '孙悟空', gender: Gender.Male//0

}

尺寸单位

  • rpx(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。
设备 rpx换算px (屏幕宽度/750) px换算rpx (750/屏幕宽度)
iPhone5 1rpx = 0.42px 1px = 2.34rpx
iPhone6 1rpx = 0.5px 1px = 2rpx
iPhone6 Plus 1rpx = 0.552px 1px = 1.81rpx

1 rpx = 屏幕宽度/750 px

页面滚动

给元素设置catchtouchmove=“notmove” notmove为空的返回函数就可以阻止滚动,只有真机测试的时候才有反应,鼠标滚动仍可以滚动,uniapp没有catchtouchmove,可用@touchmove.stop.prevent代替

事件传递

当tap或者click时,点击后事件默认是冒泡,当你添加.stop的时候当事件触发对应的stop后不再传播

ScollView中定位的坑

position:fixed会在ScollView失效,Canvas也不能用position:fixed

Vuex的Getter

相当于Vuex里的computed属性

  getters: {
    // Getter 接受 state 作为其第一个参数
    weekDate: state => {
      return moment(state.date).format('dddd'); 
    }
  }

不但如此,Getter 还会将 store.getters 对象暴露出去,你可以以属性的形式访问这些值:

console.log(store.getters.weekDate)

我们可以很容易地在任何组件中使用它:

computed: {
  weekDate () {
    return this.$store.getters.weekDate
  }
}

Data为什么是函数

因为Data是函数的话他可以有return然后返回一个对象,而每个对象都是独立的作用域的,相同类型的组件的data就可以区分开来

异步组件

components:{

​ List:()=> import(’./List’)

}

路由懒加载

import Vue from ‘vue’
import VueRouter from ‘vue-router’

Vue.use(VueRouter)
const router = new VueRouter({
routes: [
{ path: ‘/login’, component: () => import(’@/views/login/index.vue’) },
{ path: ‘/home’, component: () => import(’@/views/home/home.vue’) }
]

export default router

Vue组件通讯有哪些方式?

1、props 和 e m i t 。 父 组 件 向 子 组 件 传 递 数 据 是 通 过 p r o p s 传 递 的 , 子 组 件 传 递 给 父 组 件 是 通 过 emit。父组件向子组件传递数据是通过props传递的,子组件传递给父组件是通过 emitpropsemit触发事件来做到的。

2、$parent 和 $children 获取单签组件的父组件和当前组件的子组件。

3、$attrs 和 l i s t e n e r s A − > B − > C 。 V u e 2.4 开 始 提 供 了 listeners A -> B -> C。Vue2.4开始提供了 listenersA>B>CVue2.4attrs和$listeners来解决这个问题。

4、父组件中通过 provide 来提供变量,然后在子组件中通过 inject 来注入变量。(官方不推荐在实际业务中适用,但是写组件库时很常用。)

5、$refs 获取组件实例。

6、envetBus 兄弟组件数据传递,这种情况下可以使用事件总线的方式。

7、vuex 状态管理。

扩展补充:display:none 、 visibility:hidden 和 opacity:0 之间的区别?

三者公共点都是隐藏。不同点:

  • 一、是否占据空间。
    display:none,隐藏之后不占位置;visibility:hidden、opacity:0,隐藏后任然占据位置。
  • 二、子元素是否继承。
    display:none — 不会被子元素继承,父元素都不存在了,子元素也不会显示出来。
    visibility:hidden — 会被子元素继承,通过设置子元素 visibility:visible 来显示子元素。
    opacity:0 — 会被子元素继承,但是不能设置子元素 opacity:0 来先重新显示。
  • 三、事件绑定。
    display:none 的元素都已经不存在了,因此无法触发他绑定的事件。
    visibility:hidden 不会触发他上面绑定的事件。
    opacity:0 元素上面绑定的事件时可以触发的。
  • 四、过度动画。
    transition对于display是无效的。
    transition对于visibility是无效的。
    transition对于opacity是有效的。

Vue中methods声明方式与函数的声明方式

 methods:{       

 *// 在此时定义方法,方法之间使用逗号分隔*        

方法名:function(){} 

});
函数声明方式

    声明 : function first(){};

    调用:first()

函数表达式声明方式

     声明: var second=function(){};

    调用:second()

scroll-view 踩坑

  • scroll-view 不适合放长列表,有性能问题。长列表滚动和下拉刷新,应该使用原生导航栏搭配页面级的滚动和下拉刷新实现。包括在app-nvue页面,长列表应该使用list而不是scroll-view。

Uniapp页面级回到顶部

好像不需要事先设置生命周期

onPageScroll(e) {
this.scrollTop = e.scrollTop;
},

​  回到顶部函数

uni.pageScrollTo({
      scrollTop: 0, duration: 300
    });

组件引用JS

组件引用的JS是相对于组件的位置

CSS中left属性

通常单独使用left、right、top、bottom均无效,需要在使用绝对定位CSS position样式才能生效。

一般left和right在一个样式是只能使用其一,不能left和right都设置,要么使用left就不使用right,要么使用right就不使用left,如果left和right均使用将会出现兼容问题,一个对象设置了靠左left多少距离,自然右边距离自然就有了所以无需设置左边。

相同道理,top和bottom对一个对象只能使用其一,不然会出现逻辑兼容问题。譬如一个人让你往左走,一个人让你往右走,同时发出往左往右走这个时候你也不好判断往那边走。

组件切换

在这里我先介绍component标签: 它是Vue内置的标签,它的用途是可以动态绑定我们的组件,根据数据不同更换不同的组件.
比如:这个效果效果:

前端学习笔记_第2张图片

<body>
    <div id="app">
        <component :is="who"></component>
        <button @click="changeComponent">changeComponent</button>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        let componentA={
            template:`
I am componentA
`
} let componentB={ template:`
I am componentB
`
} let componentC={ template:`
I am componentC
`
} let app = new Vue({ el: '#app', data:{ who:'componentB' }, components:{ "componentA":componentA, "componentB":componentB, "componentC":componentC }, methods: { changeComponent(){ if(this.who=="componentA"){ this.who="componentB" } else if(this.who=="componentB"){ this.who="componentC" }else{ this.who="componentA" } } }, }) </script> </body>

Vue事件相关

1、vm.$on( event, callback )

监听当前实例上的自定义事件。事件可以由vm.$emit触发。回调函数会接收所有传入事件触发函数的额外参数。

2、vm.$emit( event, […args] )

触发当前实例上的事件。附加参数都会传给监听器回调,如果没有参数,形式为vm.$emit(event)

3、vm.$off( [event, callback] )

移除自定义事件监听器。

  • 如果没有提供参数,则移除所有的事件监听器;

  • 如果只提供了事件,则移除该事件所有的监听器;

  • 如果同时提供了事件与回调,则只移除这个回调的监听器。

inject provide

		    
				

c组件需要用,在c引用

自定义指令 directives

浅谈cookie,session和localStorage,sessionStorage的区别

https://segmentfault.com/a/1190000017155151

mapState 辅助函数

中的方法虽然引入的时候方便了,但是computed中定义的代码还是很多,而这时候vuex又给我们提供了更简便的方法mapState方法

import {mapState} from 'vuex'
export default {
  name: 'home',
  computed: mapState(['nickname','age','gender'])
}
mapState(['nickname','age','gender']) //映射哪些字段就填入哪些字段

这一句代码就相当于下面这些

nickname(){return this.$store.state.nickname}
age(){return this.$store.state.age}
gender(){return this.$store.state.gender}

mapMutations

跟mapState、mapGetters一样

methods:{
 ...mapMutations(['addAge'])
}

mapMutations([‘addAge’])这一句就相当于下面的代码

addAge(payLoad){
  this.$store.commit('addAge',payLoad)
}

MapGetters

2.1 getters相当于vue中的计算属性,通过getters进一步处理,得到我们想要的值,而且允许传参,第一个参数就是state

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
 
export default new Vuex.Store({
  state: { //存放状态
    nickname:'Simba',
    firstname:'张',
    lastname:'三丰',
    age:20,
    gender:'男',
    money:1000
  },
  getters:{
    realname(state){
      return state.firstname+state.lastname
    },
    money_us(state){
      return (state.money/7).toFixed(2)
    }
  },
  mutations: {},
  actions: {},
  modules: {}
})

vue部分

computed: {  //computed是不能传参数的
 valued(){
   return this.value/7
 },
 ...mapGetters(['realname','money_us'])

为什么用获取state用computed

不过我还有个问题就是,官方文档都是把属性state,放入computed里面去,我想vuex本身就是响应式的,能追踪到变化的,我完全可以在需要用的到地方去使用,也就是this.$store.state.count,为什么还要放在computed下呢,纯粹是因为这样可以缩减代码量吗?还是有别的原因,望指教

你如果只是想单独使用 this.$store.state.count 的话,那直接用或者mapState一下就好了。computed 一般是需要收集多个依赖,或者做一些额外的计算时使用。

谢回答,可是mapSate不也放入在computed下了嘛,我对vuex属性放在computed下的初步认识就是缩写代码量,_!

嗯,如果仅单独使用的话 是的

常用数组方法

*1*|***0***join()

join,就是把数组转换成字符串,然后给他规定个连接字符,默认的是逗号( ,)

书写格式:join(" "),括号里面写字符串 (“要加引号”),

var arr = [1,2,3];
console.log(arr.join());     // 1,2,3
console.log(arr.join("-")); 
var arr = [1,2,3];
console.log(arr.join());     // 1,2,3
console.log(arr.join("-"));   // 1-2-3
console.log(arr);         // [1, 2, 3](原数组不变)

*2*|***0***push()和pop()

push(): 把里面的内容添加到数组末尾,并返回修改后的长度。

pop():移除数组最后一项,返回移除的那个值,减少数组的length。

书写格式:arr.push(" "),括号里面写内容 (“字符串要加引号”),

书写格式:arr.pop( )

var arr = ["Lily","lucy","Tom"];
var count = arr.push("Jack","Sean");
console.log(count);           // 5
console.log(arr);            // ["Lily", "lucy", "Tom", "Jack", "Sean"]
var item = arr.pop();
console.log(item);            // Sean
console.log(arr);             // ["Lily", "lucy", "Tom", "Jack"]

*3*|***0***shift() 和 unshift() (和上面的push,pop相反,针对第一项内容)

**shift():删除原数组第一项,并返回删除元素的值;如果数组为空则返回undefined 。

**

unshift:将参数添加到原数组开头,并返回数组的长度 。

书写格式:arr.shift(" "),括号里面写内容 (“字符串要加引号”),

var arr = ["Lily","lucy","Tom"];
var count = arr.unshift("Jack","Sean");
console.log(count);               // 5
console.log(arr);                //["Jack", "Sean", "Lily", "lucy", "Tom"]
var item = arr.shift();
console.log(item);               // Jack
console.log(arr);                // ["Sean", "Lily", "lucy", "Tom"]

*4*|***0***sort()

sort():将数组里的项从小到大排序

书写格式:arr.sort( )

var arr1 = ["a", "d", "c", "b"];
console.log(arr1.sort());           // ["a", "b", "c", "d"]

sort()方法比较的是字符串,没有按照数值的大小对数字进行排序,要实现这一点,就必须使用一个排序函数

function sortNumber(a,b)
{
  return a - b
}
arr = [13, 24, 51, 3]; console.log(arr.sort());           // [13, 24, 3, 51] 
console.log(arr.sort(sortNumber));     // [3, 13, 24, 51](数组被改变)

*5*|***0***reverse()

reverse():反转数组项的顺序。

书写格式:arr.reverse( )

var arr = [13, 24, 51, 3];
console.log(arr.reverse());         //[3, 51, 24, 13]
console.log(arr);               //[3, 51, 24, 13](原数组改变)

*6*|***0***concat()

concat() :将参数添加到原数组中。这个方法会先创建当前数组一个副本,然后将接收到的参数添加到这个副本的末尾,最后返回新构建的数组。在没有给 concat()方法传递参数的情况下,它只是复制当前数组并返回副本。

书写格式:arr.concat(),括号里面写内容 (“字符串要加引号”),

var arr = [1,3,5,7];
var arrCopy = arr.concat(9,[11,13]);
console.log(arrCopy);             //[1, 3, 5, 7, 9, 11, 13]
console.log(arr);               // [1, 3, 5, 7](原数组未被修改)

*7*|***0***slice()

slice():返回从原数组中指定开始下标到结束下标之间的项组成的新数组。slice()方法可以接受一或两个参数,即要返回项的起始和结束位置。在只有一个参数的情况下, slice()方法返回从该参数指定位置开始到当前数组末尾的所有项。如果有两个参数,该方法返回起始和结束位置之间的项——但不包括结束位置的项。

书写格式:arr.slice( 1 , 3 )

var arr = [1,3,5,7,9,11];
var arrCopy = arr.slice(1);
var arrCopy2 = arr.slice(1,4);
var arrCopy3 = arr.slice(1,-2);
var arrCopy4 = arr.slice(-4,-1);
console.log(arr);               //[1, 3, 5, 7, 9, 11](原数组没变)
console.log(arrCopy);             //[3, 5, 7, 9, 11]
console.log(arrCopy2);            //[3, 5, 7]
console.log(arrCopy3);            //[3, 5, 7]
console.log(arrCopy4);            //[5, 7, 9]

arrCopy只设置了一个参数,也就是起始下标为1,所以返回的数组为下标1(包括下标1)开始到数组最后。

arrCopy2设置了两个参数,返回起始下标(包括1)开始到终止下标(不包括4)的子数组。

arrCopy3设置了两个参数,终止下标为负数,当出现负数时,将负数加上数组长度的值(6)来替换该位置的数,因此就是从1开始到4(不包括)的子数组。

arrCopy4中两个参数都是负数,所以都加上数组长度6转换成正数,因此相当于slice(2,5)。

*8*|***0***splice()

splice():删除、插入和替换。

删除:指定 2 个参数:要删除的第一项的位置和要删除的项数。

书写格式:arr.splice( 1 , 3 )

插入:可以向指定位置插入任意数量的项,只需提供 3 个参数:起始位置、 0(要删除的项数)和要插入的项。

书写格式:arr.splice( 2,0,4,6 )
替换:可以向指定位置插入任意数量的项,且同时删除任意数量的项,只需指定 3 个参数:起始位置、要删除的项数和要插入的任意数量的项。插入的项数不必与删除的项数相等。

书写格式:arr.splice( 2,0,4,6 )

var arr = [1,3,5,7,9,11];
var arrRemoved = arr.splice(0,2);
console.log(arr);                //[5, 7, 9, 11]
console.log(arrRemoved);            //[1, 3]
var arrRemoved2 = arr.splice(2,0,4,6);
console.log(arr);                // [5, 7, 4, 6, 9, 11]
console.log(arrRemoved2);           // []
var arrRemoved3 = arr.splice(1,1,2,4);
console.log(arr);                // [5, 2, 4, 4, 6, 9, 11]
console.log(arrRemoved3);           //[7]

*9*|***0***indexOf()和 lastIndexOf()

indexOf():接收两个参数:要查找的项和(可选的)表示查找起点位置的索引。其中, 从数组的开头(位置 0)开始向后查找。

书写格式:arr.indexof( 5 )

*lastIndexOf:接收两个参数:要查找的项和(可选的)表示查找起点位置的索引。其中, 从数组的末尾开始向前查找。*

书写格式:arr.lastIndexOf( 5,4 )

var arr = [1,3,5,7,7,5,3,1];
console.log(arr.indexOf(5));       //2
console.log(arr.lastIndexOf(5));     //5
console.log(arr.indexOf(5,2));      //2
console.log(arr.lastIndexOf(5,4));   //2
console.log(arr.indexOf("5"));      //-1

*10*|***0***forEach()

forEach():对数组进行遍历循环,对数组中的每一项运行给定函数。这个方法没有返回值。参数都是function类型,默认有传参,参数分别为:遍历的数组内容;第对应的数组索引,数组本身。

书写格式:arr.forEach()

var arr = [1, 2, 3, 4, 5];
arr.forEach(function(x, index, a){
console.log(x + '|' + index + '|' + (a === arr));
});
// 输出为:
// 1|0|true
// 2|1|true
// 3|2|true
// 4|3|true
// 5|4|true

*11*|***0***map()

map():指“映射”,对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组。

书写格式:arr.map()

var arr = [1, 2, 3, 4, 5];
var arr2 = arr.map(function(item){
return item*item;
});
console.log(arr2);         //[1, 4, 9, 16, 25]

*12*|***0***filter()

filter():“过滤”功能,数组中的每一项运行给定函数,返回满足过滤条件组成的数组。

书写格式:arr.filter()

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var arr2 = arr.filter(function(x, index) {
return index % 3 === 0 || x >= 8;
}); 
console.log(arr2);         //[1, 4, 7, 8, 9, 10]

*13*|***0***every()

every():判断数组中每一项都是否满足条件,只有所有项都满足条件,才会返回true。

书写格式:arr.every()

var arr = [1, 2, 3, 4, 5];
var arr2 = arr.every(function(x) {
return x < 10;
}); 
console.log(arr2);         //true
var arr3 = arr.every(function(x) {
return x < 3;
}); 
console.log(arr3);         // false

*14*|***0***some()

some():判断数组中是否存在满足条件的项,只要有一项满足条件,就会返回true。

书写格式:arr.some()

var arr = [1, 2, 3, 4, 5];
var arr2 = arr.some(function(x) {
return x < 3;
}); 
console.log(arr2);         //true
var arr3 = arr.some(function(x) {
return x < 1;
}); 
console.log(arr3);         // false

handleChooseImg

用按钮图片来增加一个可替换图片

图片上传

https://www.jianshu.com/p/84b727a4b58a

事件修饰符

在事件处理程序中调用 event.preventDefault()event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。

为了解决这个问题,Vue.js 为 v-on 提供了事件修饰符。之前提过,修饰符是由点开头的指令后缀来表示的。

  • .stop
  • .prevent
  • .capture
  • .self
  • .once
  • .passive




...
...

Vue事件总线(EventBus)使用详细介绍

https://zhuanlan.zhihu.com/p/72777951

PS:没用到的组件没加载到的时候要注意销毁事件 例子: this.Bus.$off(‘makeCover’, this.handleMakeCover);

各种插槽

后备内容 (子组件 设置默认值)

所谓的后背内容,其实就是slot的默认值,有时我没有在父组件内添加内容,那么 slot就会显示默认值,如:

//子组件 : (假设名为:ebutton)
<template>
  <div class= 'button'>
      <button>  </button>
      <slot> 这就是默认值 </slot>
  </div>
</template>

具名插槽 (子组件 多个 对应插入内容)

有时候,也许子组件内的slot不止一个,那么我们如何在父组件中,精确的在想要的位置,插入对应的内容呢? 给插槽命一个名即可,即添加name属性。

//子组件 : (假设名为:ebutton)
<template>
  <div class= 'button'>
      <button>  </button>
      <slot name= 'one'> 这就是默认值1</slot>
      <slot name='two'> 这就是默认值2 </slot>
      <slot name='three'> 这就是默认值3 </slot>
  </div>
</template>

父组件通过v-slot : name 的方式添加内容:

//父组件:(引用子组件 ebutton)
<template>
  <div class= 'app'>
     <ebutton> 
        <template v-slot:one> 这是插入到one插槽的内容 </template>
        <template v-slot:two> 这是插入到two插槽的内容 </template>
        <template v-slot:three> 这是插入到three插槽的内容 </template>
     </ebutton>
  </div>
</template>

当然 vue 为了方便,书写 v-slot:one 的形式时,可以简写为 #one

作用域插槽 ( 父组件 在子组件 处使用子组件 data)

通过slot 我们可以在父组件为子组件添加内容,通过给slot命名的方式,我们可以添加不止一个位置的内容。但是我们添加的数据都是父组件内的。上面我们说过不能直接使用子组件内的数据,但是我们是否有其他的方法,让我们能够使用子组件的数据呢? 其实我们也可以使用v-slot的方式:

//子组件 : (假设名为:ebutton)
<template>
  <div class= 'button'>
      <button>  </button>
      <slot name= 'one' :value1='child1'> 这就是默认值1</slot>    //绑定child1的数据
      <slot :value2='child2'> 这就是默认值2 </slot>  //绑定child2的数据,这里我没有命名slot
  </div>           
</template>

new Vue({
  el:'.button',
  data:{
    child1:'数据1',
    child2:'数据2'
  }
})

//父组件:(引用子组件 ebutton)
<template>
  <div class= 'app'>
     <ebutton> 
        <template v-slot:one = 'slotone'>  
           {{ slotone.value1 }}    // 通过v-slot的语法 将子组件的value1值赋值给slotone 
        </template>
        <template v-slot:default = 'slottwo'> 
           {{ slottwo.value2 }}  // 同上,由于子组件没有给slot命名,默认值就为default
        </template>
     </ebutton>
  </div>
</template>

事件循环机制

前端学习笔记_第3张图片

前端学习笔记_第4张图片

​ 任务队列 事件循环

  • 宏任务:setTimeout setInterval

js主代码 setImmediate(Node) requestAnimationFrame(浏览器)

  • 微任务: process.nextTick Promise的then方法

Process.nextTick放队列前 setImmediate 放队列后

此时需要注意,只有前一个队列完全清空后,才会执行下一个队列

SASS文档

http://www.ruanyifeng.com/blog/2012/06/sass.html

Vue的Mixin的使用

前端学习笔记_第5张图片

    import Child from './Child'
    import { toggle } from './mixins/toggle'

    export default {
      name: 'modal',
      mixins: [toggle],
      components: {
        appChild: Child
      }
    }
      //mixin
      const hi = {
        methods: {
          sayHello: function() {
            console.log('hello from mixin!')
          }
        },
        mounted() {
          this.sayHello()
        }
      }

      //vue instance or component
      new Vue({
        el: '#app',
        mixins: [hi],
        methods: {
          sayHello: function() {
            console.log('hello from Vue instance!')
          }
        },
        mounted() {
          this.sayHello()
        }
      })

      // Output in console
      > hello from Vue instance!
      > hello from Vue instance!

for in 和 for of 的区别

var obj = {a:1, b:2, c:3};

for (var prop in obj) {
  console.log("obj." + prop + " = " + obj[prop]);
}

// Output:
// "obj.a = 1"
// "obj.b = 2"
// "obj.c = 3"

不难看出,for in循环遍历的是数组的键值(索引),而for of循环遍历的是数组的值。

for of不能遍历对象,除非使用迭代器或者使用Object.key处理这个对象

[vue里面touch事件的应用]

1.首先使用touch事件第一步肯定是要绑定touch事件

在html元素里绑定@touchstart=“….自己起名字…”
             @touchmove=“….自起名字….”
            @touchend=“…自己起名字…..”

touchstart会在你第一次触碰到它时候触发
touchmove就是你一直点着不松手的时候触发
touchend就是你的手刚刚移开的时候触发
这几个touch事件可以根据自己的需求进行绑定,绑定自己起的名字
然后在methods里面写自己绑定的名字的事件你要让他如何处理
而touch事件里面更包含了下面几个跟踪触摸的属性方便我们为了对应的效果进行使用

touches:表示当前跟踪的触摸操作的touch对象的数组。

targetTouches:特定于事件目标的Touch对象的数组。

changeTouches:表示自上次触摸以来发生了什么改变的Touch对象的数组。

每个Touch对象包含的属性如下。

 clientX:触摸目标在视口中的x坐标。

  clientY:触摸目标在视口中的y坐标。

  identifier:标识触摸的唯一ID。

  pageX:触摸目标在页面中的x坐标。

  pageY:触摸目标在页面中的y坐标。

  screenX:触摸目标在屏幕中的x坐标。

  screenY:触摸目标在屏幕中的y坐标。

  target:触目的DOM节点目标。

Mounted 和 nextTick

注意 mounted 不会承诺所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以用 vm.$nextTick 替换掉 mounted

mounted: function () {
  this.$nextTick(function () {
    // Code that will run only after the
    // entire view has been rendered
  })
}

值更新了但DOM里面的节点的值还没更新完,如果你获取更新完后的DOM值的话要用nextTick

this.$set

Vue2.0对于响应式数据的实现有一些不足:

  • 无法检测数组/对象的新增
  • 当你利用索引直接设置一个项时,例如: vm.items[indexOfItem] = newValue
    当你修改数组的长度时,例如: vm.items.length = newLength
  • 都无法检测到
  • Vue3.0 利用proxy可深度监听

性能问题,性能的代价和用户体验收益不成正比

当你在使用一个引用值的时候,当你改变原来的值,还要实时响应引用中的data的话,如果你不用$set是不能实现实时响应的,可以用

that.$set(that.list,that.INDEX,res.msg[i]);

Scroll事件的性能优化

https://zhuanlan.zhihu.com/p/30078937

touch和鼠标mouse的坐标获取方式是不一样的

if(e.xundefined || e.yundefined)

{

this.pointStart = {

​ x: e.changedTouches[0].pageX,

​ y: e.changedTouches[0].pageY,

};

setTimeout里的for循环

我们先来简单了解一下setTimeout延时器的运行机制。setTimeout会先将回调函数放到等待队列中,等待区域内其他主程序执行完毕后,按时间顺序先进先出执行回调函数。本质上是作用域的问题。

因此若是这样将不会得到想要的结果输出1.2.3.4.5,而会连续输出5个6。

for (var i=1; i<=5; i++) {
    setTimeout( function timer() {
        console.log( i );
     }, i*1000 );
}

解决方案1:闭包

使用闭包是很经典的一种做法:

for (var i=1; i<=5; i++) {
    (function(j) {
        setTimeout( function timer() {
            console.log( j );
        }, j*1000 );
    })(i);
}

解决方案3:let

这里再来说一说使用es6的let来解决此问题:

for (let i=1; i<=5; i++) {
    setTimeout( function timer() {
        console.log( i );
     }, i*1000 );
}

这个例子与第一个相比,只是把var更改成了let,可是控制台的结果却是依次输出1到5。

因为for循环头部的let不仅将i绑定到for循环中,事实上它将其重新绑定到循环体的每一次迭代中,确保上一次迭代结束的值重新被赋值。setTimeout里面的function()属于一个新的域,通过var定义的变量是无法传入到这个函数执行域中的,通过使用let来声明块变量能作用于这个块,所以function就能使用i这个变量了;这个匿名函数的参数作用域和for参数的作用域不一样,是利用了这一点来完成的。这个匿名函数的作用域有点类似类的属性,是可以被内层方法使用的。

uni.getSystemInfoSync()

获取系统信息同步接口。

同步返回参数说明

参数 说明 平台差异说明
brand 设备品牌 App、微信小程序、百度小程序、字节跳动小程序、飞书小程序、QQ小程序
model 设备型号 全平台支持。H5(3.1.10+)新增PC
pixelRatio 设备像素比
screenWidth 屏幕宽度
screenHeight 屏幕高度
windowWidth 可使用窗口宽度
windowHeight 可使用窗口高度
windowTop 可使用窗口的顶部位置 App、H5
windowBottom 可使用窗口的底部位置 App、H5
statusBarHeight 状态栏的高度 字节跳动小程序不支持
navigationBarHeight 导航栏的高度 百度小程序
titleBarHeight 标题栏高度 支付宝小程序
language 应用设置的语言 字节跳动小程序不支持
version 引擎版本号 H5不支持
storage 设备磁盘容量 支付宝小程序
currentBattery 当前电量百分比 支付宝小程序
appName 宿主APP名称 字节跳动小程序、飞书小程序
AppPlatform App平台 QQ小程序
host 宿主平台 百度小程序
app 当前运行的客户端 支付宝小程序
cacheLocation 上一次缓存的位置信息 百度小程序
system 操作系统版本
platform 客户端平台,值域为:iosandroidmac(3.1.10+)windows(3.1.10+)linux(3.1.10+)
fontSizeSetting 用户字体大小设置。以“我-设置-通用-字体大小”中的设置为准,单位:px 微信小程序、支付宝小程序、百度小程序、QQ小程序
SDKVersion 客户端基础库版本 支付宝小程序和H5不支持
swanNativeVersion 宿主平台版本号 百度小程序
albumAuthorized 允许微信使用相册的开关(仅 iOS 有效) 微信小程序
cameraAuthorized 允许微信使用摄像头的开关 微信小程序
locationAuthorized 允许微信使用定位的开关 微信小程序
microphoneAuthorized 允许微信使用麦克风的开关 微信小程序
notificationAuthorized 允许微信通知的开关 微信小程序
notificationAlertAuthorized 允许微信通知带有提醒的开关(仅 iOS 有效) 微信小程序
notificationBadgeAuthorized 允许微信通知带有标记的开关(仅 iOS 有效) 微信小程序
notificationSoundAuthorized 允许微信通知带有声音的开关(仅 iOS 有效) 微信小程序
bluetoothEnabled 蓝牙的系统开关 微信小程序
locationEnabled 地理位置的系统开关 微信小程序
wifiEnabled Wi-Fi 的系统开关 微信小程序
safeArea 在竖屏正方向下的安全区域 App、H5、微信小程序
safeAreaInsets 在竖屏正方向下的安全区域插入位置(2.5.3+) App、H5、微信小程序
deviceId 设备 id 非 App 端由 uni-app 框架生成并存储,清空 Storage 会导致改变

Tips

  • 使用注意同上getSystemInfo

safeArea 的结构

参数 类型 说明
left Number 安全区域左上角横坐标
right Number 安全区域右下角横坐标
top Number 安全区域左上角纵坐标
bottom Number 安全区域右下角纵坐标
width Number 安全区域的宽度,单位逻辑像素
height Number 安全区域的高度,单位逻辑像素

safeAreaInsets 的结构

参数 类型 说明
left Number 安全区域左侧插入位置
right Number 安全区域右侧插入位置
top Number 安全区顶部插入位置
bottom Number 安全区域底部插入位置

Vue实例属性

Vue 实例属性 描述 H5 App端 微信小程序 说明
vm.$data Vue 实例观察的数据对象 详情
vm.$props 当前组件接收到的 props 对象 详情
vm.$el Vue 实例使用的根 DOM 元素 详情 x x
vm.$options 用于当前 Vue 实例的初始化选项 详情
vm.$parent 父实例,如果当前实例有的话 详情 H5端 viewtext 等内置标签是以 Vue 组件方式实现,$parent 会获取这些到内置组件,导致的问题是 this.$parent 与其他平台不一致,解决方式是使用 this.$parent.$parent 获取或自定义组件根节点由 view 改为 div
vm.$root 当前组件树的根 Vue 实例 详情
vm.$children 当前实例的直接子组件 详情 H5端 viewtext 等内置标签是以 Vue 组件方式实现,$children 会获取到这些内置组件,导致的问题是 this.$children 与其他平台不一致,解决方式是使用 this.$children.$children 获取或自定义组件根节点由 view 改为 div
vm.$slots 用来访问被插槽分发的内容 详情 x
vm.$scopedSlots 用来访问作用域插槽 详情
vm.$refs 一个对象,持有注册过 ref attribute 的所有 DOM 元素和组件实例详情 非H5端只能用于获取自定义组件,不能用于获取内置组件实例(如:view、text)
vm.$isServer 当前 Vue 实例是否运行于服务器 详情 x App端总是返回false
vm.$attrs 包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 详情 x 把父组件的所有data通过$attrs传到子组件中
vm.$listeners 包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器 详情 x -

Vue实例方法

实例方法 描述 H5 App端 微信小程序 说明
vm.$watch() 观察 Vue 实例上的一个表达式或者一个函数计算结果的变化 详情
vm.$set() 这是全局 Vue.set 的别名 详情
vm.$delete() 这是全局 Vue.delete 的别名 详情
vm.$on() 监听当前实例上的自定义事件 详情
vm.$once() 监听一个自定义事件,但是只触发一次 详情
vm.$off() 移除自定义事件监听器 详情
vm.$emit() 触发当前实例上的事件 详情
vm.$mount() 手动地挂载一个未挂载的实例 详情 x x
vm.$forceUpdate() 迫使 Vue 实例重新渲染 详情
vm.$nextTick() 将回调延迟到下次 DOM 更新循环之后执行 详情
vm.$destroy() 完全销毁一个实例 详情 -

Vue模板指令

Vue 指令 描述 H5 App端 微信小程序 说明
v-text 更新元素的 textContent 详情
v-html 更新元素的 innerHTML 详情 x 微信小程序会被转成 rich-text
v-show 根据表达式之真假值,切换元素的 display CSS属性 详情
v-if 根据表达式的值的 truthiness 来有条件地渲染元素 详情
v-else 为 v-if 或者 v-else-if 添加“else 块” 详情
v-else-if 表示 v-if 的“else if 块”。可以链式调用 详情
v-for 基于源数据多次渲染元素或模板块 详情
v-on 绑定事件监听器 详情
v-bind 动态地绑定一个或多个 attribute,或一个组件 prop 到表达式 详情
v-model 在表单控件或者组件上创建双向绑定 详情
v-pre 跳过这个元素和它的子元素的编译过程 详情 x
v-cloak 这个指令保持在元素上直到关联实例结束编译 详情 x x
v-once 只渲染元素和组件一次 详情 x -

Vue特殊属性

特殊属性 描述 H5 App端 微信小程序 说明
key 主要用在 Vue 的虚拟 DOM 算法,在新旧 nodes 对比时辨识 VNodes 详情
ref ref 被用来给元素或子组件注册引用信息 详情 非 H5 平台只能获取 vue 组件实例不能获取到内置组件实例
is 用于动态组件且基于 DOM 内模板的限制来工作 详情 x -

Vue内置组件

内置组件 描述 H5 App端 微信小程序 说明
component 渲染一个“元组件”为动态组件。依 is 的值,来决定哪个组件被渲染 详情 x
transition 作为单个元素/组件的过渡效果 详情 x x
transition-group 作为多个元素/组件的过渡效果 详情 x x
keep-alive 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们 详情 x x
slot 作为组件模板之中的内容分发插槽 详情 -
template 并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性 详情 -

Uniapp页面生命周期

onInit 监听页面初始化,其参数同 onLoad 参数,为上个页面传递的数据,参数类型为 Object(用于页面传参),触发时机早于 onLoad 百度小程序 3.1.0+
onLoad 监听页面加载,其参数为上个页面传递的数据,参数类型为 Object(用于页面传参),参考示例
onShow 监听页面显示。页面每次出现在屏幕上都触发,包括从下级页面点返回露出当前页面
onReady 监听页面初次渲染完成。注意如果渲染速度快,会在页面进入动画完成前触发
onHide 监听页面隐藏
onUnload 监听页面卸载
onResize 监听窗口尺寸变化 App、微信小程序

webpack包大小分析

https://www.jianshu.com/p/0c05faee0975

[PurgeCSS 中文文档]压缩CSS

ToKen过期问题

async和await和Promise

promise有三种状态:pending/reslove/reject 。pending就是未决,resolve可以理解为成功,reject可以理解为拒绝。

async return出去的是一个Promise对象

await 等待的也必须是一个Promise对象

let n = await

let n = async function test(){

return 1

}

相当于

return new Promise((resolve)=>{

resolve(‘1’)

})

async function test(){
							await this.preManhua();
							this.cardRightIn=false;
							this.cardLeftIn=true;
						}
						test();

let promiseDemo = new Promise((resolve, reject) => {
  // code
  resolve('success')
  // code 
  reject('failed') 
})

promiseDemo.then((result) => {
  console.log(result)
}, (result) => {
  console.log(result)
})

关于储存

cookie#

Cookie 是一些数据,由服务器生成,发送给浏览器,一旦用户从该网站或服务器退出,Cookie 就存储在用户本地的硬盘上,下一次请求同一网站时会把该cookie发送给服务器。Cookie的作用就是用于解决“如何记录客户端的用户信息”。

可以使用 document.cookie 属性来创建 、读取、及删除 cookie。

  • 创建 cookie :

    document.cookie="username=Irelia;

  • 为 cookie 添加一个过期时间(以 UTC 或 GMT 时间)。默认情况下,cookie 在浏览器关闭时删除:

    document.cookie=“username=Irelia; expires=Thu, 19 Dec 2025 12:00:00 GMT”;

  • path 参数告诉浏览器 cookie 的路径。默认情况下,cookie 属于当前页面。

    document.cookie=“username=Irelia; expires=Thu, 19 Dec 2025 12:00:00 GMT; path=/”;

Cookie的缺陷

  • cookie会被附加在每个HTTP请求中,所以无形中增加了流量。
  • 由于在HTTP请求中的cookie是明文传递的,所以安全性成问题。(除非用HTTPS)
  • Cookie的大小不能超过4kb。对于复杂的存储需求来说是不够用的。

MDN链接:https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/cookies

sessionStorage#

这个数据本质是存储在当前页面的内存中,为页面会话期间可用的每个给定源维护一个单独的存储区域(只要浏览器处于打开状态,包括页面重新加载和恢复)

  • 仅为会话存储数据,这意味着在关闭浏览器(或选项卡)之前存储数据。
  • 数据永远不会传输到服务器。
  • 存储限制大于cookie(最多5MB)。

方法:

  • setItem(key ,value):存储数据,以键值对的方式存储
  • getItem(key):获取数据,通过指定名称的key获取对应的value值
  • removeItem(key):删除数据,通过指定名称key删除对应的值
  • clear() :清空存储的内容

loclaStorage#

1.存储的内容一般为5MB

2.不同浏览器不能共享数据。但是在同一个浏览器的不同窗口中可以共享数据

3.永久生效,他的数据是存储在硬盘上,并不会随着页面或者浏览器的关闭而清除,如果想清除,必须手 动清除

方法:

  • setItem(key ,value):存储数据,以键值对的方式存储
  • getItem(key):获取数据,通过指定名称的key获取对应的value值
  • removeItem(key):删除数据,通过指定名称key删除对应的值
  • clear() :清空所有存储的内容

Cookie
cookie 是一个非常具体的东西,指的就是浏览器里面能永久存储的一种数据,仅仅是浏览器实现的一种数据存储功能。

cookie由服务器生成,发送给浏览器,浏览器把cookie以kv形式保存到某个目录下的文本文件内,下一次请求同一网站时会把该cookie发送给服务器。由于cookie是存在客户端上的,所以浏览器加入了一些限制确保cookie不会被恶意使用,同时不会占据太多磁盘空间,所以每个域的cookie数量是有限的。

Session
session 从字面上讲,就是会话。这个就类似于你和一个人交谈,你怎么知道当前和你交谈的是张三而不是李四呢?对方肯定有某种特征(长相等)表明他就是张三。

session 也是类似的道理,服务器要知道当前发请求给自己的是谁。为了做这种区分,服务器就要给每个客户端分配不同的“身份标识”,然后客户端每次向服务器发请求的时候,都带上这个“身份标识”,服务器就知道这个请求来自于谁了。至于客户端怎么保存这个“身份标识”,可以有很多种方式,对于浏览器客户端,大家都默认采用 cookie 的方式。

服务器使用session把用户的信息临时保存在了服务器上,用户离开网站后session会被销毁。这种用户信息存储方式相对cookie来说更安全,可是session有一个缺陷:如果web服务器做了负载均衡,那么下一个操作请求到了另一台服务器的时候session会丢失。

关于安全

XSS(跨站脚本攻击)是指攻击者在返回的HTML中嵌入javascript脚本,为了减轻这些攻击,需要在HTTP头部配上,set-cookie:

httponly-这个属性可以防止XSS,它会禁止javascript脚本来访问cookie。

secure - 这个属性告诉浏览器仅在请求为https的时候发送cookie

关于变量提升和函数提升

1.变量提升只会提升变量名的声明,而不会提升变量的赋值初始化。

2.函数提升的优先级大于变量提升的优先级,即函数提升在变量提升之上。

记住这两句话,就可以从容不迫的撸代码了!

console.log(a); ``var` `a=1;``console.log(a);  ``function` `a(){console.log(2);}``console.log(a);  ``var` `a=3;``console.log(a);  ``function` `a(){console.log(3);}``a();``console.log(a);

你知道执行结果吗?
运行结果

其实,实际的执行顺序为:

function` `a(){alert(3);} `
`//第一步预解析:将 var a提升   但因为变量名与函数名相同,故function a()提升时将覆盖var a,又因为存在两个相同名称              的function函数,后写的将覆盖先写的,所以最后提升的只有function a(){alert(3);}` `console.log(a);   ``//因为函数提升,所以打印的a为函数整体``a=1;    ``//将1赋值给函数a,此时的a为一个变量,不再是函数``console.log(a);   ``//故打印的为a赋的值``console.log(a);``a=3;    ``//将a重新赋值3``console.log(a);   ``//故打印结果为3``a();    ``//此时的a为一个变量,不再是一个函数,所以报错,js中一旦出现报错,后面的语句将不再运行,所以最后一个console.log不进行打印。``console.log(a);

结束!搞清楚这题,变量提升与函数提升你就搞懂啦!

清除浮动的方法(最常用的4种)

1.额外标签法(在最后一个浮动标签后,新加一个标签,给其设置clear:both;)(不推荐)

优点:通俗易懂,方便

缺点:添加无意义标签,语义化差

2.父级添加overflow属性(父元素添加overflow:hidden)(不推荐)

优点:代码简洁

缺点:内容增多的时候容易造成不会自动换行导致内容被隐藏掉,无法显示要溢出的元素

3.使用after伪元素添加clear both清除浮动(推荐使用)

优点:符合闭合浮动思想,结构语义化正确

缺点:ie6-7不支持伪元素:after,使用zoom:1触发hasLayout.

4.使用before和after双伪元素清除浮动

优点:代码更简洁

缺点:用zoom:1触发hasLayout.

快速排序

选择一个中心轴取出,设定两个下标 left 和right

如果left或者right的随便一个值 比如说 rifht 如果比中心轴大则不换下标 right往左移动 继续检测 如果比中心轴小则换到left位置 left向右移动 类似做法 到重合的时

候空的就把中心轴放进去 左右序列循环操作

########### 每个指令必须有分号结束。#################
#user administrator administrators; #配置用户或者组,默认为nobody nobody。
#worker_processes 2; #允许生成的进程数,默认为1
#pid /nginx/pid/nginx.pid; #指定nginx进程运行文件存放地址
error_log log/error.log debug; #制定日志路径,级别。这个设置可以放入全局块,http块,server块,级别以此为:debug|info|notice|warn|error|crit|alert|emerg
events {
accept_mutex on; #设置网路连接序列化,防止惊群现象发生,默认为on
multi_accept on; #设置一个进程是否同时接受多个网络连接,默认为off
#use epoll; #事件驱动模型,select|poll|kqueue|epoll|resig|/dev/poll|eventport
worker_connections 1024; #最大连接数,默认为512
}
http {
include mime.types; #文件扩展名与文件类型映射表
default_type application/octet-stream; #默认文件类型,默认为text/plain
#access_log off; #取消服务日志
log_format myFormat ‘ r e m o t e a d d r – remote_addr– remoteaddrremote_user [$time_local] $request $status $body_bytes_sent $http_referer $http_user_agent $http_x_forwarded_for’; #自定义格式
access_log log/access.log myFormat; #combined为日志格式的默认值
sendfile on; #允许sendfile方式传输文件,默认为off,可以在http块,server块,location块。
sendfile_max_chunk 100k; #每个进程每次调用传输数量不能大于设定的值,默认为0,即不设上限。
keepalive_timeout 65; #连接超时时间,默认为75s,可以在http,server,location块。

upstream mysvr {   
  server 127.0.0.1:7878;
  server 192.168.10.121:3333 backup;  #热备
}
error_page 404 https://www.baidu.com; #错误页
server {
    keepalive_requests 120; #单连接请求上限次数。
    listen       4545;   #监听端口
    server_name  127.0.0.1;   #监听地址       
    location  ~*^.+$ {       #请求的url过滤,正则匹配,~为区分大小写,~*为不区分大小写。
       #root path;  #根目录
       #index vv.txt;  #设置默认页
       proxy_pass  http://mysvr;  #请求转向mysvr 定义的服务器列表
       deny 127.0.0.1;  #拒绝的ip
       allow 172.18.5.54; #允许的ip           
    } 
}

简单的字符串过滤

value=value.replace(/
/
,'')

二叉树的创建和遍历

//构造函数
function TreeCode() {
    //构造函数
    let BiTree = function (ele) {
        this.data = ele;
        this.lChild = null;
        this.rChild = null;
    }
	//方法
    this.createTree = function () {
        let biTree = new BiTree('A');
        biTree.lChild = new BiTree('B');
        biTree.rChild = new BiTree('C');
        biTree.lChild.lChild = new BiTree('D');
        biTree.lChild.lChild.lChild = new BiTree('G');
        biTree.lChild.lChild.rChild = new BiTree('H');
        biTree.rChild.lChild = new BiTree('E');
        biTree.rChild.rChild = new BiTree('F');
        biTree.rChild.lChild.rChild = new BiTree('I');
        return biTree;
    }
}

//前序遍历
function ProOrderTraverse(biTree) {
    if (biTree == null) return;
    console.log(biTree.data);
    ProOrderTraverse(biTree.lChild);
    ProOrderTraverse(biTree.rChild);
}

//中序遍历
function InOrderTraverse(biTree) {
    if (biTree == null) return;
    InOrderTraverse(biTree.lChild);
    console.log(biTree.data);
    InOrderTraverse(biTree.rChild);
}

//后续遍历
function PostOrderTraverse(biTree) {
    if (biTree == null) return;
    PostOrderTraverse(biTree.lChild);
    PostOrderTraverse(biTree.rChild);
    console.log(biTree.data);
}

let myTree = new TreeCode();
console.log(myTree.createTree());
console.log('前序遍历')
ProOrderTraverse(myTree.createTree());
console.log('中序遍历')
InOrderTraverse(myTree.createTree());
console.log('后续遍历')
PostOrderTraverse(myTree.createTree());

不用类创建对象

function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.sayHi = function() {
  console.log("你好,我叫" + this.name);
};

let person = new Person("frank", 18);
let person2 = new Person("jack", 19);

跨域与Http的Access-Control-Allow-Origin关系

http://code-ken.github.io/2016/07/13/jsonp-json-ajax/

利用Porxy跨域

核心配置
1、你要 http://e.dxy.net/api/test 你可以在本地调 localhost:8080/api/test,如axios.get('/api/test')

localhost:8080/api/test -> http://e.dxy.net/api/test
localhost:8080/bcma/api/test -> http://e.dxy.net/bcma/api/test

//vue-cli3.0 里面的 vue.config.js做配置
devServer: {
  proxy: {
      '/api': {
          target: 'http://e.dxy.net',  // 后台接口域名
          ws: true,        //如果要代理 websockets,配置这个参数
          secure: false,  // 如果是https接口,需要配置这个参数
          changeOrigin: true,  //是否跨域
      }
  }
}

2、当你调接口后端的命名没有统一给接口前加 /api 这类的标识,那么你可以自己加,也就是你可以在本地调 localhost:8080/api/test,如axios.get('/api/test'),而你要的目标接口是 http://e.dxy.net/test,你就可以用 pathRewrite,遇到 /api 就去找代理 http://e.dxy.net 并且把 /api 重写为 /

localhost:8080/api/test -> http://e.dxy.net/test

//vue-cli3.0 里面的 vue.config.js做配置
devServer: {
  proxy: {
      '/api': {
          target: 'http://e.dxy.net',  // 后台接口域名
          ws: true,        //如果要代理 websockets,配置这个参数
          secure: false,  // 如果是https接口,需要配置这个参数
          changeOrigin: true,  //是否跨域
          pathRewrite:{
              '^/api': '/'
          }
      }
  }
}

Vu3 语法

https://zhuanlan.zhihu.com/p/139590941

栈内存和堆内存

前端学习笔记_第6张图片

垂直居中的5种方法

vertical-align

优点:

  • content 可以动态改变高度(不需在 CSS 中定义)。当 wrapper 里没有足够空间时, content 不会被截断

缺点:

  • Internet Explorer(甚至 IE8 beta)中无效,许多嵌套标签(其实没那么糟糕,另一个专题)

这个方法使用绝对定位的 div,把它的 top 设置为 50%,

优点:

  • 适用于所有浏览器
  • 不需要嵌套标签

缺点:

  • 没有足够空间时,content 会消失(类似div 在 body 内,当用户缩小浏览器窗口,滚动条不出现的情况)

只需要简单地把 line-height 设置为那个对象的 height 值

优点:

  • 适用于所有浏览器
  • 无足够空间时不会被截断

缺点:

  • 只对文本有效(块级元素无效)
  • 多行时,断词比较糟糕

JS延迟加载的几种方式

  1. defer 属性
    HTML 4.01 为

DOCTYPE html>
<html>
<head>
    <script src="test1.js" defer="defer">script>
    <script src="test2.js" defer="defer">script>
head>
<body>

body>
html>  
说明:虽然<script> 元素放在了<head>元素中,但包含的脚本将延迟浏览器遇到html>标签后再执行。

HTML5规范要求脚本按照它们出现的先后顺序执行。在现实当中,延迟脚本并不一定会按照顺序执行。

defer属性只适用于外部脚本文件。支持 HTML5 的实现会忽略嵌入脚本设置的 defer属性。

  1. async 属性
    HTML5 为

异步脚本一定会在页面 load 事件前执行。
不能保证脚本会按顺序执行。

<html>
<head>
    <script src="test1.js" async>script>
    <script src="test2.js" async>script>
head>

<body>

body>
html>  

async和defer一样,都不会阻塞其他资源下载,所以不会影响页面的加载。
缺点:不能控制加载的顺序

3.动态创建DOM方式
//这些代码应被放置在标签前(接近HTML文件底部)


<script type="text/javascript">  
   function downloadJSAtOnload() {  
       varelement = document.createElement("script");  
       element.src = "defer.js";  
       document.body.appendChild(element);  
   }  
   if (window.addEventListener)  
      window.addEventListener("load",downloadJSAtOnload, false);  
   else if (window.attachEvent)  
      window.attachEvent("onload",downloadJSAtOnload);  
   else 
      window.onload =downloadJSAtOnload;  
</script>  

4.使用jQuery的getScript()方法

$.getScript("outer.js",function(){//回调函数,成功获取文件后执行的函数  
      console.log("脚本加载完成")  
});

5.使用setTimeout延迟方法
6.让JS最后加载

Class对象选择写法

:class="{

   'dp-object-wrapper-selected': currentLayer && item.id === currentLayer.id && !(this.editor.isPoster),

   'dp-object-wrapper-editing': editor.editTextId === item.id,

  }"

truthy和falsy

JavaScript 在需要用到布尔类型值的上下文中使用强制类型转换(Type Conversion )将值转换为布尔值,比如:在条件语句或者循环语句中

一,truthy

在javascript中,Truthy (真值)指的是在Boolean上下文中转换后的值为真的值。所有值都是真值,除非它们被定义为falsy(即除了 false0""nullundefinedNaN 外)。

JavaScript中truthy值的例子 (通过 if 代码段将truthy值转换为true)

if (true)
if ({})
if ([])
if (42)
if ("foo")
if (new Date())
if (-42)
if (3.14)
if (-3.14)
if (Infinity)
if (-Infinity)

二,falsy

falsy(虚值)是在 Boolean上下文中已认定可转换为‘假‘的值.

JavaScript中falsy值的例子 (通过 if 代码段将falsy值转换为false):

1 if (false)
2 if (null)
3 if (undefined)
4 if (0)
5 if (NaN)
6 if ('')
7 if ("")
8 if (document.all)

性能优化相关

异步组件

路由懒加载

图片懒加载

图片采用CDN分发

回流之后的重排重绘

减少DOM操作

减少请求次数

HTTP缓存

Keep-alive

Input没反应-事件冒泡

可能是父级元素绑定着click事件,当点击上传时冒泡到父级元素,导致无反应。解决办法:
在 input file 外包一层元素,在该元素上阻止事件冒泡

也就是说事件往上冒泡触发了父元素覆盖了子元素的click

FileReader

FileReader的使用方式非常简单,可以按照如下步骤创建FileReader对象并调用其方法:

1.检测浏览器对FileReader的支持

if(window.FileReader) {
var fr = new FileReader();
// add your code here
}
else {
alert(“Not supported by your browser!”);
}

  1. 调用FileReader对象的方法

FileReader 的实例拥有 4 个方法,其中 3 个用以读取文件,另一个用来中断读取。下面的表格列出了这些方法以及他们的参数和功能,需要注意的是 ,无论读取成功或失败,方法并不会返回读取结果,这一结果存储在 result属性中。

方法名 参数 描述
abort none 中断读取
readAsBinaryString file 将文件读取为二进制码
readAsDataURL file 将文件读取为 DataURL
readAsText file, [encoding] 将文件读取为文本
readAsText:该方法有两个参数,其中第二个参数是文本的编码方式,默认值为 UTF-8。这个方法非常容易理解,将文件以文本方式读取,读取的结果即是这个文本文件中的内容。
readAsBinaryString:该方法将文件读取为二进制字符串,通常我们将它传送到后端,后端可以通过这段字符串存储文件。
readAsDataURL:这是例子程序中用到的方法,该方法将文件读取为一段以 data: 开头的字符串,这段字符串的实质就是 Data URL,Data URL是一种将小文件直接嵌入文档的方案。这里的小文件通常是指图像与 html 等格式的文件。

  1. 处理事件

FileReader 包含了一套完整的事件模型,用于捕获读取文件时的状态,下面这个表格归纳了这些事件。

事件 描述
onabort 中断时触发
onerror 出错时触发
onload 文件读取成功完成时触发
onloadend 读取完成触发,无论成功或失败
onloadstart 读取开始时触发
onprogress 读取中

代码复现

      const isJPG = file.type === "image/jpeg";
      const isLt2M = file.size / 1024 / 1024 < 2;

      if (!isLt2M) {
        this.$message.error("上传头像图片大小不能超过 2MB!");
      }

      let reader = new FileReader();
      reader.readAsDataURL(file); // 这里是最关键的一步,转换就在这里
      reader.onload = function () {
        this.realImg = reader.result;
      };
      

REM 相关 重要!!!!!!

https://blog.csdn.net/xinruliushui/article/details/79085485

Watch监听属性

我们可以是使用字符串形式监听。

watch: {
  'obj.a': {
    handler(newName, oldName) {
      console.log('obj.a changed');
    },
    immediate: true,
    // deep: true
  }
} 

这样Vue.js才会一层一层解析下去,直到遇到属性a,然后才给a设置监听函数。

深度作用选择器

如果你希望 scoped 样式中的一个选择器能够作用得“更深”,例如影响子组件,你可以使用 >>> 操作符:

// 上述代码将会编译成:
.a[data-v-f3f3eg9] .b { /* … */ }
有些像 Sass 之类的预处理器无法正确解析 >>>。这种情况下你可以使用 /deep/ 或 ::v-deep 操作符取而代之——两者都是 >>> 的别名,同样可以正常工作。

检测元素外部(或内部)的单击

有时我需要检测一个点击是发生在一个特定元素 el 的内部还是外部。这就是我通常使用的方法。

window.addEventListener('mousedown', e => {
  // 获取被点击的元素
  const clickedEl = e.target;
  
  if (el.contains(clickedEl)) {
   //在 "el "里面点击了
  } else {
   //在 "el "外点击了
  }
});

OSS图片跨域解决方案

排查CORS跨域规则是否设置正确,具体操作如下:

  1. 登录OSS管理控制台。

  2. 单击****Bucket列表****,单击目标Bucket,进入Bucket概览页面。

  3. 在左侧导航栏中选择权限管理>跨域设置,然后单击设置

  4. 单击规则右侧的

    编辑

    进行

    以下配置,配置规则及注意事项请参见

    更多信息

    • 来源设置成*,确认该配置项无误。如果设置成*后可以成功上传,说明是之前的来源配置错误,请根据规则认真检查。
    • 依次选择允许 Methods的全部选项,即GETPUTDELETEPOSTHEAD,确认该配置项目无误。
    • 允许 Headers配置成*,确认该配置无误。如果设置后可以正常调用,说明之前的允许 Headers配置错误,请根据规则认真检查。
    • 暴露 Headers设置为Etagx-oss-request-id,确认该项配置无误。如果设置后可以正常调用,说明之前的暴露 Headers配置错误,请根据规则认真检查。
  5. 如果问题还是无法解决,请参见设置跨域规则后调用OSS时仍然报“No ‘Access-Control-Allow-Origin’”的错误。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B6aOuqzA-1636443365383)(C:\Users\Lenovo\Desktop\image-20211109152003201.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hDHv71a0-1636443365384)(C:\Users\Lenovo\Desktop\image-20211109152025509.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kcrGwJUg-1636443365384)(C:\Users\Lenovo\Desktop\image-20211109152045103.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nQVRwTYH-1636443365385)(C:\Users\Lenovo\Desktop\image-20211109152101247.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9xl6MULV-1636443365385)(C:\Users\Lenovo\Desktop\image-20211109152129019.png)]

你可能感兴趣的:(Vue,笔记,前端,vue,uni-app,前端,javascript)