vue的相关知识以及基础原理

vue的特点

Vue.js是一款轻量级的以数据驱动(数据的变化将引起视图的变化)的构建单页面应用mvvm框架,它比较简单易学,具有双向数据绑定,在数据操作方面更为简单减少大量的逻辑代码,组件化,可以封装和重用通用组件,vue引入虚拟dom,不再使用原生的dom操作节点,极大解放dom操作,使得运行速度更快

什么是单页面应用

单页面应用:

单页面跳转仅刷新局部资源 ,公共资源(js、css等)仅需加载一次,url 模式一般为a.com/#/pageone

多页面应用

多页面跳转刷新所有资源,每个公共资源(js、css等)需选择性重新加载,url 模式一般为a.com/pageone.html

什么是mvvm

MVVM是Model-View-ViewModel的缩写。MVVM是一种设计思想。
Model 层代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑;
View 代表UI 组件,它负责将数据模型转化成UI 展现出来,
ViewModel 是一个同步View 和 Model的对象。
在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的,因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。

什么是虚拟dom

我们知道了Vue是数据驱动视图(数据的变化将引起视图的变化),当你你发现某个数据改变时,视图是局部刷新而不是整个重新渲染,如何精准的找到数据对应的视图并进行更新呢?那就需要拿到数据改变前后的dom结构,找到差异点并进行更新!

虚拟dom的比较,就是找出新节点(vnode)和旧节点(oldVnode)之间的差异新旧节点,如果不相似,直接根据新节点创建dom;如果相似,先是对data比较,包括class、style、event、props、attrs等,有不同就调用对应的update函数,然后是对子节点的比较,子节点的比较用到了diff算法
更详细请看这里

Vue组件化

首先组件的基本构成分别是:样式结构,行为逻辑,数据。web中的组件其实就是页面组成的一部分,每个组件都会提供一些对外接口,允许使用者设置和调整参数属性,可以将不同功能的组件结合在一起,快速的构成一个符合实际需求的应用

双向数据绑定原理

vue双向绑定就是指model层与view层的同步,两者之间任意一个发生变化都会同步更新到另一者。
vue.js 双向数据绑定则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

Object.defineProperty(obj, prop, descriptor)

obj

要在其上定义属性的对象。

prop

要定义或修改的属性的名称。

descriptor

将被定义或修改的属性描述符。

更过关于Object.defineProperty()请查看

当我们在定义一个属性如下然后打印data这个对象:

data: {
      name: "张三"
}
console.log(data)

这个时候除了data对象的值,原型等以外,还有两个方法分别是get和set,

var modelName= "李四";
var data = {};
Object.defineProperty(data,'name', {
    get: function(){
        return modelName;
    },
    set: function(newValue){
        modelName= newValue;
        console.log(`modelName的值已发生改变,目前的值是:${modelName}`);
    }
});
 
data.name; // 当调用这个对象时候会触发get方法,这个时候会返回modelName的值
             //,所以这里可以通过改变modelName来改变obj.key的值
 
data.name = "王五"   //当修改这个对象时候会触发set方法,modelName的值已发生改
                           // 变,目前的值是王五

如此就实现了一个简单的双向绑定:改变modelName,data.name得到的值也会改变,重新设置data.name,modelName一样会随之改变。
更详细请看这里

vue+token验证实现登陆

在前后端完全分离的情况下,Vue项目中实现token验证大致思路如下:

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信息并跳转到登录页面

vue的生命周期

vue生命周期就是从开始创建,初始化数据,编译模板,挂载DOM,渲染->更新->渲染,销毁等一系列过程
总共分为8个阶段:

