前言:带*都是重点
采用数据劫持结合观察-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter。
在数据变动时发布消息给订阅者,触发相应的监听回调来渲染视图,实现数据和视图同步。
1.模版引擎 正则 替换muastache里面的内容渲染成dom
2.数据响应式原理 Vue 会把普通对象变成响应式对象,响应式对象 getter 相关的逻辑就是做依赖收集
3.虚拟dom 由h函数产生
4.diff算法 只比较同一层级,不跨层比较
tag不同,直接删除重建,不再深度比较
tag和key,两者都相同,则认为是相同节点,不再深度比较
模版引擎 数据响应式 虚拟dom diff算法
(1)MVC:是后台的框架模式
分为M:(model模型)、V(view视图)、C(controller控制器)
(2)MVVM是为了实现MVC中的V
MVVM分为:M(model数据)、V(view视图)、VM(viewModel控制数据的改变和控制试图)
响应式系统简述:
任何一个Vue Component都有一个与之对应的Watcher实例
Vue的data上的属性会被添加getter和setter
当Vue Component render函数被执行的时候,data上会被touch,即被读,getter方法会被调用,此时 Vue 会去记录此 Vue component 所依赖的所有 data。(这一过程被称为依赖收集)
data 被改动时(主要是用户操作), 即被写, setter 方法会被调用, 此时 Vue 会去通知所有依赖于此
data 的组件去调用他们的 render 函数进行更新
通过js创建一个Object对象(AST节点树)来模拟真实DOM结构,这个对象包含标签名 (tag)、属性 (attrs) 和子元素对象 (children) 三个属性,通过vue中的render()函数把虚拟dom编译成真实dom,在通过appendChild()添加到页面中。
虚拟dom可以简单的用一句话概括,就是用普通的js对象来描述DOM结构,因为不是真实DOM,所以称之为虚拟DOM。
为什么要用虚拟DOM来描述真实的DOM呢?
创建真实DOM成本比较高,如果用 js对象来描述一个dom节点,成本比较低,另外我们在频繁操作dom是一种比较大的开销。所以建议用虚拟dom来描述真实dom。
diff的过程就是调用名为patch的函数,比较新旧节点,一边比较一边给真实的DOM打补丁
• 比较只会在同层级进行, 不会跨层级比较
• 在diff比较的过程中,循环从两边向中间比较
用 JavaScript 对象结构表示 DOM 树的结构;然后用这个树构建一个真正的 DOM 树,插到文档当中。
当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较(diff),记录两棵树差异
把第二棵树所记录的差异应用到第一棵树所构建的真正的DOM树上(patch),视图就更新了
5.既然Vue通过数据劫持可以精准探测数据变化,为什么还需要虚拟DOM进行diff检测差异?
考点: Vue 的变化侦测原理
前置知识: 依赖收集、虚拟 DOM、响应式系统
现代前端框架有两种方式侦测变化,一种是pull,一种是push
新,然后React会进行一层层的Virtual Dom Diff操作找出差异,然后Patch到DOM上,React从一开始就
不知道到底是哪发生了变化,只是知道「有变化了」,然后再进行比较暴力的Diff操作查找「哪发生变
化了」,另外一个代表就是Angular的脏检查操作。
一但数据发生变化,响应式系统就会立刻得知。因此Vue是一开始就知道是「在哪发生变化了」,但是这
又会产生一个问题,如果你熟悉Vue的响应式系统就知道,通常一个绑定一个数据就需要一个Watcher,
一但我们的绑定细粒度过高就会产生大量的Watcher,这会带来内存以及依赖追踪的开销,
而细粒度过低会无法精准侦测变化,因此Vue的设计是选择中等细粒度的方案,在组件级别进行push侦测的
方式,也就是那套响应式系统,通常我们会第一时间侦测到发生变化的组件,然后在组件内部进行Virtual
Dom Diff获取更加具体的差异,而Virtual Dom Diff则是pull操作,Vue是push+pull结合的方式进行变
化侦测的。
1.父传子:
1.在父组件的子组件标签上绑定一个属性,挂载要传输的变量。在子组件中通过props来接受数据,props可以是数组也可以是对象,接受的数据可以直接使用props
2.父组件调用子组件的方法通过ref在DOM元素上使用 r e f s 可 以 迅 速 进 行 d o m 定 位 , 使 用 t h i s . refs可以迅速进行dom定位,使用this. refs可以迅速进行dom定位,使用this.refs.paramsName能更快的获取操作子组件属性值或函数
2.子传父:
vue2.0只允许单向数据传递,我们通过触发自定义事件来改变组件的数据
在父组件的子组件标签上通过绑定自定义事件,接受子组件传递过来的事件。子组件通过$emit触发父组件上的自定义事件,发送参数(第一个是要改变的属性值,第二个是要发送的参数)
3.兄弟组件传值:
通过main.js初始化一个全局的 b u s , 在 发 送 事 件 的 一 方 通 过 b u s . b u s . b u s . e m i t ( “ 事 件 名 ” , 传 递 的 参 数 信 息 ) 发 送 , 在 接 收 事 件 的 一 方 通 过 bus,在发送事件的一方通过b u s . bus.bus.emit(“事件名”,传递的参数信息)发送,在接收事件的一方通过 bus,在发送事件的一方通过bus.bus.bus.emit(“事件名”,传递的参数信息)发送,在接收事件的一方通过bus. o n ( “ 事 件 名 ” , 参 数 ) 接 收 传 递 的 事 件 B u s . on(“事件名”,参数)接收传递的事件 Bus. on(“事件名”,参数)接收传递的事件Bus.on(“事件名”)
1.vuex :是一个专为vue.js开发的状态管理工具,采用集中式存储的所有组件状态,通过vuex我们可以解决组件之间数据共享的问题,后期也方便我们管理以及维护
有五个属性分别是: state、getters、mutations、actions、module
state属性: 存放状态,例如你要存放的数据
getters:类似于共享属性,可以通过this. s t o r e . g e t t e r s 来 获 取 存 放 在 s t a t e 里 面 的 数 据 m u t a t i o n s : 唯 一 能 改 变 s t a t e 的 状 态 就 是 通 过 提 交 m u t a t i o n s 来 改 变 , t h i s . store.getters来获取存放在state里面的数据 mutations:唯一能改变state的状态就是通过提交mutations来改变,this. store.getters来获取存放在state里面的数据mutations:唯一能改变state的状态就是通过提交mutations来改变,this.store.commit()
actions: 异步的mutations,可以通过dispatch来分发从而改变state
modules:模块化管理store(仓库),每个模块拥有自己的 state、mutation、action、getters
2.基本使用:我通过是在根目录下新建一个store文件夹,里面创建一个index.js文件,最后在main.js中引入,并挂载到实例上,之后那个组件中需要用到vuex就调用就行
3.高级用法-数据持久化
vuex里面存放的数据,页面一经刷新会丢失:
解决办法: 存放在localStorage或者sessionStorage里面,进入页面时判断是否丢失,丢失再去localStorage或者sessionStorage里面取;
在vuex中可以通过安装vuex-persistedstate [pərˈsɪstɪd steɪt] 插件,进行持久化的配置就行
4.高级用法-辅助函数(语法糖)
有4个辅助函数(
mapState,mapActions,mapMutations,mapGetters
辅助函数可以把vuex中的数据和方法映射到vue组件中。达到简化操作的目的
如何使用:
Import { mapActions, mapGetters, mapMutations, mapState } from ‘vuex’
vue中的自定义指令:
vue中除了核心功能内置的指令外,也允许注册自定义指令。自定义指令又分为全局的自定义指令和局部自定义指令。
全局自定义指令是通过Vue.directive(‘第一个参数是指令的名称’,{第二个参数是一个对象,这个对象上有钩子函数})
Vue.directive('focus', {
// el:指令所绑定的元素,可以用来直接操作 DOM。
//binding:一个对象,包含以下 property:
inserted: function (el) { vNode参数
el.focus();
}
});
局部自定义指令:
是定义在组件内部的,只能在当前组件中使用
directives: {
// 指令名称
dir1: {
inserted(el) { // inserted 表示被绑定元素插入父节点时调用
// 指令中第一个参数是当前使用指令的DOM
console.log(el);
console.log(arguments);
// 对DOM进行操作
el.style.width = '200px';
el.style.height = '200px';
el.style.background = '#000';
}
},
color: { // 为元素设置指定的字体颜色
bind(el, binding) {
el.style.color = binding.value;
}
}
}
自定义指令的钩子函数:
一个指令定义对象可以提供如下几个钩子函数 (均为可选):
inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
bind:只调用一次,指令第一次绑定到元素时调用。
update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前
componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
unbind:只调用一次,指令与元素解绑时调用。
钩子函数中的参数有:
el指令所绑定的元素,可以用来直接操作 DOM
binding:一个对象,里面有以下参数:
name:指令名,不包括 v- 前缀。
value:指令的绑定值,例如:v-my-directive=“1 + 1” 中,绑定值为 2。
使用场景:input输入框自动聚焦使用自定义指令 v-focus,在script中使用directives注册v-focus指令 自定义指令图片懒加载
vue中自定义过滤器
• 过滤器是对即将显示的数据做进一步的筛选处理,然后显示,过滤器并没有改变原来的数据,只是在原数据的基础上产生新的数据
• 过滤器分为全局过滤器和局部过滤器
全局过滤器
全局过滤器是通过Vue.filter()来定义的,定义好后,它在所有组件中都可以使用。第一个是过滤器名称 第一个参数是需要过滤的值 第二个参数是给过滤器传递的值
// global-filter是过滤器名称
// 函数第一个参数是需要过滤的数据.
// 函数第二个参数是给过滤器传递的值.
Vue.filter('global-filter',(val,...args)=>{
console.log(`需要过滤的数据是:${val}`)
return val + ' 过滤器追加的数据'
})
局部过滤器
局部过滤器,定义在组件内部 filters 属性上.它只能在此组件内部使用.
过滤器的使用方式是,在双花括号或v-bind中通过一个管道符 ‘|’ 来拼接,
过滤器在vue3中被移除了 功能需要使用 计算属性代替
局部过滤器
局部过滤器,定义在组件内部 filters 属性上.它只能在此组件内部使用.
过滤器的使用方式是,在双花括号或v-bind中通过一个管道符 ‘|’ 来拼接,
过滤器在vue3中被移除了 功能需要使用计算属性代替
router是VueRouter的实例,使用$ router.push方法导航。返回上一个历史history用$router.to(-1)
$route为当前router跳转对象。里面可以获取当前路由的name,path,query,parmas等。
通过改变 URL,在不重新请求页面的情况下,更新页面视图。
路由分为History模式和Hash模式
History模式 前端的URL必须和实际向后端发起请求的URL一致 如果后端缺少对路由处理,将返回404错误
Hash模式在浏览器中符号的“#”,以及#后面的字符称之为hash hash虽然出现在URL中,但不会被包括在HTTP请求中,对后端完全没有影响,因此改变hash不会重新加载页面。
window.hashchange监听hash值的改变,
history模式监听路径的改变
三种:分别是query,params,动态路由传参
接收:
通过query方式传递过来的参数一般是通过this.route.query接 收
通过params方式传递过来的参数一般是通过this.route.params接收 需要指定目标路由的name属性
路由规则开启props传参,路由组件接收并使用路由参数 props可以是箭头函数 对象 数组
通过动态路由 /user/:id 传参方式传递过来的参数一般是通过this.$route.params接收
Router-link路由传参 URL后面传参,通过斜线进行传参
router.beforeEach 全局前置守卫 进入路由之前 场景:动态路由权限添加
router.beforeResolve 全局解析守卫(2.5.0+) 在beforeRouteEnter调用之后调用
router.afterEach 全局后置钩子 进入路由之后 没有next
进组组件前的守卫 beforeRouteEnter 没有办法获取this,当前组件没有创建
路由更新时的守卫 beforeRouteUpdata(2.2新增)
离开组件时的守卫 beforeRouteLeave
to,from,next 这三个参数:
to和from是将要进入和将要离开的路由对象,路由对象指的是平时通过this.$route获取到的路由对象。
next:Function 这个参数是个函数,且必须调用,否则不能进入路由(页面空白)。
next() 进入该路由。
next(false): 取消进入路由,url地址重置为from路由地址(也就是将要离开的路由地址)。 next 跳转新路由,当前的导航被中断,重新开始一个新的导航。
router-link (不带参数)
this. r o u t e r . p u s h ( ) ( 函 数 里 面 调 用 ) t h i s . router.push() (函数里面调用) this. router.push()(函数里面调用)this.router.replace() (用法同push)
this.$router.go(n)go返回几级页面(正数是往前跳转页面,负数是往后跳转页面)
引入项目,在项目里面怎么使用(后台管理,token,白名单)
在下次DOM更新循环结束后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的DOM。使用场景是:可以在created钩子函数中拿到dom节点
无法获取的原因:
vue的reader渲染函数是异步的,例如将变量修改,数据改变引起虚拟dom对比,如果立刻获取真实dom,无法获取,因为数据改变引起虚拟dom对比,立即获取真实dom是undefined,可以使用定时器、 n e x t T i c k 使 用 场 景 : 假 如 定 义 一 个 变 量 开 关 , 修 改 开 关 变 量 让 按 钮 和 输 入 框 来 回 切 换 , 切 换 到 i n p u t 直 接 获 取 d o m 为 其 绑 定 自 动 聚 焦 , 是 不 可 以 获 取 d o m 的 , 因 为 数 据 的 变 化 引 起 了 虚 拟 d o m 对 比 , 立 即 获 取 真 实 d o m 是 u n d e f i n e d , 可 以 使 用 定 时 器 、 nextTick 使用场景: 假如定义一个变量开关,修改开关变量让按钮和输入框来回切换,切换到input直接获取dom为其绑定自动聚焦,是不可以获取dom的,因为数据的变化引起了虚拟dom对比,立即获取真实dom是undefined,可以使用定时器、 nextTick使用场景:假如定义一个变量开关,修改开关变量让按钮和输入框来回切换,切换到input直接获取dom为其绑定自动聚焦,是不可以获取dom的,因为数据的变化引起了虚拟dom对比,立即获取真实dom是undefined,可以使用定时器、nextTick
给ele-input绑定自定义指令v-focus,不起作用,因为ele-input被封装了,el-input绑定原生事件要加.native
如果为对象添加少量的新属性,可以直接采用Vue.set()
如果需要为新对象添加大量的新属性,则通过创建新对象的方式Object.assign()
如果你需要进行强制刷新时,可采取$forceUpdate() (不建议)
方案一:利用 this.set(this.obj,key,val) target:要修改的对象或数组
例:this.set(this.obj,‘k1’,‘v1’)
方案二:就利用 Object.assign({},this.obj)创建新对象 (额 晒恩)
如果是数组就 Object.assign([],this.obj)
如果是对象就 Object.assign({},this.obj)。
添加到对象的新属性不会触发更新
应创建一个新的对象,合并原对象和混入对象的属性
$forceUpdate如果你发现你自己需要在 Vue中做一次强制更新,99.9% 的情况,是你在某个地方做错了事
$forceUpdate迫使Vue 实例重新渲染
生命周期让我们在控制整个vue时更容易形成更好的逻辑,可以分为四个阶段,创建阶段,挂载阶段,更新阶段,销毁阶段
分别有:
创建前:beforeCreate() 数据代理前,只有一些实例本身的事件和生命周期函数,无法通过vm访问data中的数据和methods中的方法
创建后:Created() 是最早使用data和methods中数据的钩子函数
挂载前:beforeMount() 指令已经解析完毕,内存中已经生成dom树 不能对dom进行操作
挂载后:Mounted() dom渲染完毕页面和内存的数据已经同步
更新前:beforeUptate() 当data的数据发生改变会执行这个钩子,内存中的数据是新的,页面是旧的
更新后:Updated() 数据和页面都是新的
销毁前:beforeDestroy() 即将销毁data和methods中的数据此时还是可以使用的,可以做一些释放内存的操作
销毁后:Destroyed() 已经销毁完毕
自定义组件分为全局自定义组件和局部自定义组件,全局组件可以全局使用,可以在所有的页面中调用引入
局部组件仅限当前引入页面
全局自定义组件
写好组件在main文件直接引入,这种是最简单的方式
import myTabItem from ‘@/components/myTabItem/myTabItem.vue’
Vue.component(‘my-tab-item’, myTabItem) // 这种注册组件的方式叫做全局自定义组件html建议短横线分隔不建议驼峰
全局自定义组件是使用 Vue.component(‘组件名’, 组件模板)//组件模板就是引入组件路径定义的名字
局部自定义组件
在一个组件通过配置项 components注册的组件
在vue中提供了一些对于页面 + 数据的更为方便的输出,这些操作就叫做指令,指令中封装了一些DOM行为, 结合属性作为一个暗号, 暗号有对应的值,根据不同的值,框架会进行相关DOM操作的绑定
vue中的指令有很多,我们平时做项目常用的有:
v-else是搭配v-if使用的,它必须紧跟在v-if或者v-else-if后面,否则不起作用
v-show:是通过标签的CSS样式display的值是不是none,控制显示隐藏
v-if和v-show区别:
v-if更适合数据的筛选和初始渲染 v-show更适合元素频繁的切换
v-for: v-for是根据遍历数据来进行渲染,要配合key使用。要注意的是当v-for和v-if同处于一个节点时,v-for的优先级比v-if更高。这意味着v-if将运行在每个v-for循环中 在Vue3中v-if优先级更高
v-on:用来绑定一个事件或者方法,简写方式是@click=“”
v-bind: v-bind用来动态的绑定一个或者多个属性。没有参数时,可以绑定到一个包含键值的对象。常用于动态绑定class和style。以及href等。简写的方式是“:属性名=“””
v-cloak v-html v-text
数据双向绑定实现的原理:
是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter在数据变动时,发布消息给订阅者,触发相应的监听回调来渲染视图。
Vue3.0中Proxy并使用Reflect.set,可以实现对整个对象的劫持,可以在用到数据的时候再进行对下一层属性的劫持。Vue2递归对对象数据代理。
v-model
一个组件上的 v-model
默认会利用名为 value
的 prop 和名为 input
的事件,但是像单选框、复选框等类型的输入控件可能会将 value
attribute 用于不同的目的。
model
选项可以用来避免这样的冲突:
Vue.component('base-checkbox', {
model: {
prop: 'checked',
event: 'change'
},
props: {
checked: Boolean
},
template: `
`
})
1.将一个值以v-model的形式绑定到base-checkbox组件上,值的名称为checked,类型为Boolean
2.在组件上指定将哪个值用于于父组件绑定(model: { prop: ‘checked’, event: ‘change’ })
3.将checked绑定到了input上面(v-bind:checked=“checked”)
4.监听单选框的值的变化然后触发自定义事件返回给父组件
(v-on:change=“$emit(‘change’, $event.target.checked)”)
5.现在在这个组件上使用 v-model
的时候:
<base-checkbox v-model="lovingVue">base-checkbox>
这里的 lovingVue
的值将会传入这个名为 checked
的 prop。同时当
触发一个 change
事件并附带一个新的值的时候,这个 lovingVue
的 property 将会被更新。
• .stop :阻止事件冒泡
• .self :当事件作用在元素本身,触发回调
• .once :只执行一次
• .prevent: 阻止默认事件
• .capture :事件捕获
• ·passive:告诉浏览器你不想阻止事件的默认行为
• ·trim:自动过滤用户输入的首尾空格
语法:@事件名.修饰符=“方法名”0
key是给每一个vnode的唯一id,也是diff的一种优化策略,可以根据key,更准确, 更快的找到对应的vnode节点
有输入类的dom 进行unshift 头部数据插入删除一般不使用index 作为key
Number、bollean、string、object、array、function、date、symbol Symbol函数
Props是单线程的传递
prop 数据单项传递,父影响子,子不影响父
不能在组件中直接修改 prop 传递过来的值,Vue 会给出警告
prop 验证时,会在实例创建之前进行验证,所以实例的属性 (如 data、computed 等) 在 default 或 validator 函数中是不可用的
非 prop 特性,组件可以接受任意的特性,而这些特性会被添加到这个组件的根元素上。
Vue.mixin(xxx)
局部混入:mixins:['xxx']
例如 ref reactive watch computed toRefs toRaws
5.Suspense
Vue3中不再支持过滤器filterr
sync修改符已移除, 由v-model代替
vue3: v-if 优先级高于 v-for 因为vue2先循环再判断 耗费性能
6.Vue3 Tree shaking
简单来讲,就是在 保持代码运行结果不变的前提下,去除无用的代码
在Vue2中,无论我们使用什么功能,它们最终都会出现在生产代码中。主要原因是Vue实例在项目中是单例的,捆绑程序无法检测到该对象的哪些属性在代码中被使用到
而Vue3源码引入tree shaking特性,将全局 API 进行分块。如果你不使用其某些功能,它们将不会包含在你的基础包中
就是比如你要用watch 就是import {watch} from ‘vue’ 其他的computed 没用到就不会给你打包减少体积
Progressive Web App(PWA)支持
模板编译时的优化,将一些静态节点编译成常量
Slot优化,将slot编译为lazy函数,将slot的渲染的决定权交给子组织
Vue2--------------vue3
beforeCreate -> setup() 开始创建组件之前,创建的是data和method
created -> setup()
beforeMount -> onBeforeMount 组件挂载到节点上之前执行的函数。
mounted -> onMounted 组件挂载完成后执行的函数
beforeUpdate -> onBeforeUpdate 组件更新之前执行的函数。
updated -> onUpdated 组件更新完成之后执行的函数。
beforeDestroy -> onBeforeUnmount 组件挂载到节点上之前执行的函数。
destroyed -> onUnmounted 组件卸载之前执行的函数。
activated -> onActivated 组件卸载完成后执行的函数
deactivated -> onDeactivated
在vue脚手架在4.5.15的时候,vue3还是会向下兼容vue2的命令,但是vue的脚手架一旦升级成为5.0.1以后vue3就会舍弃掉现有的命令行,不会再向下兼容vue2版本,
但是在创建项目的时候5.0.1版本就会结合vite来创建项目,
vite有一个优点就是创建项目的时候启动的非常快和vue的4.5.15版本不太一样,在vue的4.5.15它会在创建项目的时候把所有的依赖(vuex、vue-router等)全部安装完毕,但是5.0.1版本它是冷启动(什么是冷启动,就是什么依赖都不会去装)你需要哪个就去下载哪个,所以它启动的非常迅速
keep-alive 是 Vue 的内置组件,当它包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。
keep-alive 是一个抽象组件:它自身不会渲染成一个 DOM 元素,也不会出现在父组件链中。
在组件切换过程中 把切换出去的组件保留在内存中,防止重复渲染DOM,减少加载时间及性能消耗,提高用户体验性,性能优化 。
被包含在 keep-alive 中创建的组件,会多出两个生命周期的钩子: activated keep-alive 组件激活时调用与 deactivated keep-alive 组件停用时调用
在不同环境,需要连接不同的资源:
比如dev环境,可能使用的数据库连接是某个远端的url
到了test环境,数据库连接可能存在一些变化——比如使用内网地址或库名有些变化……
这里希望达到的效果是,通过部署脚本来配置后端资源(数据库、缓存等)
这样各环境可以使用相同的构建物(docker image),从而保证代码一致性
这样在测试环境测试没问题的docker image,可以直接打标签部署到生产环境
毕竟没人能保证每次两次构建是完全一致的。
首先要安装axios,一般我会在项目的src目录中,新建一个utils文件夹,作为我们的网络请求模块,然后在里面新建一个http.js和一个api.js文件和一个reques.js。http.js文件用来封装我们的axios,在http.js里面添加请求拦截器和响应拦截器api.js用来统一管理我们的接口url,
reques.js用来调用封装我们需要使用到的方法在request.js中添加请求拦截和响应拦截。
在请求拦截中,会给请求头添加token字段,还有loading动画的开启。
在响应拦截中,可以做一些loading动画的关闭,还有可以根据后端返回的状态码,做一些检验token是否有效或者过期的操作。
接着就是做一些axios进行的api接口的封装,这里用到了async,await封装请求接口函数,这样可以将异步操作同步化操作,代码更加友好,避免回调地域的出现。
插槽就是父组件往子组件中插入一些内容。
有三种方式,默认插槽,具名插槽,作用域插槽
1.默认插槽就是把父组件中的数据,显示在子组件中,子组件通过一个 slot插槽标签 显示父组件中的数据
2.具名插槽是在父组件中通过,改用新写法 v-slot:center # 需要写template标签,给插槽命名,在子组件中通过slot标签,根据定义好的名字填充到对应的位置。
3.作用域插槽是带数据的插槽,子组件提供数据,父组件根据子组件传来的插槽数据来进行不同的展现和填充内容。在标签中通过slot-scope来接受数据。
如果不是一个函数,每个组件实例的data都是同一个引用数据,当该组件作为公共组件共享使用,一个地方的data更改,所有的data一起改变,如果data是一个函数,每个实例的data都在闭包中,就不会各自影响了。
data可以是对象也可以是函数,不会产生数据污染情况,函数有一个独立的作用域,函数内部的变量只能内部的函数去访问从而形成一个闭包
在mounted中加上this.$refs,或ref绑定一个对象
首先安装按需引入的插件,在main.js中添加按需引入的配置,之后在建好的js文件中首先导入vue,再导入需要的element-ui /vant-ui插件,通过vue.use()全局注入。
修改样式可以用样式穿透 /deep/ :deep
安装 npm install node-sass sass-loader --save 注意版本 使用lang=”scss”
Scss是Sass的缩排语法
1.变量符不一样,Less是@,而Sass是$,而且变量的作用域也不一样。
2.Sass没有局部变量,满足就近原则。Less中{}内定义的变量为局部变量。
3.**Sass支持条件语句,可以使用if{}else{},for{}循环等等。而Less不支持。**less里面有一些内置函数
十九、 Rem、vw/vh设置
rem 是根 root em的缩写,1rem等于html根元素设定的font-size的px值 flexible中
js动态设置html的 font-size= 移动设备 / 设计稿宽度 * 100 VantUI中设计稿默认37.5px
如果css里面没有设定html的font-size,则默认浏览器以1rem=16px来换算。
vw视窗的宽度 1vw=视窗宽度的1%
vh视窗高度,1vh=视窗高度的1%
一个对象,键是需要观察的表达式,值是对应回调函数。主要用来监听某些特定数据的变化,从而进行某些具体的业务逻辑操作;可以看作是 computed 和 methods 的结合体;
值是包括选项的对象:选项包括有三个。
第一个handler:其值是一个回调函数。即监听到变化时应该执行的函数。
第二个是deep:其值是true或false;确认是否深入监听。
第三个是immediate:其值是true或false;确认是否以当前的初始值执行handler的函数
1 . computed 属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算。主要当作属性来使用;调用多次,只会执行一次
2 . methods 方法表示一个具体的操作,主要书写业务逻辑;
3 . watch 一个对象,键是需要观察的表达式,值是对应回调函数。主要用来监听某些特定数据的变化,从而进行某些具体的业务逻辑操作;可以看作是 computed 和 methods 的结合体;
module.exports = {
devServer: {
proxy: {
'/api1': {// 匹配所有以 '/api1'开头的请求路径
target: 'http://localhost:5000',// 代理目标的基础路径
changeOrigin: true,
pathRewrite: {'^/api1': ''}
},
'/api2': {// 匹配所有以 '/api2'开头的请求路径
target: 'http://localhost:5001',// 代理目标的基础路径
changeOrigin: true,
pathRewrite: {'^/api2': ''}
}
}
}
}
/*
changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:8080
changeOrigin默认值为true
*/
一、Vue首屏加载路由懒加载使用ES6的import ( ) const 组件名 = ( ) => import(‘组件路径’)
1.webpack是可以帮助我们做到资源的去重和分离,去重就是将重复的引用减少,分离将不同的资源包分离在不同的包内
Webpack 构建结果输出分析 loader对css 图片资源压缩 js文件进行压缩 去除console 生产环境关闭source-map
externals防止将某些包打包到最终的bundle中,使用CDN加载 ,开启 gzip 压缩
浏览器缓存
浏览器域名解析为IP地址(DNS域名解析)。
本地解析:
浏览器缓存 → 系统缓存 → 查找本地host文件 → 本地DNS服务器缓存
互联网域名服务器解析:
→ 根域名服务器 → 顶级域名服务器 → 权威域名服务器
浏览器获得域名对应的ip地址后 ,与WEB服务器建立TCP连接(TCP三次握手)
tcp连接建立后,浏览器给WEB服务器发送一个HTTP请求
服务器端响应HTTP请求,返回HTTP报文
浏览器解析和渲染页面
关闭 TCP 连接(四次挥手)
(1)回流(重排):当render树中的一部分或者全部因为大小边距等问题发生改变而需要重建的过程叫做回流(改变大小)。
**(2)重绘:**当元素的一部分属性发生变化,如外观背景色不会引起布局变化而需要重新渲染的过程叫做重绘(改变样式)。
回流必将引起重绘
1.让元素脱离文档流 有动画效果的元素
2.通过合并多次DOM样式的修改,来减少回流和重绘的发生次数。
3.添加css样式而不是利用js控制样式
浏览器解析文档的过程中,如果遇到 script 标签,会立即解析脚本,停止解析文档(因为 JS 可能会改变 DOM 和 CSS,如果继续解析会造成浪费)。
如果是外部 script, 会等待脚本下载完成之后在继续解析文档。
现在 script 标签增加了 defer 和async 属性,脚本解析会将脚本中改变 DOM 和 css 的地方> 解析出来,追加到 DOM Tree 和Style Rules 上
100-199 提示信息 – 表示请求正在处理
200-299 成功 – 表示请求正常处理完毕
300-399 重定向 – 要完成请求必须进行更进一步的处理
400-499 客户端错误 – 请求有语法错误或请求无法实现
500-599 服务器端错误 – 服务器处理请求出错
200:请求成功,浏览器会把响应体内容(通常是html)显示在浏览器中;
301/302/303:(网站搬家了,跳转)重定向
400: 语义有误,当前请求无法被服务器理解。
401: 当前请求需要用户验证
403: 服务器已经理解请求,但是拒绝执行它。
404:(客户端问题)请求的资源没有找到
500:(服务端问题)请求资源找到了,但服务器内部发生了不可预期的错误;
理解浏览器跨域的概念:协议、域名、端口都相同才同域,否则都是跨域
跨域就是指浏览器不允许当前页面的所在源,去请求另一个源的数据
CORS跨域 (前端不用动,后端设置Access-Control-Allow-Origin等)
服务端进行接口请求设置,前端直接调用
说明:后台设置前端某个站点进行访问
JSONP (动态创建script标签)
JSONP跨域-前端适配,后端配合
前后端同时改造
git init 初始化git仓库 (mac中Command+Shift+. 可以显示隐藏文件)
git status 查看文件状态
git add 文件列表 追踪文件
git commit -m 提交信息 向仓库中提交代码
git log 查看提交记录
1.分支明细
(1)主分支(master):第一次向 git 仓库中提交更新记录时自动产生的一个分支。
(2)开发分支(develop):作为开发的分支,基于 master 分支创建。
(3)功能分支(feature):作为开发具体功能的分支,基于开发分支创建
2.分支命令
(1)git branch 查看分支
(2)git branch 分支名称 创建分支
(3)git checkout 分支名称 切换分支
(4)git merge 来源分支 合并分支 (备注:必须在master分支上才能合并develop分支)
(5)git branch -d 分支名称 删除分支(分支被合并后才允许删除)(-D 强制删除)
3.暂时保存更改
(1)存储临时改动:git stash
(2)恢复改动:git stash pop
多人冲突:
是当前修改是左箭头方向,传入的是右箭头的方向,中间用等于号分割,等号上边是当前修改,下边是传入的修改。
两人同时提交可能会出现冲突,解决办法是手动修改冲突
HTTP与HTTPS的区别
1、HTTP是超文本传输协议,信息是明文传输,HTTPS是具有安全性的SSL加密传输协议。
2、HTTPS协议需要ca申请证书,一般免费证书少,因而需要一定费用。
3、HTTP和HTTPS使用的是完全不同的连接方式,用的端口也不一样。前者是80,后者是443。
4、HTTP连接是无状态的,HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,安全性高于HTTP协议。
三次握手:
第一次:建立连接时,客户端发送syn(syn=j)包到服务器,等待服务端确认
第二次:服务器收到syn包,必须确认客户的syn(ack=j+1),同时也发送一个syn(syn=k)包,即syn+ACK包
第三次:客户端收到服务器的syn和ack包,向服务器发送确认包ack(ack=k+1),发送完毕,客户端和服务端连接成功,完成三次握手
四次挥手:
第一次:浏览器发送完数据后,发送fin请求断开连接
第二次:服务器发送ack到客户端,确认客户端的断开请求
第三次:服务器请求断开fin的请求
第四次:客户端确认服务器的断开ack
使用基于 Token 的身份验证方法,大概的流程是这样的:
客户端使用用户名跟密码请求登录
服务端收到请求,去验证用户名与密码
验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里
客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据
GET请求会将数据放到URL后面 POST请求会将数据放到请求体中 (http 协议规定,url 在请求头中,所以大小限制很小)
GET请求对所发信息量的限制是2000 个字符 POST请求对信息量没有限制
GET请求的参数只能是ASCII码,所以中文需要URL编码 POST请求传参没有这个限制
GET请求用于提交非敏感数据和小数据 POST请求用于提交敏感数据和大数据
Ge和post的选择:
1.私密性的信息请求使用post(如注册、登陆)
2.查询信息使用get。
攻击者往Web页面里插入恶意 html标签或者javascript代码。
用来窃取cookie中的用户信息
解决:对一些输入的字符进行过滤,尽量采用post表单提交的方式。
登录受信任的网站A,并在本地生成Cookie,在不登出A的情况下,携带cookie去访问危险网站B
解决:通过验证码的方式解决
就是通过吧SQL命令插入到Web表单递交或输入域名,最终达到欺骗服务器执行恶意的SQL命令。
解决:表单输入时通过正则表达式将一些特殊字符进行转换