赞
踩
vue是个轻量级的框架,是一个构建数据的视图集合,大小只有几十Kb
vue是组件化开发,适合多人开发
vue中的双向数据绑定更方便操作表单数据
因为vue是MVVM的框架,视图,数据,结构分离使数据的更改更为简单
vuex可以管理所有组件用到的数据,不需要借助之前props在组件间传值
官方文档通俗易懂,易于理解和学习;
数据驱动和组件化。
理解
model是数据模型,管理数据和处理业务逻辑
view是视图,负责显示数据
ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,负责监听Model中数据的改变并且控制视图的更新
model中的数据改变,view也会跟着改变;用户通过交互操作改变view中的数据,model也会跟着改变。其中的dom操作viewmodel帮我们完成了,不需要自己操作dom
优点
mvvm 主要解决了 mvc 中大量的 DOM 操作使页面渲染性能降低,加载速度变慢,影响用户体验。
当 Model 频繁发生变化,开发者需要主动更新到 View
当data 有变化的时候它通过Object.defineProperty()方法中的set方法进行监控,并调用在此之前已经定义好data 和view关系的回调函数,来通知view进行数据的改变
而view 发生改变则是通过底层的input 事件来进行data的响应更改
首先,使用Vue.extend()创建一个组件
然后,使用Vue.component()方法注册组件
接着,如果子组件需要数据,可以在props中接受定义
最后,子组件修改好数据之后,想把数据传递给父组件,可以使用emit()方法
通过props,例子如下
<template>
<div>
<div>{{message}}(子组件)</div>
</div>
</template>
<script>
export default {
props: {
message: { type: String, default: '默认值' } ,//定义传值的类型
}
</script>
<template> <div> <div>父组件</div> <child :message="parentMsg"></child> </div> </template> <script> import child from './child' //引入child组件 export default { data() { return { parentMsg: 'a message from parent' //在data中定义需要传入的值 } }, components: { child } } </script>
父:
<child ref="childMethod"></child>
子:
method: {
test() {
alert(1)
}
}
在父组件里调用test即 this.$refs.childMethod.test()
<template> <div class="app"> <input @click="sendMsg" type="button" value="给父组件传递值"> </div> </template> <script> export default { data () { return { //将msg传递给父组件 msg: "我是子组件的msg", } }, methods:{ sendMsg(){ //func: 是父组件指定的传数据绑定的函数,this.msg:子组件给父组件传递的数据 this.$emit('func',this.msg) } } } </script>
<template> <div class="app"> <child @func="getMsgFormSon"></child> //父组件调用方法 </div> </template> <script> import child from './child.vue' export default { data () { return { msgFormSon: "this is msg" } }, components:{ child, }, methods:{ getMsgFormSon(data){ //此处的data即为子组件传过来的数据 this.msgFormSon = data console.log(this.msgFormSon) } } } </script>
直接在子组件中通过this.$parent.event来调用父组件的方法
bus方式
1.新建bus.js
import Vue from 'vue'
export default new Vue
2.在需要传值和接受值的vue文件中,各自引入bus.js
import bus from '../util/bus'
3.定义传值的方法,使用bus.$emit(‘methodName’,data), methodName是自定义的方法名
<button @click="trans()">传值</button>
methods: {
trans(){
bus.$emit('test',this.helloData)
}
},
4.在要接收值的组件里,使用bus.on(‘methodName’,val =>{ }) ,val 就是传过来的值
mounted(){
bus.$on('test',val=>{
console.log(val);
this.cdata = val
})
}
1、安装vuex :cnpm install vuex --save
2、创建一个 vuex 文件夹,并在里面新建一个 store.js 写入以下代码:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
3、state 定义数据:state在vuex中用于存储数据
var state={ //存放数据,数据中心
count:1,
// 其他数据格式:orderList: [],
// 其他数据格式:params: {}
}
4、 getters 类似计算属性:
var getters= {
computedCount: (state) => {
return state.count*2
}
}
5、mutations里面放的是方法,方法主要用于改变state里面的数据
var mutations={
incCount(){
++state.count;
}
}
6、异步操作,Action 提交的是 mutation,而不是直接变更状态
var actions= {
incMutationsCount(context) { /*因此你可以调用 context.commit 提交一个 mutation*/
context.commit('incCount'); /*执行 mutations 里面的incCount方法 改变state里面的数据*/
//此处按照实际情况扩展~
}
}
7、暴露参数
const store = new Vuex.Store({
state,
mutations,
getters,
actions
})
export default store;
8、 组件里去使用 Vuex:
(1). 获取state里面的数据
this.$store.state.数据
(2). 获取 getters里面方法返回的的数据 (一般vue 和 store 进行交互 用 $store.getters, getters的值放在计算属性里,动态绑定在计算属性computed里)
this.$store.getters.computedCount
(3). 触发 mutations 改变 state里面的数据
this.$store.commit('incCount');
(4). 触发 actions里面的方法
this.$store.dispatch('incMutationsCount');
//这个 incMutationsCount 会再去 执行 mutations 里面的incCount方法
1.区别:vuex存储在内存,localstorage(本地存储)则以文件的方式存储在本地,永久保存;
localStorage和sessionStorage只能存储字符串类型,对于复杂的对象可以使用ECMAScript提供的JSON对象的stringify和parse来处理
2.应用场景:vuex用于组件之间的传值,localstorage,sessionstorage则主要用于不同页面之间的传值。
3.永久性:当刷新页面(这里的刷新页面指的是 --> F5刷新,属于清除内存了)时vuex存储的值会丢失,sessionstorage页面关闭后就清除掉了,localstorage不会。
1.使用vue-router通过跳转链接带参数传参。
2.使用本地缓存localStorge。
3.使用vuex数据管理传值。
路由钩子函数有三种:
1:全局钩子: beforeEach、 afterEach
2:单个路由里面的钩子: beforeEnter
3: 组件路由:beforeRouteEnter、 beforeRouteUpdate、 beforeRouteLeave
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
// ...
})
to:路由将要跳转的路径信息,信息是包含在对像里边的。
from:路径跳转前的路径信息,也是一个对象的形式。
next:路由的控制参数,常用的有next(true)和next(false)。
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` } }
beforeRouteEnter 钩子 不能 访问 this,因为钩子在导航确认前被调用,因此即将登场的新组件还没被创建。不过,你可以通过传一个回调给 next来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数。
beforeRouteEnter (to, from, next) {
next(vm => {
// 通过 `vm` 访问组件实例
})
}
1、清除当前组件中的定时器,当一个组件中有一个定时器时, 在路由进行切换的时候, 可使用beforeRouteLeave将定时器进行清楚, 以免占用内存:
beforeRouteLeave (to, from, next) {
window.clearInterval(this.timer) //清除定时器
next()
}
2、当页面中有未关闭的窗口, 或未保存的内容时, 阻止页面跳转如果页面内有重要的信息需要用户保存后才能进行跳转, 或者有弹出框的情况. 应该阻止用户跳转
beforeRouteLeave (to, from, next) {
//判断是否弹出框的状态和保存信息与否
if (this.dialogVisibility === true) {
this.dialogVisibility = false //关闭弹出框
next(false) //回到当前页面, 阻止页面跳转
}else if(this.saveMessage === false) {
//弹出警告
next(false) //回到当前页面, 阻止页面跳转
}else {
next() //否则允许跳转
}
}
配置静态的路由表,比如登录、注册页,其他路由通过动态注入
登录的时候过滤后台返回的路由列表,拿到符合路由规则的路由表
通过 addRoutes() 这个方法把路由给注入到路由表,这样就可以访问已注入的路由了
1、第一次登录的时候,前端调后端的登陆接口,发送用户名和密码
2、后端收到请求,验证用户名和密码,验证成功,就给前端返回一个token
3、前端拿到token,将token存储到localStorage和vuex中,并跳转路由页面
4、前端每次跳转路由,就判断 localStroage 中有无 token ,没有就跳转到登录页面,有则跳转到对应路由页面
5、每次调后端接口,都要在请求头中加token
6、后端判断请求头中有无token,有token,就拿到token并验证token,验证成功就返回数据,验证失败(例如:token过期)就返回401,请求头中没有token也返回401
7、如果前端拿到状态码为401,就清除token信息并跳转到登录页面
// 导航守卫
// 使用 router.beforeEach 注册一个全局前置守卫,判断用户是否登陆
router.beforeEach((to, from, next) => {
if (to.path === '/login') {
next();
} else {
let token = localStorage.getItem('Authorization');
if (token === 'null' || token === '') {
next('/login');
} else {
next();
}
}
});
// 添加请求拦截器,在请求头中加token
axios.interceptors.request.use(
config => {
if (localStorage.getItem('Authorization')) {
config.headers.Authorization = localStorage.getItem('Authorization');
}
return config;
},
error => {
return Promise.reject(error);
});
//如果前端拿到状态码为401,就清除token信息并跳转到登录页面
localStorage.removeItem('Authorization');
this.$router.push('/login');
调微信的授权登录地址,成功之后微信会重定向回到我们开发的页面并返回code在回调的url中
拿到code以后,传给后台,让后台去获取用户信息再传给前端。我们拿到用户信息后,比如openId,头像等,可以用localStorage缓存起来
v-show 本质就是通过控制 css 中的 display 设置为 none,控制隐藏,只会编译一次;v-if 是动态的向 DOM 树内添加或者删除 DOM 元素,若初始值为 false ,就不会编译了。而且 v-if 不停的销毁和创建比较消耗性能。
总结:如果要频繁切换某节点,使用 v-show (切换开销比较小,初始开销较大)。如果不需要频繁切换某节点使用 v-if(初始渲染开销较小,切换开销比较大)
v-model 双向数据绑定;
v-for 循环;
v-if v-show 显示与隐藏;
v-on 事件;v-once : 只绑定一次。
概念:Vue 实例从创建到销毁的过程
生命周期钩子的一些使用方法:
beforecreate : 可以在这加个loading事件,在加载实例时触发
created : 初始化完成时的事件写在这里,如在这结束loading事件,异步请求也适宜在这里调用
mounted : 挂载元素,获取到DOM节点
updated : 如果对数据统一处理,在这里写上相应函数
beforeDestroy : 可以做一个确认停止事件的确认框 nextTick : 更新数据后立即操作dom
父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。
mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。
计算属性和侦听属性都可以实现当某一个数据(称它为依赖数据)发生变化的时候,所有依赖这个数据的“相关”数据“自动”发生变化,但在特定场景下的处理还是有一些微妙的区别
data: { firstName: 'Liu', lastName: 'lu' }, computed: { fullName:{ get(){//回调函数 当需要读取当前属性值时执行,根据相关数据计算并返回当前属性的值 return this.firstName + ' ' + this.lastName }, set(val){//监视当前属性值的变化,当属性值发生变化时执行,更新相关的属性数据 //val就是fullName的最新属性值 console.log(val) const names = val.split(' '); console.log(names) this.firstName = names[0]; this.lastName = names[1]; } } }
watch: {
pagination: {
handler (val) {
this.paginationInfo = val
},
immediate: true,
deep: true
}
}
computed常用于值的计算,如简化tempalte里面{{}}计算和处理props或$emit的传值,页面重新渲染值不变化,计算属性会立即返回之前的计算结果,而不必再次执行函数。
watch常用来观察动作,听props,$emit或本组件的值执行异步操作,页面重新渲染时值不变化也会执行
computed名称不能与data里对象重复,只能用同步,必须有return,是多个值变化引起一个值变化,多多对一
watch名称必须与data里对象一样,可以用于异步,没有return,是一对多,监听一个值,一个值变化引起多个值变化
1、watch中的函数名称必须是所依赖data中的属性名称
2、watch中的函数是不需要调用的,只要函数所依赖的属性发生了改变 那么相对应的函数就会执行
3、watch中的函数会有2个参数 一个是新值,一个是旧值
4、watch默认情况下无法监听对象的改变,如果需要进行监听则需要进行深度监听 深度监听需要配置handler函数以及deep为true。(因为它只会监听对象的地址是否发生了改变,而值是不会监听的)
5、watch默认情况下第一次的时候不会去做监听,如果需要在第一次加载的时候也需要去做监听的话需要设置immediate:true
6、watch在特殊情况下是无法监听到数组的变化
- 通过下标来更改数组中的数据
- 通过length来改变数组的长度
原因:v-for比v-if优先,如果每一次都需要遍历整个数组,将会影响速度,尤其是当之需要渲染很小一部分的时候。
不推荐:
<ul>
<li v-for="user in users" v-if="user.isActive" :key="user.id">
{{ user.name }}
</li>
</ul>
推荐:
computed: {
activeUsers: function () {
return this.users.filter(function (user) {
return user.isActive
})
}
}
<ul>
<li v-for="user in activeUsers" :key="user.id">
{{ user.name }}
</li>
</ul>
可以让当前组件或者路由不经历创建和销毁,而是进行缓存,凡是被keep-alive组件包裹的组件,除了第一次以外。不会经历创建和销毁阶段的。第一次创建后就会缓存到缓存当中
初次进入时:created > mounted > activated;退出后触发 deactivated
再次进入:会触发 activated;事件挂载的方法等,只执行一次的放在 mounted 中;组件每次进去执行的方法放在 activated 中
keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。
routers: [{
path: '/',
name: 'Home',
meta: {
keepAlive: false // 不需要缓存
}
},{
path: '/page',
name: 'Page',
meta: {
keepAlive: true // 需要缓存
}
},]
$router为VueRouter的实例,是一个全局路由对象,包含了路由跳转的方法、钩子函数等。
$route 是路由信息对象||跳转的路由对象,每一个路由都会有一个route对象,是一个局部对象,包含path,params,hash,query,fullPath,matched,name等路由信息参数
state:存储数据,存储状态;在根实例中注册了store 后,用 this.$store.state 来访问;对应vue里面的data;存放数据方式为响应式,vue组件从store中读取数据,如数据发生变化,组件也会对应的更新。
组件访问State中数据的两种方式
1、this.$store.state.全局数据名称
2、从vuex中按需导入mapState函数,将当前组件需要的全局数据映射为当前组件的computed计算属性
import { mapState } from 'vuex'
computed:{
...mapState( ['count'] )
}
getter:可以认为是 store 的计算属性,它的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
const store = new Vuex.store({
state:{
count : 0
},
getters:{
countAfter: state=>{
return count*2
}
}
})
//使用getters的第一种方式
this.$store.getters.countAfter
mutation:更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。
const store = new Vuex.store({
state:{
count : 0
},
mutation:{
add(state){
//变更状态
state.count++
}
}
})
nethods:{
handle(){
//触发mutation的第一种方式
this.$store.commit('add')
}
//1、从vuex中按需导入mapMutation函数
import { mapMutation } from 'vuex'
//2、将指定的mutation函数,映射为当前组件的methods函数
methods:{
...mapMutation(['add','addN'])
handle(){
//触发mutation的第二种方式
this.add()
}
}
action:包含任意异步操作,通过提交 mutation 间接更变状态。
const store = new Vuex.store({ mutation:{ add(state){ state.count++ } }, actions:{ addAsync(context){ //在actions中不能直接修改state中的数据 //必须通过context.commit()触发某个mutation才行 setTimeout(()=>{ context.commit('add') },1000) } } })
//触发Action
methods:{
handle(){
//触发actions的第一种方式
this.$store.dispatch('addAsync')
}
}
//1、从vuex中按需导入mapActions函数
import { mapActions} from 'vuex'
//2、将指定的mapAtions函数,映射为当前组件的methods方法
methods:{
...mapMutation(['addAsync','addNAsync'])
handle(){
//触发mutation的第二种方式
this.addAsync()
}
}
module:将 store 分割成模块,每个模块都具有state、mutation、action、getter、甚至是嵌套子模块。
<input type="text" v-model.trim="msg">
<input type="text" v-model.lazy="msg" @input="input" @change="change">
首先,sass和less都是css的预编译处理语言,他们引入了mixins,参数,嵌套规则,运算,颜色,名字空间,作用域,JavaScript赋值等 加快了css开发效率,当然这两者都可以配合gulp和grunt等前端构建工具使用,但是他们两者有什么不同呢?
1.编译环境不同
less是通过js编译 是在客户端处理
sass同通过ruby 是在服务器端处理
2.变量符不一样
less是用@,sass是用$
3.sass支持条件语句,可以使用if{}else{},for{}循环等等。而less不支持。
var 存在变量提升而let和const不存在变量提升
var存在变量覆盖,而let和const在同级作用域中不能重复定义
var声明的变量会挂载到window上,会放在全局,let 和 const声明的变量不会
let和const声明的变量会形成块级作用域,var不会
const有一个很好的应用场景,当我们引用第三方库的时声明的变量,用const来声明可以避免未来不小心重命名而导致出现bug
console.log(a);//undefined
var a = "hey I am now hoisting";
console.log(a);//Uncaught ReferenceError: a is not defined
let a = "hey I am now hoisting";
var a="show";
function hah(){
alert(a);//undefined
var a=4;
alert(a);//4
}
hah();
function hah(number){
var a="show";
while(number!=0){
alert(a);//show
var a=4;
alert(a);//4
number--;
}
}
hah(1);
$("#result").append(`
There are <b>${basket.count}</b> items
in your basket, <em>${basket.onSale}</em>
are on sale!
`);
function(x, y) {
x++;
y--;
return x + y;
}
(x, y) => {x++; y--; return x+y}
// 3.新增字符串方法
let str = "hello.vue";
// 开头
console.log(str.startsWith("hello"));//true
// 后缀
console.log(str.endsWith(".vue"));//true
// 包含
console.log(str.includes("e"));//true
console.log(str.includes("hello"));//true
当我们使用箭头函数时,函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,它的this是继承外面的,因此内部的this就是外层代码块的this
普通函数中的this总是代表它的直接调用者,在默认情况下,this指的是window
依赖管理:方便引用第三方模块、让模块更容易复用、避免全局注入导致的冲突、避免重复加载或加载不需要的模块。
合并代码:把各个分散的模块集中打包成大文件,减少 HTTP 的请求链接数,配合 UglifyJS 可以减少、优化代码的体积。
各路插件:babel 把 ES6+ 转译成 ES5 ,eslint 可以检查编译期的错误……
由于 webpack 并不支持除 .js 以外的文件,
从而需要使用 loader 转换成 webpack 支持的模块,
plugin 用于扩展 webpack 的功能,
在 webpack 构建生命周期的过程在合适的时机做了合适的事情。
简单的说就是分析代码,找到“require”、“exports”、“define”等关键词,并替换成对应模块的引用。
把你的项目当成一个整体,通过一个给定的主文件(index.js),
webpack将从这个文件开始找到你的项目的所有的依赖文件,
使用loaders处理他们,最后打包为一个浏览器可以识别的js文件
file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件
url-loader:和 file-loader 类似,但是能在文件很小的情况下以 base64 的方式把文件内容注入到代码中去
source-map-loader:加载额外的 Source Map 文件,以方便断点调试
image-loader:加载并且压缩图片文件
babel-loader:把 ES6 转换成 ES5
css-loader:加载 CSS,支持模块化、压缩、文件导入等特性
style-loader:把 CSS 代码注入到 JavaScript 中,通过 DOM 操作去加载 CSS。
eslint-loader:通过 ESLint 检查 JavaScript 代码
process.env是Node.js用于存放当前进程环境变量的对象;
而NODE_ENV则可以让开发者指定当前的运行时环境,
当它的值为production时即代表当前为生产环境
库和框架在打包时如果发现了它就可以去掉一些开发环境的代码,如警告信息和日志等。这将有助于提升代码运行速度和减小资源体积
首先可以优化Loader的搜索范围,只在src文件夹下查找,node_modules下的代码是编译过的,没必要再去处理一遍
使用HappyPack可以将Loader的同步执行转为并行,从而执行Loader时的编译等待时间
代码压缩相关,启用gzip压缩
概念
虚拟dom就是一个能代表dom树的js对象,通常含有标签名、标签属性还有一些子元素等等
优点
虚拟dom借助dom diff算法可以减少不必要的dom操作
diff算法是在新虚拟DOM和老虚拟DOM进行diff(精细化比对),实现最小量更新,最后反映到真正的DOM上
v-for默认使用就地复用策略,列表数据修改的时候,他会根据key值去判断某个值是否修改,
如果修改,则重新渲染这一项,否则复用之前的元素
key的作用主要是为了高效的更新虚拟DOM
不建议用index作为key值的原因
如果用index作为key导致的问题就是以前的数据和重新渲染后的数据随着 key 值的变化从而没法建立关联关系. 这就失去了 key 值存在的意义.
回调函数是作为参数传递给另一个函数的函数,然后在外部函数内调用该函数以完成某种例程或操作
函数作为参数层层嵌套就是回调地狱
promise对象采用链式的 then方法,可以指定一组按照次序调用的回调函数。
前一个 then 里的一个回调函数,返回的可能还是一个 Promise对象,(即有异步操作)这时后面的回调函数,就会等待该 Promise对象的状态发生变化才会被调用,由此实现异步操作按照次序执行。
Promise也有一些缺点。首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
// 采用ajax异步回调的方式改装成promise function getIp(){ var promise = new Promise(function(resolve,reject){ var xhr = new XMLHttpRequest() xhr.open('GET','https://easy-mock.com/mock/5ac2f80c3d211137b3f2843a/promise/getIp', true) //设置一个ajax的参数) xhr.onload = function(){ var retJson = JSON.parse(xhr.responseText) // {"ip":"58.100.211.137"} 数据到来对数据进行解析 resolve(retJson.ip) //初始化-完成状态-变为成功状态 } xhr.onerror = function(){ reject('获取IP失败') //初始化-拒绝状态-变为失败状态 } xhr.send() }) return promise } function getCityFromIp(ip){ var promise = new Promise(function(resolve,reject){ var xhr = new XMLHttpRequest() xhr.open('GET','https://easy-mock.com/mock/5ac2f80c3d211137b3f2843a/promise/getCityFromIp?ip='+ip, true) xhr.onload = function(){ var retJson = JSON.parse(xhr.responseText) // {"city": "hangzhou","ip": "23.45.12.34"} resolve(retJson.city) } xhr.onerror = function(){ reject('获取city失败') } xhr.send() }) return promise } function getWeatherFromCity(city){ var promise = new Promise(function(resolve,reject){ var xhr = new XMLHttpRequest() xhr.open('GET','https://easy-mock.com/mock/5ac2f80c3d211137b3f2843a/promise/getWeatherFromCity?city='+city, true) xhr.onload = function(){ var retJson = JSON.parse(xhr.responseText) // {"weather": "晴天","city": "beijing"} reslove(retJson) } xhr.onerror = function(){ reject('获取天气失败') } xhr.send() }) return promise } // getIp获取IP-IP获取城市-城市获取天气 getIp().then(function(ip){ return getCityFromIp(ip) // 得到ip }).then(function(city){ return getWeatherFromCity(city) // 得到城市 }).then(function(){ console.log(data) // 得到具体的城市其他状况(如天气、人口等等) }).catch(function(e){ console.log('出现了错误',e) })
Promise.all()
const p = Promise.all([p1, p2, p3]);
Promise.all方法接收一个数组作为参数,p1、p2、p3都是Promise实例。
当所有Promise对象都成功的时候,整个Promise.all才成功,
即Promise.all()方法会等指定的promise对象全部执行结束后才执行
Promise.race()
const p = Promise.race([p1, p2, p3]);
Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。
async函数
只要函数名之前加上async关键字,就表明该函数内部有异步操作。
该异步操作应该返回一个Promise对象,前面用await关键字注明。
当函数执行的时候,一旦遇到await就会先返回,等到触发的异步操作完成,再接着执行函数体内后面的语句
axios是通过promise实现对ajax技术的一种封装,就像jQuery实现ajax封装一样
axios({ url: '/getUsers', method: 'get', responseType: 'json', // 默认的 data: { //'a': 1, //'b': 2, } }).then(function (response) { console.log(response); console.log(response.data); }).catch(function (error) { console.log(error); })
$.ajax({
url: '/getUsers',
type: 'get',
dataType: 'json',
data: {
//'a': 1,
//'b': 2,
},
success: function (response) {
console.log(response);
}
})
从 node.js 创建 http 请求
支持 Promise API
客户端支持防止CSRF
提供了一些并发请求的接口
直接对对象属性进行添加和删除是不会响应到视图中的,需要用到this.$set()方法
由于 Vue 会在初始化实例时对属性执行 getter/setter 转化过程,所以属性必须在 data 对象上存在才能让 Vue 转换它,这样才能让它是响应的。
(1)路由传参的功能的坑。之前一直使用路由传参,但是当本页面刷新的时候,页面上是没有参数的,因为参数是从上个页面传入进来的。 解决办法:使用了缓存,和vuex状态管理。但是由于项目并不是很大型的项目,所以使用最多的是缓存。
(2)页面缓存的坑。有个填写信息的页面,需要填写一部分信息,进入查新协议页面,返回的时候,页面上填写的信息还需要留存。 解决办法:使用vue提供的keep-alive,来完成页面的缓存的。
v-if 和 v-show 区分使用场景
computed 和 watch 区分使用场景
v-for 遍历必须为 item 添加 key,且避免同时使用 v-if
长列表性能优化
事件的销毁
图片资源懒加载
路由懒加载
第三方插件的按需引入
优化无限列表性能
服务端渲染 SSR or 预渲染
Webpack 对图片进行压缩
减少 ES6 转为 ES5 的冗余代码
提取公共代码
模板预编译
提取组件的 CSS
优化 SourceMap
构建结果输出分析
Vue 项目的编译优化
因为js本身的特性带来的,如果data是一个对象,那么由于对象本身属于引用类型,当我们修改其中的一个属性时,会影响到所有vue实例的数据,如果将data作为一个函数返回一个对象,那么每一个实例的data属性是独立的,不会相互影响。
SPA( single-page application )仅在 Web 页面初始化时加载相应的 HTML、JavaScript 和 CSS。一旦页面加载完成,SPA 不会因为用户的操作而进行页面的重新加载或跳转;取而代之的是利用路由机制实现 HTML 内容的变换,UI 与用户的交互,避免页面的重新加载。
优点:
缺点:
1:hash 模式下,仅hash符号之前的内容会被包含在请求中,如http://www.abc.com,因此对于后端来说,即使没有做到对路由的全覆盖,也不会返回404错误。
history模式下,前端的URL必须和实际向后端发起请求的URL一致。
history 模式需要后端配合将所有访问都指向 index.html,否则用户刷新页面,会导致 404 错误
浏览器默认的 margin 和 padding 不同。解决方案是加一个全局的 *{margin: 0; padding: 0;} 来统一。
IE下 event 对象有 event.x,event.y 属性,而 Firefox 下没有。Firefox 下有 event.pageX,event.PageY 属性,而 IE 下没有。 解决办法:var mx = event.x?event.x:event.pageX;
Chrome 中文界面下默认会将小于 12px 的文本强制按照 12px 显示, 可通过加入 CSS 属性 -webkit-text-size-adjust: none; 解决.
超链接访问过后 hover 样式就不出现了,被点击访问过的超链接样式不在具有 hover 和 active 了,解决方法是改变 CSS 属性的排列顺序: L-V-H-A : a:link {} a:visited {} a:hover {} a:active {}
1** 信息,服务器收到请求,需要请求者继续执行操作
2** 成功,操作被成功接收并处理
3** 重定向,需要进一步的操作以完成请求
4** 客户端错误,请求包含语法错误或无法完成请求
5** 服务器错误,服务器在处理请求的过程中发生了错误
301 Moved Permanently 永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替
302 Found 临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI
304 Not Modified 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源
400 Bad Request 客户端请求的语法错误,服务器无法理解
401 Unauthorized 请求要求用户的身份认证
403 Forbidden 服务器理解请求客户端的请求,但是拒绝执行此请求
404 Not Found 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。
它是基于 JavaScript 的一个子集。
数据格式简单,易于读写,占用带宽小。
格式:采用键值对。例如:{ “age‟: ‟12‟, ”name‟: ‟back‟ }
web 前端是应用服务器处理之前的部分,前端主要包括:HTML、CSS、javascript、image 等各种资源,针对不同的资源有不同的优化方式。
合并多个 CSS 文件和js 文件,
利用 CSS Sprites 整合图像,Inline Images (使用 data:URL scheme在实际的页面嵌入图像数据 ),
合理设置 HTTP 缓存等。
减小 Cookie 大小
针对 Web 组件使用域名无关的 Cookie
CSS 优化
将 CSS 代码放在 HTML 页面的顶部
避免使用 CSS 表达式
使用 < link> 来代替 @import
避免使用 Filters
优化图片大小
通过 CSS Sprites 优化图片
不要在 HTML 中使用缩放图片
favicon.ico 要小而且可缓存
onload 是等 HTML 的所有资源都加载完成后再执行 onload 里面的内容,所有资源包括 DOM 结构、图片、视频 等资源;
ready 是当 DOM 结构加载完成后就可以执行了,相当于 jQuery 中的 $(function(){ js 代码 });
另外,onload 只能有一个,ready 可以有多个。
所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
/** * @desc 函数防抖 * @param func 函数 * @param wait 延迟执行毫秒数 * @param immediate true 表立即执行,false 表非立即执行 */ function debounce(func,wait,immediate) { let timeout; return function () { let context = this; let args = arguments; if (timeout) clearTimeout(timeout); if (immediate) { var callNow = !timeout; timeout = setTimeout(() => { timeout = null; }, wait) if (callNow) func.apply(context, args) } else { timeout = setTimeout(function(){ func.apply(context, args) }, wait); } } }
简单版
function debounce(fn,wait){
let timeOut = null
return args =>{
if(timeOut) clearTimeout(timeOut)
timeOut = setTimeout(fn,wait)
}
}
所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数。节流会稀释函数的执行频率。
对于节流,一般有两种方式可以实现,分别是时间戳版和定时器版。
function throttle(func, wait) {
let timeout;
return function() {
let context = this;
let args = arguments;
if (!timeout) {
timeout = setTimeout(() => {
timeout = null;
func.apply(context, args)
}, wait)
}
}
}
防抖应用场景
文本输入搜索联想
文本输入验证(包括 Ajax 后端验证)
节流应用场景
鼠标点击
监听滚动 scroll
窗口 resize
mousemove 拖拽
图片进行懒加载或者延迟加载。
对于多次http请求的数据,用localStorage或者sessionStorage进行缓存。
对ui框架使用按需加载。
使用防抖节流尽可能地减少http请求
使用事件委托尽量减少直接操作dom节点,事件委托就是通过事件冒泡的原理,利用父级去触发子级的事件(即事件绑定在父节点上)
//1、在index.html中cdn引入
<script src="//cdn.bootcss.com/vue/2.2.5/vue.min.js"></script>
<script src="//cdn.bootcss.com/vue-router/2.3.0/vue-router.min.js"></script>
<script src="//cdn.bootcss.com/vuex/2.2.1/vuex.min.js"></script>
<script src="//cdn.bootcss.com/axios/0.15.3/axios.min.js"></script>
<script src="https://cdn.bootcss.com/element-ui/2.12.0/index.js"></script>
<script src="https://cdn.bootcss.com/element-ui/2.12.0/locale/zh-CN.js"></script>
2、在vue.config.js中配置
config.externals({
'vue': 'Vue',
'vue-router': 'VueRouter',
'Vuex': "Vuex",
// 'store': 'store',
'axios': 'axios',
'element-ui': 'ELEMENT'
})
Vue 会通过 Object.defineProperty 对数据进行劫持,来实现视图响应数据的变化,然而有些时候我们的组件就是纯粹的数据展示,不会有任何改变,我们就不需要 Vue 来劫持我们的数据,在大量数据展示的情况下,这能够很明显的减少组件初始化的时间,那如何禁止 Vue 劫持我们的数据呢?可以通过 Object.freeze 方法来冻结一个对象,一旦被冻结的对象就再也不能被修改了。
export default {
data: () => ({
users: {}
}),
async created() {
const users = await axios.get("/api/users");
this.users = Object.freeze(users);
}
};
可以借助lodash和moment等工具库
Lodash内部封装了诸多对字符串、数组、对象等常见数据类型的处理函数
momen.js是日期处理类库
export default { data(){ return{ } } }, /// 取而代之是使用以下的方式去初始化数据: <template> <div class="hello"> 123 </div> <div>{{name.name}}</div> </template> import {reactive} from 'vue' export default { setup(){ const name = reactive({ name:'hello 番茄' }) return {name} } }
在新版当中setup等效于之前2.0版本当中得到beforeCreate,和created,它是在组件初始化的时候执行,甚至是比created更早执行。值得注意的是,在3.0当中如果你要想使用setup里的数据,你需要将用到值return出来,返回出来的值在模板当中都是可以使用的
created -> 请使用 setup()
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeDestroy -> onBeforeUnmount
destroyed -> onUnmounted
如果要想在页面中使用生命周期函数的,根据以往2.0的操作是直接在页面中写入生命周期,而现在是需要去引用的,这就是为什么3.0能够将代码压缩到更低的原因
// Vue3
import { ref } from 'vue'
export default {
setup () {
const count = ref(0) // 声明 count,初始值为 0
const str = ref('hello') // 声明 str,初始值为 'hello'
return {
count,
str
}
}
}
我们要先引入 ref 方法,然后使用它来声明响应式变量。重要的是,这些操作需要在 setup 函数中进行,而且添加 methods,watch 和 computed 都需要在 setup 中进行
Vue组件分为全局注册和局部注册,在react中都是通过import相应组件,然后模版中引用;
每个Vue实例都实现了事件接口,方便父子组件通信,小型项目中不需要引入状态管理机制,而react必需自己实现;
多了指令系统,让模版可以实现更丰富的功能,而React只能使用JSX语法;
Vue增加的语法糖computed和watch,而在React中需要自己写一套逻辑来实现;
react做的事情很少,很多都交给社区去做,vue很多东西都是内置的,写起来确实方便一些, 比如 redux的combineReducer就对应vuex的modules, 比如reselect就对应vuex的getter和vue组件的computed, vuex的mutation是直接改变的原始数据,而redux的reducer是返回一个全新的state,所以redux结合immutable来优化性能,vue不需要。
react是整体的思路的就是函数式,所以推崇纯组件,数据不可变,单向数据流,当然需要双向的地方也可以做到,比如结合redux-form,组件的横向拆分一般是通过高阶组件。而vue是数据可变的,双向绑定,声明式的写法,vue组件的横向拆分很多情况下用mixin。
模板语法的不同:
react通过JSX渲染模板,vue通过拓展的html语法进行渲染。
比如react中插值、条件、循环都通过JS语法实现,
vue是通过指令v-bind、v-if、v-for实现的。
监听数据变化原理不同:
vue通过getter、setter劫持通知数据变化,
react通过比较引用的方式进行。
vue使用的响应式数据,而react是不可变数据。
vue改变数据直接赋值,react需要调用setState方法(用新的state替换旧的state)。
H5新特性
1. 语义化更好的内容标签(header,nav,footer,aside,article,section)
2. 音频、视频API(audio,video)
3. 画布(Canvas) API
4. 数据存储 localStorage、sessionStorage
5. 表单控件,calendar、date、time、email、url、search
CSS3新特性
1. 文字阴影(text-shadow)
2. 边框: 圆角(border-radius)边框阴影: box-shadow
3. 盒子模型:box-sizing
4. 过渡:transition,可实现动画
5. 媒体查询,多栏布局
6. 2D转换:transform:translate(x,y) rotate(x,y) skew(x,y) scale(x,y)
7.新增选择器:属性选择器、伪类选择器、伪元素选择器。
rem是相对于根元素也就是 html的字体大小的单位
只要我们根据不同屏幕设定好根元素的font-size,其他已经使用了rem单位的元素就会自适应显示相应的尺寸了
const oHtml = document.getElementsByTagName('html')[0]
const width = oHtml.clientWidth;
// 320px的屏幕基准像素为12px
oHtml.style.fontSize = 12 * (width / 320) + "px";
@media screen and (min-width: 375px){ html { font-size: 14.0625px; } } @media screen and (min-width: 360px){ html { font-size: 13.5px; } } @media screen and (min-width: 320px){ html { font-size: 12px; } } html { font-size: 16px; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。