阶段 作用
beforeCreate----创建前 组件实例更被创建,组件属性计算之前,数据对象data都为undefined,未初始化。
created----创建后 组件实例创建完成,属性已经绑定,数据对象data已存在,但dom未生成,$el未存在这个时候html还没有渲染出来
beforeMount---挂载前 vue实例的$el和data都已初始化,挂载之前为虚拟的dom节点,data.message未替换
mounted-----挂载后 vue实例挂载完成,data.message成功渲染。
beforeUpdate----更新前 当data变化时,会触发beforeUpdate方法
updated----更新后 当data变化时,会触发updated方法
beforeDestory---销毁前 组件销毁之前调用
destoryed---销毁后 组件销毁之后调用,对data的改变不会再触发周期函数,vue实例已解除事件监听和dom绑定,但dom结构依然存在

vue生命周期的应用场景:

beforeCreate 可以在此时加一些loading效果,在created时进行移除
created 需要异步请求数据的方法可以在此时执行,完成数据的初始化
mounted 当需要操作dom的时候执行,可以配合$.nextTick 使用进行单一事件对数据的更新后更新dom
updated 当数据更新需要做统一业务处理的时候使用
只有ajax数据请求放在created里面就可以了,这样可以及早发请求获取数据;如果有依赖DOM的情况下,就放到mounted里面

组件之间的传值通信?

父组件向子组件传值:

父组件如下:

<template>
  <div>
      //这里data为传给子组件的字段,value为需要传的值
      <child :data="value" @back= "getBack"></child>
  </div>
