titel:Vue 核心
渐进式 JavaScript 框架,用来动态构建用户界面
特点
与其他前端 JS 框架的关联
Vue 扩展插件、
】、
引入Vue.js
创建 Vue 对象
el:指定根 element (选择器)
data:初始化数据(页面可以访问)
双向数据绑定:v-model
显示数据:{ {xxx}}
理解 vue 的 mvvm 实现
hello {
{msg}}
MVVM --> model-view-viewModel
model:模型,数据对象(data)
view:视图,模板页面
viewModel:视图模型(vue 的实例)
MVVM 本质上是 MVC (Model-View- Controller)的改进版。即模型-视图-视图模型。
模型
指的是后端传递的数据,视图
指的是所看到的页面。
视图模型
是 mvvm 模式的核心,它是连接 view 和 model 的桥梁。它有两个方向:
模型
转化成视图
,即将后端传递的数据转化成所看到的页面。实现的方式是:数据绑定。视图
转化成模型
,即将所看到的页面转化成后端的数据。实现的方式是:DOM 事件监听。这两个方向都实现的,我们称之为数据的双向绑定。
模板的理解
双大括号表达式
指令一:强制数据绑定
功能:指定变化的属性值
完整写法:v-bind:xxx=‘yyy’ //yyy会作为表达式解析执行
简洁写法::xxx=‘yyy’
第一种
:title="`字符串${xx}`"
第二种
:title="'字符串' + xx"
指令二:绑定事件监听
功能:绑定指定事件名的回调函数
完整写法:v-on:keyup=‘xxx’,v-on:keyup=‘xxx(参数)’,v-on:keyup.enter=‘xxx’
简洁写法:@keyup=‘xxx’,@keyup.enter=‘xxx’
原理为Object.defineProperty()
计算属性
监视属性a
通过 vm 对象的 $watch()
或 watch 配置
来监视指定的属性
当属性变化时,回调函数自动调用,在函数内部进行计算
vm监视data中数据的特点
所有层次属性会监视
对象内部也会监视 对象属性添加set方法
数组内部元素监视 重写数组原型方法 1、调用原有方法处理数据 2、更新界面
计算属性高级
class 绑定::class='xxx'
:style="{ color: activeColor, fontSize: fontSize + 'px' }"
如果需要频繁切换 v-show 较好。当条件不成立时, v-if 的所有子节点不会解析。
列表显示指令:
列表的更新显示:
1.删除item:变更方法,顾名思义,会变更调用了这些方法的原始数组。
// 两种更新方式
this.persons[index] = newP
// 这样只更新persons中的某一个数据,vue根本就不知道,视图不会更新
this.persons.splice(index, 1, newP)
// splice方法被 Vue 将进行了包裹,所以也将会触发视图更新。
这些被包裹过的方法包括:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
2.替换item:相比之下,也有非变更方法,例如 filter()
、concat()
和 slice()
。它们不会变更原始数组,而总是返回一个新数组。当使用非变更方法时,可以用新数组替换旧数组。
let fpersons = persons.filter(
p => p.name.includes(searchName)
)
列表的高级处理:
列表过滤
filterPerson(){
//得到依赖数据
const{searchName ,persons}=this
//进行计算处理,产生结果数据返回
过滤
consr arr=persons.filter(p=>p.name.indexOf(searchName)>=0)
return arr
}
列表排序
fpersons.sort(function (p1, p2) {
if (orderType === 1) { // 降序
return p2.age - p1.age
} else { // 升序
return p1.age - p2.age
}
})
$event
就是当前触发事件的元素,即使不传 $event
,在回调函数中也可以使用 event 这个参数。
事件修饰符用来控制事件的冒泡和默认行为。
使用 v-model 对表单数据自动收集
vue 生命周期分析
常用的生命周期方法
vue 动画的理解
操作 css 的 transition 或 animation
vue 会给目标元素添加/移除特定的 class
过渡的相关类名
xxx-enter-active:指定显示的 transition
xxx-leave-active:指定隐藏的 transition
xxx-enter/xxx-leave-to:指定隐藏时的样式
基本过渡动画的编码
在目标元素外包裹
定义 class 样式
指定过渡样式:transition
指定隐藏时的样式:opacity/其它
理解过滤器
功能: 对要显示的数据进行特定格式化后再显示(比如日期格式)
注意: 并没有改变原本的数据, 可是产生新的对应的数据
定义和使用过滤器
定义过滤器:
Vue.filter(filterName, function(value[,arg1,arg2,...]){
// 进行一定的数据处理
return newValue
})
使用过滤器 :
其中,myData 会作为 value 传入 filter 中。
v-text : 更新元素的 textContent
v-html : 更新元素的 innerHTML
v-text和{ {}}表达式渲染数据,不解析标签。
v-html不仅可以渲染数据,而且可以解析标签。
v-if : 如果为 true, 当前标签才会输出到页面
v-else: 如果为 false, 当前标签才会输出到页面
v-show : 通过控制 display 样式来控制显示/隐藏
v-for : 遍历数组/对象
v-on : 绑定事件监听, 一般简写为@
v-bind : 强制绑定解析表达式, 可以省略 v-bind:
v-model : 双向数据绑定
ref : 指定唯一标识, vue 对象通过$els 属性访问这个元素对象
ref 被用来给DOM元素或子组件注册引用信息。引用信息会根据父组件的 $refs 对象进行注册。如果在普通的DOM元素上使用,引用信息就是元素; 如果用在子组件上,引用信息就是组件实例注意:只要想要在Vue中直接操作DOM元素,就必须用ref属性进行注册
el:指令所在的标签对象
binding:包含指令相关数据的容器对象
Vue.directive('my-directive', function(el, binding){
el.innerHTML = binding.value.toupperCase()
})
directives: {
'my-directive'(el, binding) {
el.innerHTML = binding.value.toupperCase()
}
}
(binding.value 就是 xxx 的值)
说明
Vue 插件是一个包含 install 方法的对象
通过 install 方法给 Vue 或 Vue 实例添加方法,定义全局
(function(window){
const MyPlugin={}//定义插件对象
MyPlugin.install = function (Vue, options) {
// 1. 添加全局方法或 property
Vue.myGlobalMethod = function () {
// 逻辑...
}
// 2. 添加全局资源
Vue.directive('my-directive', {
bind (el, binding, vnode, oldVnode) {
// 逻辑...
}
...
})
// 3. 注入组件选项
Vue.mixin({
created: function () {
// 逻辑...
}
...
})
// 4. 添加实例方法
Vue.prototype.$myMethod = function (methodOptions) {
// 逻辑...
}
}
暴漏插件
window.MyPlugin=MyPlugin
})(window)
用法:将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。它跟全局方法 Vue.nextTick
一样,不同的是回调的 this
自动绑定到调用它的实例上。
用途:需要在视图更新之后,基于新的视图进行操作。
//改变数据
vm.message = 'changed'
//想要立即使用更新后的DOM。这样不行,因为设置message后DOM还没有更新
console.log(vm.$el.textContent) // 并不会得到'changed'
//这样可以,nextTick里面的代码会在DOM更新后执行
Vue.nextTick(function(){
console.log(vm.$el.textContent) //可以得到'changed'
})
保证该组件的多个实例都有自己独立的data对象
有的时候,在不同组件之间进行动态切换是非常有用的,比如在一个多标签的界面里切换组件
可以通过 Vue 的
元素加一个特殊的 is
attribute 来实现:
在上述示例中,currentTabComponent
可以包括
缓存组件
异步组件
在需要组件的时候 ,才异步请求加载组件的代码(后台)
Vue能够将组件定义为一个工厂函数,此函数可以异步解析组件
import()语法比较适合的是路由的异步懒加载
组件间通信基本原则
使用组件标签时:
定义 MyComponent 时:
1.在组件内声明所有的 props:
// 方式一:只指定名称
props: ['name', 'age', 'setName']
// 方式二:指定名称和类型
props: {
name: String,
age: Number,
setNmae: Function
}
// 方式三:指定名称/类型/必要性/默认值
props: {
name: {type: String, required: true, default:xxx},
}
注意
绑定事件监听(绑定在父组件中)
// 方式一: 通过v-on 绑定
@delete_todo="deleteTodo"
// 方式二: 通过$on()
mounted () {
this.$refs.header.$on('delete_todo', this.deleteTodo)
}
触发事件(写在子组件中)
// 触发事件(只能在父组件中接收)
this.$emit('delete_todo', data)
注意
订阅消息
PubSub.subscribe('msg', function(msg, data){//对象
...
})
发布消息
PubSub.publish('msg', data)//异步发布
PubSub.publishSync('MY TOPIC', 'hello world!');//同步发布
注意
此方式用于父组件向子组件传递标签数据
子组件: Child.vue
不确定的标签结构1
组件确定的标签结构
不确定的标签结构2
父组件: Parent.vue
xxx 对应的标签结构
yyyy 对应的标签结构
为脚手架添加 axios 模块
1.本地安装 axios 模块:
npm i -save axios
2.在脚手架项目源代码的 src/main.js 中,new Vue() 前引入 axios 模块
import axios from "axios"
// node_modules中安装的模块,引入时都不用加路径
3.设置 axios 对象的基础路径属性:
axios.defaults.baseURL="http://服务器端域名"
4.将 axios 对象放入 Vue 的原型对象中
Vue.prototype.axios = axios;
5.结果:因为所有组件对象都是 Vue 类型的子对象,所以在所有组件内,任何位置都可用 this.$axios.get()
和 this.$axios.post()
访问 Vue.prototype 中的 axios 对象里的函数。
// 发送 ajax 请求
this.$axios.get('/index')
.then(response => {
console.log(response.data) // 得到返回结果数据
})
.catch(error => {
console.log(error.message)
})
let data = {
pagenum: 1
};
this.$axios
.post("/users/signin", data)
.then(res=>{
console.log(res.data);
})
.catch(err => {
console.log(err.message);
});
在 main.js 文件中
// 原始写法
new Vue({
el: '#app',
components: { // 将App.vue映射成标签
APP
},
template: ' ', // 将App标签转化成模板
})
// 更简洁的写法
new Vue({
el: '#app',
render: h => h(App),
})
render 是一个渲染函数,h => h(App) 是一个箭头函数,其参数 h 是一个函数,这个函数执行接收一个参数 App 组件。
h(App) 执行后返回的结果就是 render 的值。
也就是:
new Vue({
el: '#app',
render: function (createElement) { // h就是createElement,用来创建元素标签
return createElement(App) //
},
})
// 其中App标签被插入到el中
官方提供的用来实现 SPA 的 vue 插件。
1.注册路由器(在 main.js)
import Vue from 'vue'
import router from './router'
// 创建vue 配置路由器
new Vue({
el: '#app',
router,
render: h => h(app)
})
2.路由器配置:(在 router 目录下 index.js)
import Vue from "vue";
import VueRouter from "vue-router";
Vue.use(VueRouter);
3.路由配置:
const routes = [
{
path: '/home',
component: home,
// 嵌套路由
children: [
{
path: 'news',
component: News
},
{
path: 'message',
component: Message
}
]
},
{
// 一般路由
path: 'about',
component: About
},
{
// 自动跳转路由
path: '/',
redirect: '/about'
}
]
3.VueRouter():用于创建路由器的构建函数
const router = new VueRouter({
mode: "history", // 模式
base: process.env.BASE_URL,
routes
});
export default router;
4.使用路由组件标签
:用来生成路由链接
它默认会被渲染成一个带有链接的a标签,通过to属性指定链接地址。
注意:被选中的router-link将自动添加一个class属性值.router-link-active。
:用于渲染匹配到的组件。
children: [
{
path: 'mdetail/:id',
component: MessageDetail
}
]
{
{m.title}}
this.$route.params.id
属性携带数据
前后端分离 ===> 利用Ajax,可以在不刷新浏览器的情况下异步数据请求交互。
单页应用(只有一个html文件,整个网站的所有内容都在这一个html里,通过js来处理)不仅仅是在页面交互是无刷新的,连页面跳转都是无刷新的。为了实现单页应用 ==> 前后端分离 + 前端路由。(更新视图但不重新请求页面)
前端路由实现起来其实也很简单,就是匹配不同的 url 路径,进行解析,加载不同的组件,然后动态的渲染出区域 html 内容。
vue-router 默认 hash 模式,还有一种是 history 模式。
只能改变 # 后面的 url 片段即 hash 值。hash 值的变化,并不会导致浏览器向服务器发出请求,浏览器不发出请求,也就不会刷新页面。每次 hash 值的变化,会触发 hashchange
这个事件,通过这个事件我们就可以知道 hash 值发生了哪些变化。然后我们便可以监听 hashchange
来实现更新页面部分内容的操作:
hash 模式的工作原理是 hashchange 事件,可以在 window 监听 hash 的变化。
在 url 后面随便添加一个 #xx 会触发 onhashchange 事件。打印 event,里边有两个属 性 newURL 和 oldURL。可以通过模拟改变 hash 的值,动态改变页面数据。
HashHistory 的方法
this.$router.push(path)
:相当于点击路由链接(可以返回到当前路由界面)this.$router.replace(path)
:用新路由替换当前路由(不可以返回到当前路由界面)3)this.$router.back()
:请求(返回)上一个记录路由
4) this.$router.go(-1)
:请求(返回)上一个记录路由
5) this.$router.go(1)
:请求下一个记录路由
因为 hash 发生变化的 url 都会被浏览器记录(历史访问栈)下来,从而你会发现浏览器的前进后退都可以用了。尽管浏览器没有请求服务器,但是页面状态和 url 已经关联起来了,这就是所谓的前端路由,单页应用的标配。
前面的 hashchange,只能改变 # 后面的 url 片段,而 history api 则给了前端完全的自由。
通过history api,我们丢掉了丑陋的 #,但是它也有个毛病:
不怕前进,不怕后退,就怕f5刷新,刷新是实实在在地去请求服务器的。在 hash 模式下,前端路由修改的是 # 中的信息,而浏览器请求时是跟它无关的,所以没有问题。
但是在 history 下,你可以自由的修改 path,当刷新时,如果服务器中没有相应的响应或者资源,会刷出404来。
解决刷新404问题
路径不带# http://localhost:5000/home/views
发送的请求路径 http://localhost:5000/home/views
响应404错误
希望:如果没有对应的资源返回index页面 path部分被解析成前台路由路径 http://localhost:5000
解决 添加配置
当使用 HTML5 History API 时,任意的 404
响应都可能需要被替代为 index.html
。通过传入以下启用:
historyApiFallback: true 注意资源引用路径问题
output:publicPath:'/' 引入的打包路径以/开头
多了两个 API,pushState()
和 replaceState()。
通过这两个 API:
1)可以改变 url 地址且不会发送请求
2)不仅可以读取历史记录栈,还可以对浏览器历史记录栈进行修改。
window.history.pushState(stateObject, title, URL)
window.history.replaceState(stateObject, title, URL)
history.go(-2);//后退两次
history.go(2);//前进两次
history.back(); //后退
hsitory.forward(); //前进
$router
与$route
的区别$route
是一个跳转的路由对象,每一个路由都会有一个 route 对象,是一个局部的对象。可以获取对应的 name、path、query、params 等(
传的参数由 this.$route.query
或者 this.$route.params
接收)$router
为通过 Vue.use(VueRouter) 和 VueRouter 构造函数得到的一个 router 的实例对象,这个对象是一个全局的对象。想要导航到不同 URL,则使用$router.push
方法;返回上一个 history 也是使用$router.go
方法
vuex 是什么:对 vue 应用中多个组件的共享状态进行集中式的管理(读/写)
状态自管理应用:
多组件共享状态的问题:
以前的解决办法:
vuex 就是用来解决这个问题的。
vuex 管理的状态对象。它应该是唯一的:
const state = {
xxx: initValue
}
包含多个计算属性(get)的对象
由谁读取:组件中 $store.getters.xxx
const getters = {
nnn(state) {
return ...
}
mmm(state, getters) {
return getters.nnn...
//注意:引入getters时,必须放在第二位,因为第一位默认是state
}
}
包含多个事件回调函数的对象。通过执行 commit()
来触发 mutation 的调用,间接更新 state。
由谁触发:组件中 $store.dispatch('action 名称', data1)
// ‘zzz’
可以包含异步代码(定时器,ajax)
const actions = {
zzz ({commit, state}, data1) {
commit('yyy', {data1}) // 传递数据必须用大括号包裹住
}
}
包含多个直接更新 state 的方法(回调函数)的对象。
由谁触发:action 中的 commit('mutation 名称')
来触发。
只能包含同步的代码,不能写异步代码。
const mutations = {
yyy (state, {data1}) { // 传递数据必须用大括号包裹住
// 更新 state 的某个属性
}
}
包含多个 module。一个 module 是一个 store 的配置对象,与一个组件(包含有共享数据)对应
index.js 固定写法:
import Vue from 'vue'
import Vuex from 'vuex'
import state from './state'
import mutations from './mutations'
import actions from './actions'
import getters from './getters'
Vue.use(Vuex)
export default new Vuex.store({
state,
mutations,
actions,
getters
})
{
{xxx}} {
{mmm}} @click="zzz(data)"
import {mapState. mapGetters, mapActions} from 'vuex'
export default{
computed: {
...mapState(['xxx']), //相当于 this.$store.state.xxx
...mapGetters(['mmm']), //相当于 this.$store.getters['mmm']
},
methods: {
...mapActions(['zzz']) //相当于 this.$store.dispatch('zzz')
}
}
在 main.js 中
import store from './store'
new Vue({
store
})
1.所有用 vuex 管理的组件中都多了一个属性 $store,它就是一个 store 对象
2.属性:
state:注册的 state 对象
getters:注册的 getters 对象
3.方法:
dispatch(actionName, data):分发调用 action
分析 vue 作为一个MVVM 框架的基本实现原理
1.[].slice.call(this) 将伪数组转换为真数组
2、node.nodeType 得到节点类型
3、Object.defineProperty(obj,propertyName,{}) 给对象添加属性
3、Object.keys(obj) 得到对象自身可以枚举属性组成的数组
5、obj.hasOwnProperty(prop) 判断prop是否是obj的属性
6、DocumentFragment 文档碎片 高效批量更新多个节点
数据代理:通过一个对象代理对另一个对象(在前一个对象内部)中属性的操作(读/写)
vue 数据代理:data 对象的所有属性的操作(读/写)由 vm 对象来代理操作
好处:通过 vm 对象就可以方便的操作 data 中的数据
基本实现流程:
将 el 的所有子节点取出,添加到一个新建的文档 fragment 对象中
对 fragment 中的所有层次子节点递归进行编译解析处理
得到指令名和指令值(表达式) text/html/class msg/myClass
从 data 中根据表达式得到对应的值
根据指令名确定需要操作元素节点的什么属性
将得到的表达式的值设置到对应的属性上
移除元素的指令属性
数据绑定
一旦更新了 data 中的某个属性数据,所有界面上直接使用或间接使用了此属性的节点都会更新。
数据劫持
实现数据的绑定,首先要对数据进行劫持监听,所以我们需要设置一个监听器 Observer,用来监听所有属性。
如果属性发生变化了,就需要告诉订阅者 Watcher 看是否需要更新。因为订阅者是有很多个,所以我们需要有一个消息订阅器 Dep 来专门收集这些订阅者,然后在监听器 Observer 和订阅 Watcher 之间进行统一管理。
接着,我们还需要有一个指令解析器 Compile,对每个节点元素进行扫描和解析,将相关指令对应初始化成一个订阅者 Watcher,并替换模板数据或者绑定相应的函数。此时当订阅者 Watcher 接收到相应属性的变化,就会执行对应的更新函数,从而更新视图。
1.用来对 data 所有属性数据进行劫持的构造函数
2.给 data 中所有属性重新定义属性描述(get/set)
3.为 data 中的每个属性创建对应的 dep 对象
1.data 中的每个属性(所有层次)都对应一个 dep 对象
2.创建的时机:
3.对象的结构
function Dep() {
// 标识属性
this.id = uid++; // 每个dep都有一个唯一的id
// 相关的所有watcher的数组
this.subs = []; //包含n个对应watcher的数组(subscribes的简写)
}
{
this.id = uid++,
this.subs = []
}
4.subs 属性说明
1.模板中每个非事件指令或表达式都对应一个 watcher 对象
2.监视当前表达式数据的变化
3.创建的时机:在初始化编译模板时(compiler中)
4.对象的组成
function Watcher(vm, exp, cb){
this.vm = vm; // vm 对象
this.exp = exp; // 对应指令的表达式
this.cb = cb; // 当表达式所对应的数据发生改变的回调函数
this.value = this.get(); // 表达式当前的值
this.depIds = {};
// 表达式中各级属性所对应的dep对象的集合对象
// 属性名为dep的id, 属性值为dep
}
MVVM 中会创建 Observer(用来劫持/监听所有属性)和 Compile(解析指令/大括号表达式),
Observer:要劫持就需要对应的set()方法,所以在observer中为每一个属性创建了一个 dep 对象(与 data 中的属性一一对应)
Compile:(做了两件事)
1.目的是初始化视图(显示界面),调用 updater(有很多更新节点的方法)
2.为表达式创建对应的 Watcher ,同时指定了更新节点的函数
Watcher 和 Dep 建立关系:
1.watcher 放到 dep 中(添加订阅者)
dep 中有一个 subs,是用来保存 n 个 watcher 的数组容器
2.dep 放到 watcher 中
watcher 中的 depIds 是用来保存 n 个 dep 的对象容器。为了判断 dep 与 watcher 的关系是否已经建立(防止重复的建立关系)
以上都是初始化阶段会经历的过程
更新阶段:
vm.name = ‘Tom’ 导致 data 中的数
据变化,会触发监视 data 属性的 observer 中的 set() 方法,然会它又会通知 dep,dep 会去通知它保存的所有相关的 watcher,watcher 收到信息后,其回调函数会去调用 updater 更新界面
如下图所示:(黑线是初始化阶段,红线是更新阶段)
数据绑定实现
1数据监视/劫持 defineProperty()
2订阅者 发布者
observer 发布者
dep 订阅器
**watcher 订阅者 通知更新节点**
导航守卫提供下面两个方面的功能
监视路由跳转 控制路由跳转
应用
在跳转页面前,进行用户权限检查限制(验证是否登录)
在界面离开前 做收尾工作
导航守卫分类
全局守卫
全局前置守卫
全局后置守卫
全局前置守卫:在准备跳转到某个路由组件之前
router.beforeEach((to, from, next)=>{
}
说明: to 将要访问的路径
from 从那个路径跳转过来
next 是一个函数 表示放行
next()执行下一个守回调 如果没有跳转到目标路由
next(false) 不执行 跳转流程在当前出中短 不会跳转到目标路由组件
全局后置守卫:在跳转到某个路由之后
router.afterEach((to, from) => {
// ...
})
组件守卫
进入前
当前路由改变
离开后
beforeRouteEnter (to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
next(component=>{}) 回调函数访问组件对象
},
beforeRouteUpdate (to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave (to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
导航解析流程
导航被触发
在失活的组件里调用组件离开守卫 :beforeRouteLeave
调用全局的前置守卫:router.beforeEach
在被激活的组件里调用组件进入守卫:beforeRouteEnter 函数内部执行 next(component=>{}) 导航被确认
导航被确认
创建组件对象
调用组件通过next(component=>{}) 指定的回调函数,并将创建好的组件对象传入
调用全局的后置组件对象
使用
// 挂载路由守卫
router.beforeEach((to, from, next) => {
// to 将要访问的路径
// from 从那个路径跳转过来
// next 是一个函数 表示放行
// 如果用户访问的登录页,直接放行
if (to.path === '/login') return next()
// 从 sessionStorage 中获取到 保存的 token 值
const tokenStr = window.sessionStorage.getItem('token')
// 没有token,强制跳转到登录页
if (!tokenStr) return next('/login')
next()
})
可以一路径为参考也可以使用路由验证配置
{
path:'/userinfo',
component:userinfo,
meta:{
istoken:true
}
}
通过to.meta.istoken获取路由属性值判断
原生事件 vue自定义 事件 全局加载总线
什么条件下绑定的是原生DOM事件监听
1、给html原生标签绑定dom监听
2、给组件标签绑定dom事件监听使用.native
什么条件下绑定的vue自定义事件监听
1、自定义事件名
2、与dom事件同名
利用vm实现全局eventBus
1、前置知识
vue原型对象上有3个事件处理的方法 $on $emit $off $once
组件对象的原型对象是一个VM对象 组件对象可以直接访问Vue原型的方法
2、实现
创建vm作为全局事件总线 Vue.prototype.$bus=new Vue()
分发事件/传递数据的组件 this. b u s . bus. bus.emit(‘eventName’,data)
当用在组件上时,v-model
则会这样:
为了让它正常工作,这个组件内的 必须:
value
attribute 绑定到一个名叫 value
的 prop 上input
事件被触发时,将新的值通过自定义的 input
事件抛出写成代码之后是这样的:
Vue.component('custom-input', {
props: ['value'],
template: `
`
})
现在 v-model
就应该可以在这个组件上完美地工作起来了:
基本原理
在初始化时 利用Object.defineProperty()给data属性添加setter监听数据变化
在初始化时候 每个组件的实例都有相应的watcher对象 每个属性都关联上了所有的watcher对象
在更新数据后 对应的setter调用,通知相关的watcher watcher内异步更新节点或者子组件
细节
只有data中属性是响应式对饿,只在组件对象上的属性不是响应式的
data中所i有层次的属性都是响应式的
直接在data中响应式属性对象中添加一个新的属性,默认不响应式的,需要通过Vue提供的语法添加 Vue.set(obj,propName,value)
正向代理
客户端代理,代理客户端,服务器端不知道实际发起请求的客户端
例子 Dev-server 使用了非常强大的 http-proxy-middleware 包
devServer:{
host: 'localhost',//target host
port: 8080,
//proxy:{'/api':{}},代理器中设置/api,项目中请求路径为/api的替换为target
proxy:{
'/api':{
target: 'http://192.168.1.30:8085',//代理地址,这里设置的地址会代替axios中设置的baseURL
changeOrigin: true,// 如果接口跨域,需要进行这个参数配置
//ws: true, // proxy websockets
//pathRewrite方法重写url
pathRewrite: {
'^/api': '/'
//pathRewrite: {'^/api': '/'} 重写之后url为 http://192.168.1.16:8085/xxxx
//pathRewrite: {'^/api': '/api'} 重写之后url为 http://192.168.1.16:8085/api/xxxx
}
}}
},
//...
}
反向代理
服务器代理 ,代理服务端 服务端不知道发起请求的客户端
例子 Nginx
CROS
服务器端添加Access-Control-Allow-Origin:"*"
1、调试的目的
查找bug 不断缩小可以代码的范围
查看程序的运行流程
2、如何开启调试模式
添加debugger语句:程序运行前 次方式用于打包后运行的项目
添加断点 : 程序运行前或者过程中 此方式运行源码js
3、如何进行调试工作
resume 恢复程序执行(可能执行完或者进入下一个断点)
step ove单步跳转 尝试执行完当前语句 进入下一条(如果内部有断点 自动进入内部断点处)
step into 跳入 进入当前调用函数内部
step out 跳出 一次性执行完当前函数后面的语句并出去
deactivate breakpoints 使所有断点暂时失效
call stack 显示是程序函数的调用过程
scop 当前执行环境对应的作用域包含的变量数据
breakpoints 断点列表