虚拟DOM( VDOM )是利用了js的Object对象模型来模拟真实DOM,它的结构是一个树形结构,操作虚拟DOM比真实DOM更高效
diff算法的思维来自于后端,用来比较两个或多个文件,返回值是文件的不同点,diff算法进行的是同级比较
diff算法的比较思维(Vue中),会出现以下四种情况:
1. 此节点是否被移除 ---> 添加新的节点
2. 属性是否被更改 ---> 旧属性改为新属性
3. 文本内容被改变 ---> 旧内容改为新内容
4. 结构完全不同 ---> 节点将被整个移除替换
v-if用于操作Dom是否渲染,而v-if操作的则是display属性,v-if的有更高的切换开销,v-show有更大的初始渲染开销,所以,如果需要频繁切换,使用v-show比较好,而如果渲染条件改变次数少,则v-if更好
v-model默认绑定了对象的value,checked等属性,当它初次绑定的时候,就会触发getter,watcher就会触发, watcher通知Vue生成新的VDOM树,再通过render函数进行渲染,生成真实DOM当视图修改时,意味着DOM的value属性值改变,就会触发setter,watcher监听机制就会执行,watcher通知Vue生成新的VDOM树,再通过render函数进行渲染,生成真实DOM
父子通信
子父通信
非父子组件通信
使用ref来绑定组件, 【ref链】
通过事件总线(bus)
它是通过事件的发布(声明), 以及事件的订阅(触发)来做的
首先在js中 创建一个bus对象(vm)
var bus = new Vue()
在Count组件中定义数据, 和修改数据的方法
在Count组件中 通过 created 钩子 , 进行bus事件的发布
created: {
bus.$on('add',this.addCount)
}
在MyButton组件的方法中通过 bus进行事件的订阅
increment () {
bus.$emit( 'add' )
}
Vue 实例有一个完整的生命周期,生命周期也就是指一个实例从开始创建到销毁的这个过程。
beforeCreated():在实例创建之前执行,数据未加载状态。
created():在实例创建、数据加载后,能初始化数据,DOM 渲染之前执行。
beforeMount():虚拟 DOM 已创建完成,在数据渲染前最后一次更改数据。
mounted():页面、数据渲染完成,真实 DOM 挂载完成。
mounted():页面、数据渲染完成,真实 DOM 挂载完成。
beforeUpadate():重新渲染之前触发。
updated():数据已经更改完成,DOM 也重新 render 完成,更改数据会陷入死循环。
beforeDestory()
和 destoryed():前者是销毁前执行(实例仍然完全可用),后者则是销毁后执
- 改变:
vue 在 2.6.0 中,具名插槽和作用域插槽引入了一个新的统一的语法 (即 `v-slot` 指令)。它取代了 `slot` 和 `slot-scope` 这两个目前已被废弃但未被移除且仍有用的特性。但是将会在vue 3 中,被废弃的这两个,不会被支持即无效。
- 使用
1. 具名插槽的变化
```javascript
------------header----------------
这是header1的内容
这是header2的内容
------------header----------------
这是header1的内容
这是header2的内容
```
2. 具名插槽的缩写
跟 v-on 和 v-bind 一样,v-slot 也有缩写,即把参数之前的所有内容 (v-slot:) 替换为字符 #。例如 v-slot:header 可以被重写为 #header:
```html
Here might be a page title
A paragraph for the main content.
And another one.
Here's some contact info
```
3. 作用域插槽的变化
```html
说了:{{thing.said}}
{{value.send.text}}
说了:{{thing.said}}
{{value.send.text}}
```
4. 动态插槽名:态指令参数也可以用在 v-slot 上,来定义动态的插槽名:
```html
...
```
v-model其实是v-bind和v-on的语法糖
``其实是
``的语法糖
v-on,它其实就是一个事件绑定器。我们仔细阅读一下
``,
发现它由两部分组成:v-bind:value和v-on:input,必须是value属性和input事件,否则也不会等价于v-model,而且input事件里面,正好是something等于当前输入值。
vuex是一个集中式的存储仓库【状态】,类似于 本地存储、数据库,vuex是vue的状态管理工具,它的功能主要是实现多组件间的状态【数据】共享
vuex的组成部分(其中state,action和mutation是它的核心组成)
- **state: 状态**
- **action: 动作(业务交互)**
- **mutation: 修改state**
- getter: 获取数据的
- store: state的存储者
应用场景
相对比较大型的应用(状态较多)
1. 创建插件目录,使用npm init -y 初始化目录。
2. 定义插件组件内容,并在入口文件index.js中引入插件组件,并使用install方法,并导出
```JavaScript
import Vue from 'vue'
import Loading from './components/Loading.vue'
export default {
install () {
Vue.component('Loading',Loading)
}
}
```
3. 在Vue的入口文件中引入index.js文件并使用Vue.use()使用该组件,则可以在项目中任意位置使用
```JavaScript
import Loading from './zyl_plugins'
Vue.use(Loading)
```
1. 当你利用索引设置一个项时, 例如: vm.items[indexOfItem] = newValue;
**解决方法**: 使用 Vue.set || this.$set 或splice(indexOfItem, 1, newValue);
2. 当你修改数组的长度时,例如: vm.items.length = newLength;
**解决方法**:使用splice(newLength)
Vue数据请求用的是原生的fetch和封装的第三方库axios
vue.js是不兼容ie8及其以下浏览器,因为用到了ES5中的`Object.defineProperty`
不区分平台,都可以使用
第一步、安装 babel-polyfill
`npm install --save babel-polyfill`
第二步、在VUE项目的src目录下找到main.js,添加代码`import 'babel-polyfill'`
第三步、在webpack.base.conf.js中配置:
`entry: {
app: ['babel-polyfill','./src/main.js']
},`
可以用路由的 history 模式,添加 mode: 'history' 之后将使用 HTML5 history 模式,该模式下没有 # 前缀
1. 在公共方法中(如 public.js 中),加入函数防抖和节流方法
- 防抖
```JavaScript
export function _debounce(fn, delay) {
var delay = delay || 200;
var timer;
return function () {
var th = this;
var args = arguments;
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(function () {
timer = null;
fn.apply(th, args);
}, delay);
};
}
```
- 节流
```JavaScript
export function _throttle(fn, interval) {
var last;
var timer;
var interval = interval || 200;
return function () {
var th = this;
var args = arguments;
var now = +new Date();
if (last && now - last < interval) {
clearTimeout(timer);
timer = setTimeout(function () {
last = now;
fn.apply(th, args);
}, interval);
} else {
last = now;
fn.apply(th, args);
}
}
}
```
2. 在需要使用的组件引用
`import { _debounce } from "@/utils/public";`
3. 在 methods 中使用
```JavaScript
methods: {
// 改变场数
changefield: _debounce(function(_type, index, item) {
// do something ...
}, 200)
}
```
(技术栈:某项工作或某个职位需要掌握的一系列技能组合的统称)
1. vue
组件的生命周期、组件的通信、计算属性(computed)、数据更新检测,对象更新、事件处理器(修饰符)、表单控件绑定、异步更新队列、过渡效果、插件、混合(mixins)....
2. vue-router
两种导航方式(router-link声明式导航,编程式导航)、导航(路由)守卫、路由的激活,动画、数据获取,预载,懒加载,缓存、路由的传接参、动态路由...
3. vuex
state、actions、mutations、getters、modules、热重载
vue-cli 用于快速创建vue项目,底层配置使用的就是webpack
1. 安装cli
npm install @vue/cli -g cli3的版本
npm install vue-cli -g cli2的版本
(npm install @vue/cli-init -g 装了这个工具,可以随意安装cli2又能随意安装cli3)
2. 创建项目
vue create peoject(项目名) --->cli3
vue init webpack/webpack-simple(简易版本) peoject(项目名) ---->cli2
3. 目录结构说明
* node_modules 项目的依赖包
* public 静态资源文件夹
* src 源代码开发目录
1. assets 当前项目开发的静态资源
2. compomemts 项目的组件
3. main.js webpack中配置的主入口文件
.......
* .browserslistrc 项目不支持 ie8及以下
* .gitignore git上传时,不上传的文件
* package.json 当前项目的依赖包配置文件
* pastcss.cofig.js 给css添加引擎头前缀
* readme.md 当前项目的说明文件
* yarn.lock 当前项目的依赖包的第三方库的详细信息记录
4. 下载依赖包
下载所需要的包,npm/cnpm/yarn
5. 运行项目
npm run dev
(vue.$data.__ob__)
是保存Observer对象的,用来记录是否已经做过数据的“响应式化”,也就是是否已经被Observer处理过,最终是为了用Object.defineProperty进行数据的双向绑定。
利用sessionStorage/localStorage,做一个暂时的储存store的模块化结构
主要是针对mutations 和 getters 做一个简单的赋值和取值封装
mutations.js改变state的同时在本地做一个备份
getters.js 取值时默认从state里面取,没有就从本地拿
在页面vue文件直接用mapGetters获取状态值
这样一来就算state被清空了,还可以在本地储存里面获取状态值
watch所监听的对象里添加deep: true
- hash 模式 —— 使用 URL 的 hash值 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。支持所有浏览器,包括不支持 HTML5 History Api 的浏览器。
- history 模式——这种模式充分利用 h5 history.pushState API 来完成 URL 跳转而无须重新加载页面。history需要后台配置支持
登录路由拦截,
```javascript
router.beforeEach((to, from, next) => {
if (to.name !== 'login') {
if (!window.sessionStorage.tokenId) {
router.push({name: 'login'})
}
}
next()
```
- beforeCreate:表示组件创建前的准备工作, 为事件的发布订阅 和 生命周期的开始做初始化,无法获取data数据和真实dom
- created: 在实例创建、数据加载后,能初始化数据,DOM 渲染之前执行。数据、属性、方法已经初始化完成,还没挂载。在这个钩子中可以进行数据请求,然后可以进行默认数据的修改
- beforMount: 挂载之前,已完成模板的渲染,生成了虚拟dom, 但真实dom依然无法获取,在这个钩子中数据请求, 它也可以进行一次数据修改
- mounted:页面、数据渲染完成,真实 DOM 挂载完成。在这个钩子中DOM操作就可以进行了, 也可以进行第三方库的实例化(dom不改变)
- beforeUpdate: 数据更新后被动执行,发生在虚拟DOM重新渲染前,因为这个钩子主要做的事情是内部进行的, 所以对我们而言没有太多的操作意义
- updated: 在数据更改导致的虚拟DOM重新渲染和打补丁之后调用。调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作,如进行第三方库的实例化( DOM是改变的 )。然而在大多数情况下,应该避免在此期间更改状态,通常最好使用计算属性或 watcher 取而代之。
- beforeDestory: 销毁前执行(实例仍然完全可用),
- beforeDestory: 组件连同数据和方法一起被销毁,在这个钩子中做善后工作 , 手动清除一些计时器, 和一些方法, 还有第三方实例化出来的对象
看实际情况,一般在created(或beforeRouteEnter)里面就可以,如果涉及到需要页面加载完成之后的话用mounted。
在created的时候,视图中的html并没有渲染出来,所以此时如果直接去操作html的dom节点,一定找不到相关的元素
而在mounted中,由于此时html已经渲染出来了,所以可以直接操作dom节点,(此时document.getelementById 即可生效了)。
首先,组件可以提升整个项目的开发效率。能够把页面抽象成多个相对独立的模块,解决了我们传统项目开发:效率低、难维护、复用性等问题。
然后,使用Vue.extend方法创建一个组件,然后使用Vue.component方法注册组件。子组件需要数据,可以在props中接受定义。而子组件修改好数据后,想把数据传递给父组件。可以采用emit方法。
父子 props/event $parent/$children ref provide/inject
兄弟 bus vuex
跨级 bus vuex provide.inject
```javascript
HTML:
{{countDownList}}
script:
export default {
data() {
return {
countDownList: '00天00时00分00秒',
actEndTime: '2018-11-19 18:50:00'
};
},
created() {
this.countDown();
},
methods: {
timeFormat(param) {
return param < 10 ? '0' + param : param;
},
countDown(it) {
var interval = setInterval(() => {
// 获取当前时间,同时得到活动结束时间数组
let newTime = new Date().getTime();
// 对结束时间进行处理渲染到页面
let endTime = new Date(this.actEndTime).getTime();
let obj = null;
// 如果活动未结束,对时间进行处理
if (endTime - newTime > 0) {
let time = (endTime - newTime) / 1000;
// 获取天、时、分、秒
let day = parseInt(time / (60 * 60 * 24));
let hou = parseInt(time % (60 * 60 * 24) / 3600);
let min = parseInt(time % (60 * 60 * 24) % 3600 / 60);
let sec = parseInt(time % (60 * 60 * 24) % 3600 % 60);
obj = {
day: this.timeFormat(day),
hou: this.timeFormat(hou),
min: this.timeFormat(min),
sec: this.timeFormat(sec)
};
} else { // 活动已结束,全部设置为'00'
obj = {
day: '00',
hou: '00',
min: '00',
sec: '00'
};
clearInterval(interval);
}
this.countDownList = obj.day + '天' + obj.hou + '时' + obj.min + '分' + obj.sec + '秒';
}, 1000);
}
}
}
```