</template>
<script>
export default {
  data () {
    return {
      value:'父组件的值传给子组件'
    }
  },
methods: {
    getBack(backValue){
      //backValue 这个就是回传的值
    }
}
</script>

父组件如下:

<template>
  <div>
    <p @click="backData">这是子组件</p>
  </div>
</template>
<script>
export default {
  data () {
    return {
      value1:"返回的值",
    }
  },
  props: ['data'],
  methods: {
     backData() {
           //这里back为事件名称用于父组件接收回传的值,后面为要传的值
           this.$emit('back',this.value1);
      }
}
}
</script>

兄弟组件传值

bus方式的组件间传值其实就是建立一个公共的js文件,专门用来传递消息

1.建立公共文件,并引入

//新建msgBus.js文件。只需两句代码。
1 import Vue from 'vue'
2 export default new Vue;
//然后在需要传递消息的两个组件引入
 import MsgBus from '@/components/utils/msgBus.js';

2.发送消息

//触发组件的事件:
MsgBus.$emit('msg', _this.examineNum);

3.接受消息

//接受组件的事件:
//写在钩子函数内:例如:mounted   created都可以
1 MsgBus.$on('msg', (e) => {
2   this.examineNum = e;
3 })

这里建议使用vuex

vue中watch、computed

computed:当页面中有某些数据依赖其他数据进行变动的时候,可以使用计算属性

computed: {  
            fullName: function () {  
               //这里不管是firstName ,还是lastName重要有一个改变就会触发
                return this.firstName + ' ' + this.lastName  
            }  
        }  

需要注意的是,就算在data中没有直接声明出要计算的变量,也可以直接在computed中写入。computed是具有缓存的,这就意味着只要计算属性的依赖没有进行相应的数据更新,那么computed会直接从缓存中获取值,多次访问都会返回之前的计算结果

watch:如果要在数据变化的同时进行异步操作或者是比较大的开销,那么watch为最佳选择如:

            watch(oldVal,newVal) {  
              setTimeOut(()=>{
               },2000);
            }  

用watch可以实现2s后更改数据。而这种效果用computed不能实现,因为computed不适合做异步操作
watch监控现有的属性,computed通过现有的属性计算出一个新的属性
watch不会缓存数据,每次打开页面都会重新加载一次,但是computed如果之前进行过计算他会将计算的结果缓存,如果再次请求会从缓存中得到数据

v-show和v-if区别

v-show指令是通过修改元素的displayCSS属性让其显示或者隐藏
v-if指令是直接销毁和重建DOM达到让元素显示和隐藏的效果
一般来说, v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件不太可能改变,则使用 v-if 较好

Vue操作DOM

在vue中可以通过给标签加ref属性,就可以在js中利用ref去引用它,从而操作该dom元素,如下:

<template>  
  <div>  
    <div id="box" ref="mybox">  
      DEMO  
    </div>  
  </div>  
</template>  
<script>  
export default {  
  data () {  
    return {  
    }  
  },  
  mounted () {  
    this.init();  
  },  
  methods:{  
    init() {  
      this.$refs.mybox.style.color = 'red';  
    }  
  }  
}  
</script>  

vue中 key 值的作用

用于管理可复用的元素。因为Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。这么做使 Vue 变得非常快,但是这样也不总是符合实际需求

例如,如果你允许用户在不同的登录方式之间切换:
<template v-if="loginType === 'username'">
  <label>Username</label>
  <input placeholder="Enter your username">
</template>
<template v-else>
  <label>Email</label>
  <input placeholder="Enter your email address">
</template>

那么在上面的代码中切换loginType 将不会清除用户已经输入的内容。因为两个模板使用了相同的元素
这样也不总是符合实际需求,所以Vue为你提供了一种方式来表达这两个元素是完全独立的,不要复用它们。只需添加一个具有唯一值的 key 属性即可:

<template v-if="loginType === 'username'">
  <label>Username</label>
  <input placeholder="Enter your username" key="username-input">
</template>

<template v-else>
  <label>Email</label>
  <input placeholder="Enter your email address" key="email-input">
</template>

现在,每次切换时,输入框都将被重新渲染。

vue事件中如何使用event对象

//html部分
<a href="javascript:void(0);" data-id="12" @click="showEvent($event)">event</a>
//js部分
showEvent(event){
    //获取自定义data-id
    console.log(event.target.dataset.id)
   //阻止事件冒泡
    event.stopPropagation(); 
    //阻止默认
    event.preventDefault()
}

vue中如何编写可复用的组件

在编写组件的时候,时刻考虑组件是否可复用是有好处的。一次性组件跟其他组件紧密耦合没关系,但是可复用组件一定要定义一个清晰的公开接口。

Vue.js组件 API 来自 三部分:prop、事件、slot:

prop 允许外部环境传递数据给组件,在vue-cli工程中也可以使用vuex等传递数据。
事件允许组件触发外部环境的 action
slot 允许外部环境将内容插入到组件的视图结构内。
代码示例:

<my-component
    :foo="bar"
    :bar="qux"
    //子组件调用父组件方法
    @event-a="doThis"
    @event-b="doThat">
    <!-- content -->
<img slot="icon" src="..." />
<p slot="main-text">Hello!</p>
</my-component>

如何解决非工程化项目,网速慢时初始化页面闪动问题

使用v-cloak指令,v-cloak不需要表达式,它会在Vue实例结束编译时从绑定的HTML元素上移除,经常和CSS的display:none配合使用。

<div id="app" v-cloak>
{{message}}
</div>
<script>
var app = new Vue({
    el:"#app",
    data:{
        message:"这是一段文本"
    }
})
</script>

这时虽然已经加了指令v-cloak,但其实并没有起到任何作用,当网速较慢、Vue.js 文件还没加载完时,在页面上会显示{{message}}的字样,直到Vue创建实例、编译模版时,DOM才会被替换,所以这个过程屏幕是有闪动的。只要加一句CSS就可以解决这个问题了:

[v-cloak]{
    display:none;
}

在一般情况下,v-cloak是一个解决初始化慢导致页面闪动的最佳实践,对于简单的项目很实用。

如何在组件中使用全局常量

//第一步,在 src 下新建 const 文件夹下 新建 const.js

.
├── src
│   ├── const
│   │    ├── const.js
│   │    
│   └── main.js
└── ...
//第二步,如何在 const.js 文件下,设置常量

export default {

    install(Vue,options){

        Vue.prototype.global = {
            title:'全局',
            isBack: true,
            isAdd:  false,
        };
        
    }

 }
//第三步,在 main.js 下全局引入:

//引入全局常量
import constant from './const/const.js'
Vue.use(constant);
//第四步,即可在 .vue 组件中使用:

//通过js方式使用:
this.global.title
//或在 html 结构中使用
{{global.title}}

如何定义一个常量,允许项目打包后,修改 js 里面的值

第一步,在 static 下新建 config.js:

├── 项目路径
│   ├── static
│   │___├── config.js

第二步,在 config.js 里面设置全局变量:

window.g = {
    PUBLIC_IP  : "http://10.10.10.10:8080"
}

第三步,在 index.html 里面引入:

<script type="text/javascript" src="./static/config.js"></script>

第四步,在其他 .js 文件中即可使用:

window.g.PUBLIC_IP

第五步,打包后修改:

通过 npm run build 命令打包后,此 config.js 文件会被打包到 dist/static文件夹下,

image

此时如果需要修改 PUBLIC_IP,打开config.js即可修改,无需重新打包!

vue如何禁止弹窗后面的滚动条滚动

methods : {
   //禁止滚动
   stop(){
        var mo=function(e){e.preventDefault();};
        document.body.style.overflow='hidden';
        document.addEventListener("touchmove",mo,false);//禁止页面滑动
    },
    /***取消滑动限制***/
    move(){
        var mo=function(e){e.preventDefault();};
        document.body.style.overflow='';//出现滚动条
        document.removeEventListener("touchmove",mo,false);
    }
}

vue-router实现原理

1. hash 模式

单页应用不仅仅是在页面交互是无刷新的,连页面跳转都是无刷新的,为了实现单页应用,所以就有了前端路由。 类似于服务端路由,前端路由实现起来其实也很简单,就是匹配不同的 url 路径,进行解析,然后动态的渲染出区域 html 内容。但是这样存在一个问题,就是 url 每次变化的时候,都会造成页面的刷新。那解决问题的思路便是在改变 url 的情况下,保证页面的不刷新。在 2014 年之前,大家是通过 hash 来实现路由,url hash 就是类似于:
http://www.xxx.com/#/login
这种 #。后面 hash 值的变化,并不会导致浏览器向服务器发出请求,浏览器不发出请求,也就不会刷新页面。另外每次 hash 值的变化,还会触发 hashchange 这个事件,通过这个事件我们就可以知道 hash 值发生了哪些变化

2. history 模式

因为HTML5标准发布。多了两个 API, pushState 和 replaceState ,通过这两个 API 可以改变 url 地址且不会发送请求。同时还有 popstate 事件。通过这些就能用另一种方式来实现前端路由了,但原理都是跟 hash 实现相同的。用了 HTML5 的实现,单页路由的 url 就不会多出一个#,变得更加美观。但因为没有 # 号,所以当用户刷新页面之类的操作时,浏览器还是会给服务器发送请求。为了避免出现这种情况,所以这个实现需要服务器的支持,需要把所有路由都重定向到根页面

import VueRouter from 'vue-router'
Vue.use(VueRouter)
const router = new VueRouter({
 mode: 'history',
 routes: [...]
})
new Vue({
 router
 ...
})

vue-router如何响应路由参数的变化

复用组件时,想对路由参数的变化作出响应的话, 可以watch (监测变化) $route 对象:

const User = {
  template: '...',
  watch: {
    '$route' (to, from) {
      // 对路由变化作出响应...
    }
  }
}
或者使用 2.2 中引入的 beforeRouteUpdate 守卫:

const User = {
  template: '...',
  beforeRouteUpdate (to, from, next) {
    // react to route changes...
    // don't forget to call next()
  }
}

vue-router有哪几种导航钩子( 导航守卫 )

1、全局守卫: router.beforeEach
2、全局解析守卫: router.beforeResolve
3、全局后置钩子: router.afterEach
4、路由独享的守卫: beforeEnter
5、组件内的守卫: beforeRouteEnter、beforeRouteUpdate (2.2 新增)、beforeRouteLeave

vue-router的几种实例方法以及参数传递

实例方法:
实例方法 说明
this.$router.push(location, onComplete?, onAbort?) 这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,则回到之前的 URL。并且点击 <router-link :to="...">等同于调用 router.push(...)
this.$router.replace(location, onComplete?, onAbort?) 这个方法不会向 history 添加新记录,而是跟它的方法名一样 —— 替换掉当前的 history 记录,所以,当用户点击浏览器后退按钮时,并不会回到之前的 URL
this.$router.go(n) 这个方法的参数是一个整数,意思是在 history 记录中向前或者后退多少步,类似 window.history.go(n)
参数传递方式:

vue-router提供了params、query、meta三种页面间传递参数的方式。
示例:

// 字符串,不带参数
this.$router.push('home')
// 对象,不带参数
this.$router.push({ path: 'home' })
// params(推荐):命名的路由,params 必须和 name 搭配使用
this.$router.push({ name:'user',params: { userId: 123 }})
// 这里的 params 不生效
this.$router.push({ path:'/user',params: { userId: 123 }})
// query:带查询参数,变成 /register?plan=private
this.$router.push({ path: 'register', query: { plan: 'private' }})
//meta方式:路由元信息
export default new Router({
    routes: [
        {
            path: '/user',
            name: 'user',
            component: user,
            meta:{
                title:'个人中心'
            }
        }
    ]
})

在组件中使用:

//通过 $route 对象获取,注意是route,么有r
this.$route.params
this.$route.query
this.$route.meta

$route$router 的区别

$route是路由信息对象,包括path,params,hash,query,fullPath,matched,name等路由信息参数。
$router是“路由实例”对象包括了路由的跳转方法,钩子函数等。

vue-router实现动态加载路由组件( 懒加载 )

{
  path: '/home',
  name: 'home',
  component: resolve => require(['@/components/home'],resolve)
}

什么是vuex

请看这里

使用vuex的核心概念

每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。

Vuex 和单纯的全局对象有以下两点不同

1、Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。

2、你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。

ajax请求代码应该写在组件的methods中还是vuex的actions中

一、如果请求来的数据是不是要被其他组件公用,仅仅在请求的组件内使用,就不需要放入vuex 的state里。
二、如果被其他地方复用,这个很大几率上是需要的,如果需要,请将请求放入action里,方便复用,并包装成promise返回,在调用处用async await处理返回的数据。如果不要复用这个请求,那么直接写在vue文件里很方便。

axios有什么特点

1、Axios 是一个基于 promise 的 HTTP 库,支持promise所有的API
2、它可以拦截请求和响应
3、它可以转换请求数据和响应数据,并对响应回来的内容自动转换成 JSON类型的数据
4、安全性更高,客户端支持防御 XSRF

axios的封装

请看这里

不定时更新

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 210,835评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,900评论 2 383
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,481评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,303评论 1 282
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,375评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,729评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,877评论 3 404
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,633评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,088评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,443评论 2 326
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,563评论 1 339
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,251评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,827评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,712评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,943评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,240评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,435评论 2 348

推荐阅读更多精彩内容

  • 一:什么是闭包?闭包的用处? (1)闭包就是能够读取其他函数内部变量的函数。在本质上,闭包就 是将函数内部和函数外...
    xuguibin阅读 9,534评论 1 52
  • 前言 您将在本文当中了解到,往网页中添加数据,从传统的dom操作过渡到数据层操作,实现同一个目标,两种不同的方式....
    itclanCoder阅读 25,755评论 1 12
  • Vue问得最多的面试题 什么是 mvvm? MVVM 是 Model-View-ViewModel 的缩写。mvv...
    崽崽不哭阅读 678评论 0 8
  • vue-cli搭建项目 确保安装了node与npm 再目标文件夹下打开终端 执行cnpm i vue-cli -g...
    Akiko_秋子阅读 3,215评论 1 22
  • vue是什么? vue是构建数据驱动的web界面的渐进式框架。Vue.js 的目标是通过尽可能简单的 API 实现...
    九四年的风阅读 8,697评论 2 131