-
Vue2数据双向绑定的原理
Vue2 数据双向绑定原理是通过数据劫持 + 发布者-订阅者模式 的方式来实现,首先是通过 ES5 提供的 Object.defineProperty() 方法来劫持(监听)各属性的 getter、setter,并在当监听的属性发生变动时通知订阅者,是否需要更新,若更新就会执行对应的更新函数。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>title</title> </head> <body> <div> <!-- 发布者 --> <input type="text" class="publisher"> <!-- 订阅者 --> <div class="subscriber">我是订阅者</div> </div> <script> // 目标对象 let Target = {} <!-- 发布对象 --> let pub= document.querySelector('.publisher') <!-- 订阅对象 --> let sub= document.querySelector('.subscriber') //数据对象属性‘劫持’过程:Object.defineProperty() 方法劫持(监听)Target属性的 get、set Object.defineProperty(Target, 'msg', { get() { return console.log('访问了Target.msg的值,触发了get方法') }, set(value) { //2.Target的属性msg值改变会触发这个回调,带修改的这个值value过来了 console.log('修改了Target.msg的值,触发了set方法', value) //3.然后修改需要改变的数据sub对象,ok,实现发布者的值改变后,订阅者的数据同步改变 sub.innerHTML = value } }) // 1.监听器,监听发布者,监听pub对象的input输入事件,触发回调,回调中给对象Target的属性msg 赋值 pub.addEventListener('input', (e) => { Target.msg = e.target.value }) </script> </body> </html>
Object.getOwnPropertyDescriptor
对象原型的toString方法,以及数组的length属性都是不可枚举的。
对象的每个属性都有一个描述对象(Descriptor),用来控制该属性的行为。Object.getOwnPropertyDescriptor方法可以获取该属性的描述对象。
let obj = { foo: 123 }; //打印obj对象的foo属性的描述对象 Object.getOwnPropertyDescriptor(obj, 'foo') //输出的对象: // { // value: 123, // writable: true, // enumerable: true, 是否可以枚举 // configurable: true // } //Object的原型toString属性是不可枚举 Object.getOwnPropertyDescriptor(Object.prototype, 'toString').enumerable // false //数组的长度length属性是不可枚举 Object.getOwnPropertyDescriptor([], 'length').enumerable // false
$route 和 $router的区别
$router 是VueRouter的实例,在script标签中想要导航到不同的URL,使用 $router.push方法
$route为router跳转对象,里面可以获取当前路由的name,path,query,parmas等。
路由懒加载
方法一 resolve
import Vue from 'vue' import Router from 'vue-router' Vue.use(Router) export default new Router({ routes: [ { path: '/', name: 'HelloWorld', component: resolve => require(['@/components/HelloWorld'], resolve) } ] })
方法二.import按需加载(官方写法)
const comA = () => import('url') const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
方法三 webpack提供的require.ensure()
{ path: '/home', name: 'home', component: r =>require.ensure([], () => r(require('@/components/home')), 'demo') }
.vue文件组成部分
1.<template>所需要渲染的区域</template>
2.<script>存放引入的资源与业务实现的数据与操作</script>
3.<style>存放界面css的样式</style>
scoped作用与原理
组件css作用域,避免子组件内部的css样式被父组件覆盖,起到隔离的作用。
组件通信有哪些方式
- 通过 props 传递
- 通过 $emit 触发自定义事件
- 使用 ref
- EventBus
- $parent 或$root
- attrs 与 listeners
- Provide 与 Inject
- Vuex
data属性是一个函数而不是一个对象原因
每次调用产生一个新的地址空间防止数据被污染。
vue生命周期
- 创建vue实例对象: beforeCreate、 created
- 挂载dom节点 : beforeMount、mounted
- 数据更新 : beforeUpdate、updated
activated: 被 keep-alive 缓存的组件激活时调用
deactivated: 被 keep-alive 缓存的组件失活时调用
- 组件销毁: beforeDestroy、destroyed
父子组件生命周期构造函数执行顺序
加载渲染过程: 父 beforecreate,created,beforeMount 子 beforecreate,created,beforeMount 子 mounted 父 mounted 子组件更新过程: 父 beforeUpdate 子 beforeUpdate 子 Updated 父 Updated 销毁过程: 父 beforeDestroy 子 beforeDestroy 子 destroyed 父 destroyed 如果常用的数据如果需要传递到子组件的话,最好在created 或者 beforemount,把数据请求回来,然后传递给子组件。
axios
axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,简单的理解就是ajax的封装。
post请求的时候参数通过data进行传递
其他请求的时候参数通过params进行传递//get请求方式: axios.get("api", { // 传递参数 params: { key: value }, // 设置请求头信息,可以传递空值 headers: { key: value } }).then((response) => { // 请求成功 let res = response.data; console.log(res); }).catch(error => { // 请求失败, console.log(error); }); //post请求方式: let data = { key: value }, headers = { USERID: "", TOKEN: "" }; // 若无headers信息时,可传空对象占用参数位置 axios.post("api", qs.stringify(data), { headers } }).then((response) => { // 请求成功 let res = response.data; console.log(res); }).catch((error) => { // 请求失败, console.log(error); });
/**** 以下简单封装axios request.js ****/ // 导入axios import axios from 'axios' import { Message} from 'element-ui' //1. 创建新的axios实例, const service = axios.create({ // 公共接口 baseURL: process.env.BASE_API, // 超时时间 单位是ms timeout: 3 * 1000 }) // 2.请求拦截器 service.interceptors.request.use(config => { config.data = JSON.stringify(config.data); //数据转化,也可以使用qs转换 config.headers = { 'Content-Type':'application/json' //配置请求头 } //如有需要:注意使用token的时候需要引入cookie方法或者用本地localStorage等方法,推荐js-cookie //const token = getCookie('名称');//这里取token之前,你肯定需要先拿到token,存一下 //if(token){ //config.params = {'token':token} //如果要求携带在参数中 //config.headers.token= token; //如果要求携带在请求头中 //} return config }, error => { Promise.reject(error) }) // 3.响应拦截器 service.interceptors.response.use(response => { //接收到响应数据并成功后的一些共有的处理,关闭loading等 return response }, error => { /***** 接收到异常响应的处理开始 *****/ if (error && error.response) { // 1.公共错误处理 // 2.根据响应码具体处理 switch (error.response.status) { case 400: error.message = '错误请求' break; case 401: error.message = '未授权,请重新登录' break; case 403: error.message = '拒绝访问' break; case 404: error.message = '请求错误,未找到该资源' window.location.href = "/NotFound" break; case 405: error.message = '请求方法未允许' break; case 408: error.message = '请求超时' break; case 500: error.message = '服务器端出错' break; case 501: error.message = '网络未实现' break; case 502: error.message = '网络错误' break; case 503: error.message = '服务不可用' break; case 504: error.message = '网络超时' break; case 505: error.message = 'http版本不支持该请求' break; default: error.message = `连接错误${error.response.status}` } } else { // 超时处理 if (JSON.stringify(error).includes('timeout')) { Message.error('服务器响应超时,请刷新当前页') } error.message = '连接服务器失败' } Message.error(error.message) return Promise.resolve(error.response) }) var config = { meth