封装ajax
//要封装一个函数,保存重用的代码:
//1. 代码中所有不确定的,都定义为形参变量!
//2. 所有不一定执行的代码,都要加判断条件。
//三个参数:
//1. url: 要请求的目标服务端接口地址
//2. type: 不同的请求类型
//3. callback: 是调用者自定义的一个函数,会在调用时提前传入ajax函数内部,但是不是立刻执行。而是等相应回来后,自动执行。——因为我把callback()写在了onreadystatechange中。
//4. data: 要发送的参数, 要求,必需是:
// "变量1=值1&变量2=值2&..."
// 不要带问号
// 且必需是字符串
//强调: 回调函数,总是需要的,因为相应结果都要处理!
// 但是就不是所有请求都带参数!
// data有时候需要有,有时候没有。
// 将来,凡是有可能有,有可能没有的形参,都必须放在形参列表的结尾。
// 因为函数调用时,中间是不能缺参数的!
// 比如: ajax(url, type, callback )//没有第四个data参数值。如果没有第四个参数值,则ajax内的data变量获得的就是undefined
// ajax(url, type, , callback) //编译错误
function ajax({url,type="get",data}){
// door err
return new Promise(function(resolve,reject){
var xhr=new XMLHttpRequest();//不变!
//如果发送get请求时,带参数
if(type=="get"&&data!==undefined){
//则需要将参数用?连接到url地址结尾
url+="?"+data;
}
xhr.open(type,url,true);
xhr.onreadystatechange=function(){
if(xhr.readyState==4){
var result=JSON.parse(xhr.responseText)
//door(result);
resolve(result);//开门,并将结果,反馈到外部!功能类似于普通函数的return
}
}
if(type=="post"){//只有发送的是post请求时,才需要添加请求头
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
}
if(type=="post"){//只有post请求,才会将参数放在send()中发送
xhr.send(data);
}else{//而如果是get请求,send()中什么都没有
xhr.send();
}
})
}
异步promise ajax 数据累加
问题:
如果在已经封装过ajax 的基础上,进行数据的累加,不进行promise 进行排序的话就会出现 首次值为0的情况发生,所以要用 promise 进行排序,但是如果每一次调用都需要 return 上一次的结果的时候就会造成层级太深,且耗费时间较长
解决:
promise.all(),将执行的异步操作放在all的回调函数内,就可以提高 效率,但是不可以直接累加,而是在最后一个异步函数后面加 .then() 在其内部用循环遍历才能将数据进行汇总,但是在es6中的写法 await 代替了then 更直观
var a=await Promise.all([多个回调方法])
函数内多个参数不确定时,有要求按顺序传入时
- 默认值
只能应对结尾一个参数不确定的时候 - 剩余参数 "…"
虽然可应对多个参数不确定的情况,但是无法规定传入参数的顺序 - 参数结构
向函数传参的时候,将一个大的对象,打散后,传递给形参变量
1,定义形参时,所有形参变量都要定义在一个对象结构中
2,调用函数传参时,所有实参值都要放在一个对象结构中整体传入
函数也是一个对象,可以通过函数返回值.新的属性函数
var sum=0;
function f2(){
sum++
return f2
}
f2.valueOf=function(){
return sum ;
}
f2.toString=function(){
return sum +''
}
console.log(+f2()); f2.valueOf() 0;
console.log(+f1()()); +f2() 1 -> f2.valueOf() 1
console.log(+f1()()()); +f1() sum++ 1, f2.valueOf() 1,f2() sum++ 2
引用类型都是对象
如:数组,函数,对象,null,newNumber(10)等都是引用类型的对象。如果只是简单声明一个函数,这个变量并不是只能给这个函数用而是可以直接用.对其属性和方法进行扩展。
例子如下:
var fn = function () {
alert(100);
};
fn.a = 10;
fn.b = function () {
alert(123);
};
fn.c = {
name: "王福朋",
year: 1988
};
this之指向
在函数中this到底取何值,是在函数真正被调用执行的时候确定的,函数定义的时候确定不了。因为this的取值是执行上下文环境的一部分,每次调用函数,都会产生一个新的执行上下文环境。
1,定义函数this默认指向这个函数本身,
2,构造函数,this转移到这个新的函数本身上 也就是 new 出来的那一个
3,函数作为一个对象的时候,对象之间的属性和方法用this 进行访问,
this指向被调用的那个对象
4,用api 强行绑定this 的时候 ,this 指向被绑定的对象,如 apply call
5,全局对象中,this 默认指向windows
6,给元素绑定事件的时候,this 指向 这个元素本身
等等。
作用域
- “javascript没有块级作用域”。所谓“块”,就是大括号“{}”中间的语句。
- 光知道“javascript没有块级作用域”是完全不够的,你需要知道的是——javascript除了全局作用域之外,只有函数可以创建的作用域
- 作用域最大的用处就是隔离变量,不同作用域下同名变量不会有冲突
- 作用域只是一个“地盘”,一个抽象的概念,其中没有变量。要通过作用域对应的执行上下文环境来获取变量的值
- 作用域中变量的值是在执行过程中产生的确定的,而作用域却是在函数创建时就确定了。
如果要查找一个作用域下某个变量的值,就需要找到这个作用域对应的执行上下文环境,再在其中寻找变量的值。
作用域链
如果某个正在执行的函数,在寻找某个变量的时候,先就近,再跨作用域去一层层的查找直到找到,这样的路线也就是作用链。
闭包
函数作为返回值,函数作为参数传递。使用闭包会增加内容开销,必要时进行销毁
1,函数作为返回值
()(
return function bar(){
console.log(1+1);
}
)
2,函数作为参数传递。
(function f(a){
console.log(a);
})(f(10));
此时 这个函数就作为了一个匿名函数的第一个参数,
而后者对它进行调用的时候进行了传参
匹配URL 地址的每一部分正则
[a-z]+://多个字母://--------协议
[A-Za-z0-9.]+ 主机名
:\d+ 主机名后的端口号
(/[a-z.]+) 多组(/*******)的组合的相对路径
\?([a-z]+=[a-z0-9]+&?)+? 变量名=变量值
#[a-z]+ #后跟的多个地址 锚点
使用 math进行匹配的时候可以将具体的 匹配项用一个()括起来,可以实现分格子存放
ES7异步函数自调(微信小程序)
(async function(){
try{
顺序放置异步函数
await a();
await b();
await c();
}cath(e){
throw e
}
})
引用类型,原始类型
原始类型。比如 var a=3;b=a; b++ ;console.log(a) 结果为 3,而不是4,b 为4,操作的值只不过是复制的一个值而已;
引用类型: var arr=[1,2,3,4]; var a=arr; a.pop()会直接将 arr中的数值进行了修改,a 赋值的是 arr的地址而不是 单独复制的一份值
vue 观察者模式
每一个需要获得data变量中数据的对象,自身带了一个类似于getData()的函数,但是如果让每个这样的对象都这样直接获取,就不叫观察者了,所以把他们存在一个类似于观察者的数组中,数组中存放的就是这些希望获得data 中变量的对象,而data 中负责修改这个变量的函数对象,除了有个类似于setdata 的函数外还有一个 类似通知all()函数,每当变量修改时,都会通知,遍历这个观察者数组,让里面的对象获得修改后的变量值
//手写观察者模式
var data={
money:1000,
setMoney(){
this.money=money
//变量被修改,通知遍历观察者对象的数组修改这个变量值
},
//保存需要获得这个变量的对象
observer:[],
all(){
this.observer.forEach((obj)=>{
obj.setMoney()//凡是进入观察者数组的对象都带有一个设置该变量函数
})
}
}
//假设有三个希望获得这个变量的对象
var obj1={
//变量值
money:0,
getMoney(){
console.log('obj1被通知修改')
this.money=data.money
}
}
var obj3={
//变量值
money:0,
getMoney(){
console.log('obj2被通知修改')
this.money=data.money
}
var obj2={
//变量值
money:0,
getMoney(){
console.log('obj3被通知修改')
this.money=data.money
}
vueX 多个组件之间共享状态,防止子传父父传子造成数据混乱
模块1->vuex—>模块2 好处:避免数组混乱 vuex 会自动绑定,就像使用data 中的变量一样
import Vue from "vue";
import Vuex from "vuex";
import axios from "axios";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
//变量值
uname: "",
},
mutations: {
//专门负责修改state 中的变量,函数等,但是不能放异步
//状态 传参
setUname(state, uname) {
state = uname;
},
},
actions: {
//专门负责发送ajax 异步请求,从服务器端获取数据
//假设有个登录函数
login(context) {
//context 代表的是整个vuex 的对象
//普通写法
axios.post("/login", "uname=dingding&upwd=12345678").then((res) => {
console.log(res);
});
// es7的写法
(async,
function() {
//等待排序
var result = await axios.post("/login", "uname=dingding&upwd=12345678");
// console.log(result);
//连接 设置 state 中的值
//函数名 传参
context.commit('setUname',result)
})();
},
},
/*
登录页面怎么调用 actions
// 引入
import {mapActions} from 'vuex'
// 辅助函数,存放在计算属性里面
import {mapstate} from 'vuex'
使用
methods(){
// 自己当前页面定义的登录的函数
myLogin(){
this.login(
{
// 传参给user
uname:this.uname,
upwd:this.upwd
}
)
}
...mapActions([
// 取出 该对象中 actions 中自己创建的login函数
'login'
])
},
computed(){
//计算属性
}
// 跟上面的同理
outLogin(){
this.outlogin("")
}
...mapActions([
// 取出 该对象中 actions 中自己创建的login函数
'outlogin'
])
*/
modules: {},
});
vue-router中的history模式
问题:客户端路由地址可能有服务器端路由地址重名,浏览器只要看不到带#的地址,都会发送给服务器端。
**解决:**vue-router 启动 history 模式可解决
脚手架 router.js或router/index.js 中
new vueRouter({
mode:"hostory",
routes
})
安装一个专门支持history 重定向的中间件
npm i connect-history-api-fallback
再引入应用
app.js 中引用
引入history 模块
require('connect-history-api-fallback')
var app=express()后插入 app.use (history)
虽然改成了history 模式 但仍然可以采用 #/ 或者 #的方式进行并存
虽然改成了history 模式 但仍然可以采用 #/ 或者 #的方式进行并存
解决:
1, 所有图片和直接使用的第三方js 和css 都放在 ,public 目录下
2,在唯一完整的index.html 网页中,引入public 下的第三方 css,js文件时必须以 “/”开头,不能用 相对路径
vue 脚手架 懒加载
run bulid 一下
要想懒加载 挂载路由的时候不要在上面引入
如 import hello from './hello'//不要这样做
安装懒加载的依赖
npm i -save @bable/plugin-syntax-dynamic-import
配置 router.js
将需要懒加载的页面,如详情页设置为
//路径
component:()=('../view/detaile.vue',)
如果一开始已经有 bulid 过的文件夹请先删除,然后再 bulid 一次
keep aLive 缓存
缓存组件内容,避免组件反复加载,影响效率
何时:
希望组件内容不要重复加载时
使用:
缓存页面
1,在路由当中 router.js
如果希望缓存当前页面:
可以在配置路由的后加上
meta 不可改动
meta:{
//KeepAlive 是自定义的属性
keepAlive:true
}
2,在app.vue 中
//将router-view 标签 用 <keep-alive></keep-alive>包裹起来,如下
<keep-alive>
//
<router-view v-if="$router.meta.keepAive"/ >
</keep-alive>
//如果有的不希望缓存
//这个标签配置在下面就行,不用包裹
<router-view v-if="!$router.meta.keepAive"/ >
问题
虽然是同一个页面,但是有时数据需要缓存有的时候不需要缓存,
如有一个商品列表界面,可以根据关键词,商品列表
首页–搜索页—商品列表页面–商品详情页
解决路由守卫
路由守卫
路由钩子函数,在发生路由跳转时,自动执行的回调函数函数就叫做路由钩子函数。
何时:
跳进或跳出一个路由的时候自定执行一项任务
使用:
分为几个阶段:
- 导航被触发。
在失活的组件里调用离开守卫 beforeRouteLeave 守卫。(跳走时)
调用全局的 beforeEach 守卫。
在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。(路由更新的时候)
在路由配置里调用 beforeEnter。
解析异步路由组件。
在被激活的组件里调用 beforeRouteEnter。(进入触发)
调用全局的 beforeResolve 守卫 (2.5+)。
导航被确认。
调用全局的 afterEach 钩子。
触发 DOM 更新。
调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作 为回调函数的参数传入。
原页面(beforeRouteLeave)--------->新页面(beforeRouteEnter)
原页面组件方法中中可以写
beforeRouteLeave(to,from,next){
//如果从商品列表跳转到详情页的时候就缓存
if(to.name='details'){
to.meta.keepAlive=true;
}
next()
}
新页面组件方法中
beforeRouteEnter(to,from,next){
//如果从首页跳到详情页是不需要缓存的
if(to.name=='products'){
//设置不缓存
to.meta.keepAlive=false;
}
next()
}
vue 间避免样式冲突
问题:由于vue 会将所有的样式编译在一个js 和css 文件夹所以会出现样式冲突
解决:
- 加
<style scoped></style>
- 定义组件的class 名称 :组件名为类名>元素类名称
vue 事件修饰符
1 限制键盘号 @key.13=“search”
2 阻止默认行为 @click.prevent=“search” 等效于e.preventDefault()
3 阻止事件冒泡 @click.stop=“search”
当然 1 2 3可以连着写
vue 防抖
必须在用户操作停止一段时间才进行正式的操作
data 变量中加一个定时器 timer:null
//定时器 实现
if(this.timer!=null){
clearTimeout(this.timer)
}
this.timer=setTimeout(Function(){
if(this.keyword.trim()!==""){
console.log(`查找` ${this.keyword.trim()}相关的内容)
}
},1000)
父子通信/传参
打通父子之间所有的数据和方法的共享
父模板
<child ref="子组件名称" ></child>
父访问子
父组件:this.$refs.子组件名称.子数据/方法名称()
子访问父: 父组件:this.$parent.子数据/方法名称()
兄弟传参
1,单独建一个 中间传递信息的js 文件,创建一个实例对象
bus.js
import Vue from 'vue'
export default new Vue()
再在main.js 中引用
导入 import vue
应用 安装到 vue 的原型对象中
Vue.prototype.bus=bus;//公共
2,其他组件调用
created(){
//将这个函数的this绑定到该组件的函数中,确定this指向
this.bus.$on('自定义的函数名',this.add.bind(this))
}
3,发送者
this.bus.$emit('自定义函数名称',this.task);//传值双向绑定
this.task=''
vue 子组件接收父组件传递的参数及内容
子组件先定义两个接收属性的参数
定义 props 公开属性,接收父组件传递的内容
<todolitem props:["index","item"]></todolitem>
父组件
<todo-item v-for="(item,index) of emp " :key='index'
:index="index" :item:'item'>
</todo-item>
如果只是想显示的话可以设置为插槽
vue 父子通信之插槽
插槽传递的值只能用来显示而不适合直接传递使用
使用方法:
父组件要在引用的子组件上添加一个自定义的事件,并且绑定
自定义事件
<todo-item v-for="(item,index) of emp"
:key="index" :l="index" @del='del'>
<li></li>
</todo-item>
父组件可以提前在自己自定义的方法内声明好这个方法然后传递给子组件
父组件:
methods:{
del(){
this.item.splice(l,1)
}
}
子组件:
触发父组件的方法:
methods:{
//触发的意思
this.$emit('父元素自定义的方法',this.i)
}
总而言之,就是子组件可以定义好插槽等着接收看,父组件装备好卡片进行传递
子组件显示内容区域:
<li>
<slot name="task"></slot>
</li>
父组件:
<ul>
子组件定义的插槽名称
<template sloat='task'>
{{task(父组件的要传递的内容)}}
</template>
</ul>
Vue filter 跟angular 一样的过滤器 百度查可用
- https://github.com/freearhey/vue2-filters