Vue

277 阅读8分钟

不用脚手架自行搭建Vue项目

不用脚手架自行搭建Vue项目

历史

  • Vue1.0版本时确实是MVVM 但是后来就在逐步向MVC架构发展的了

基本概念与规范

  1. let vm=new Vue(); vm叫Vue实例
  2. vue单文件 叫组件, 其实是一个对象,不是Vue实例
  3. 导入的组件名用大写开头,文件名则最好小写: import Demo from './demo.vue'
  4. 使用data中的数据 this.n, 等同于 this.$data.n 而不是this.data.n
  5. this.set方法===vm.set方法 === vm.set方法
  6. el属性就是this.$mount('...') --- 设置挂载点
  7. const vm=new Vue( options ) // options 被称为构造选项
  8. 不要在options中使用箭头函数,原因如下:
    • vue中频繁用到this,但options中的箭头函数中的this -> window (new Vue是函数调用而非定义)
    • 为什么options中普通函数的this -> Vue实例vm呢? 因为Vue源码保证了
  9. 无论是 v-on 之类的 官方指令 还是 自定义指令,都是用于封装dom操作
    • 比如 v-on ,Vue底层会替你调用 addEventListner 把元素和函数绑定好,这当然就是dom操作
  10. methods , computed , watch 都是对象的形式,因为它们各自有多个items
  11. {{}} 插值表达式, 仅支持单行js表达式
    new Vue({
        watch:{
            n:()=>{ 
                // 箭头函数中不存在this,this来自于外部
                // 你想要this -> Vue实例vm,这是在意淫
                // 这里箭头函数中的 this -> window, 因为new Vue()是函数调用而非函数定义
                // this借用的是外部this,这里的外部就是全局window了
                }
        }
    })
    
  12. 没必要用 Vue的 filter过滤器 ,可以用 methods 中写一个filter函数去替代

Vue书写中的细节

Vue书写中的细节

vue create demo-1 初始配置

Vue的html代码是如何被浏览器解析的?

我们知道传统的html代码其实就是字符串,
这些字符串在做了一些声明之后就可以被浏览器读到的时候给转成dom节点;

Vue中的html代码(字符串)挺特殊的,
比如混有v-if,v-for,{{n}}这些在其中,那到底浏览器是如何转成dom节点的呢?

原来vue的完整版中有着一个编译器,
会把混有v-if,v-for,{{n}}这些的html代码翻译成Vue中内置用以生成dom节点的函数,名叫h函数

但是编译器的体积太大了,所以作者其实是不推荐使用带有编译器的完整版Vue的,
比如cli脚手架工具其实就是默认使用运行时版本的Vue,
那么运行时版本的Vue没有了编译器是如何让浏览器解析混有v-if,v-for,{{n}}这些的html代码的呢?

答案是通过webapack中的vue-loader这个加载器,
vue-loader的作用和编译器一样其实就是把混有v-if,v-for,{{n}}这些的html代码
调用Vue中内置用以生成dom节点的h函数,重构整个代码

证明cli中的 vue-loader 会帮我们自动转译.vue中的html==>js

完整版Vue VS 运行时版本Vue

  • 完整版 运行时+编译器
  • 非完整版即运行时版 只包括运行时,不包括编译器

通过vue-cli默认安装的就是运行时版本的Vue

完整版Vue如何书写视图层

完整版Vue书写视图层的方式可以有三种

  1. html格式的文件中比如src/index.html (下图1+图2)
  2. Vue实例或者Vue组件中的template属性里书写html代码 (下图3)
  3. 当然也可以在.vue单文件中< template >标签中进行书写-----只不过这有点显得大材小用

mvc架构的视图通常是写在V这个对象中的,而不是直接从html代码中获取的,但这里却可以,是因为这对小白更友好

非完整版Vue如何书写视图层

非完整版Vue不支持在.html文件中书写html也不支持在Vue实例或者Vue组件的template属性中书写html

  1. 可以在Vue实例或者Vue组件的render方法中调用h函数以手动生成dom节点的方式书写----缺点是太复杂
  2. 可以在.vue结尾的单文件中书写html----这是最佳方法

template属性 VS render方法 (在Vue组件或者Vue实例中的)

下图源自官网

compiler VS vue-loader

  • compiler存在于完整版Vue源码中,其功能是把vue的html代码 其实就是字符串 (注意,这些字符串很复合比如有v-if,{{n}}这些) 转化成dom节点
  • vue-loader则属于webpack的内容,是vue-cli默认的配置项,作用和编译器是一样的,将复合的html字符串用生涩的h函数重新渲染成js文件

如何使用Vue实例?

按理说是三种方式 ,但实际只用单文件方式这一种

方式1 直接在index.html中书写html代码或者在Vue实例中的 template属性中书写html代码(需要完整版本Vue); // 缺点是完整版本Vue源码中多了编译器,因此体积大了百分之四十

方式2 在Vue实例中书写render方法配合h函数一同构造视图(运行时版本Vue) // 虽然体积节约很多,但是缺点是这种方式生涩难写,因为这等于是用vue封装好的h方法直接生成并操作dom元素

方式3 单文件.vue文件方式,依旧允许以传统方式去书写html(运行时版本Vue) // 体积节约很多,还需要有webpack的vue-loader加载器去配合, // 因为你写的传统html代码(字符串)需要被vue-loader转化成h函数那种操作dom的方式,就可以生成dom节点了。

对SEO的影响

由上可见,传到浏览器的大多都是由vue-loader调用h函数渲染成的js代码或者说字符串,
然后浏览器是通过解析js来渲染页面的
现在问题就在于,js是不能被搜索引擎所理解的,因此SEO往往不理想

优化思路

  • 可以给index.html中的app节点上写上一些对SEO有帮助的内容
  • title description keyword h1 a 这些标签写好即可
这样一来也就能让搜索引擎在curl访问你的网页的时候能提取适当的信息

不过由于国内的SEO本身也就是以收费为主,所以不必太较真。

详解Vue实例

const vm=new Vue( options )
// options 被称为选项或者构造选项
// vm 是尤雨溪的惯用,即Vue实例,该实例封装了数据读写事件绑定DOM更新,但不包含ajax

options

  • 数据
  • DOM
  • 生命周期钩子
  • 资源
  • 组合

面试题:data为什么是一个函数?(Vue全解-class2-4th)

Vue面试题

使用组件的三种方式

引入使用组件的方式有三种,
1.单开一个.vue文件然后import这叫单文件组件,在需要用的地方先import再声明才能用
2.Vue.component(id,options) 这叫全局组件,随处声明,随处使用

3. 在Vue实例内部定义一个组件

值得注意的是,[全局组件]或者[在Vue实例中components属性上定义的组件]里面的属性都与Vue实例中的属性一模一样

生命周期钩子 $nextTick

Vue生命周期 $nextTick

props 用于父->子传值

当更新了 data,立马获取视图中的数据的话,并不会得到你想要的结果。
要么你在原地使用 nextTick ,要么你就在updated 里去操作
在线示例

props在vue中指的就是用于传参的属性,既可以是propName也可以是:propName
:propName=“xxx” 里面的xxx写的是js代码,甚至可以传递函数

  • 下图是在父组件中,在往子组件中传值
    在线示例

.prop修饰符 property attribute

先上结论: .prop修饰符的作用其实就是把vue中的prop转化成像一个真正的property一样挂在于最外层上便于读取 .prop修饰符的在线示例

  • 写在子组件身上的 label 都是Vue中的prop, 都是可以在子组件内读取的
  • 但类似 style 这样的保留的prop 是无法被子组件读取的
  • 因此以下这些都是vue的 prop

什么是js中的property? 以下这些属性都是property,存在于dom结构最外层, 可以用 直接访问 什么是js中的attribute? 存在于一个propertyattributes中的所有属性都是attribute getAttribute是原生js中的api 经测试, titleidstyle,既是property又是attribute,也就是说他们既挂在最外层,又存在于attributes这个对象中

vue中自定义的 propName 存储于哪里,目前并不清楚,即不挂在最外层也不存在于attributes这个对象中

Vue数据响应式原理

Vue 数据响应式原理 defineProperty

set方法

在方法中我们只可通过 this.n 或者 this.obj.a 类似这样的去操作已存在的数据,但如果要创建尚未存在的次根级别数据则需要用到set,Vue不支持操作根级别数据 set方法不要去操作数组,数组用变异方法

  • Vue.set === this.$set === vm.$set两种set方法一模一样,仅仅为了避免与你自己写的set方法重名
  • set方法只可设置data对象第二层及其往后的数据
  • set原理就是调用Object.defineProperty,但参数不同,举个例子
  • this.$set(this.obj,'b',1)

图示,举个例子

  this.$set(this, 'b', 1); // 非法
  this.$set(this.obj, 'b', 100); // 合法

下面这张图来自于Vue官网,同样的理解

为什么无法set data中的第一层属性?

请看Vue数据响应式的源码的完整思路!中,Vue对 data 对象中属性的监听思路是,会对 data 的属性调用 Object.defineProperty ,但如果你最初连第一层属性都没给,Vue是不会去执行数据响应式监听的

Vue中数组的七种变异方法

Vue是如何制造数组的变异方法的? 拿push举例,原理类似下面

class VueArray extends Array{ 
    push(...args){ // push方法挂在VueArray.prototype上
        const oldLength = this.length // this 就是arr
        super.push(...args) // super就是调用父类的push
        console.log('push ')
        for(let i = oldLength; i<this.length; i++){ 
        // 对新增项调用set方法让Vue监听到
            Vue.set(this, i, this[i])
        }
    }
}
const arr=new VueArray(1,2,3,4);
console.log(arr)

Computed 计算属性

Vue computed watch methods

Watch 侦察属性

Vue computed watch methods

面试题: Computed, Watch, Methods 区别

Vue面试题

v-bind :class :style 数组语法 对象语法

在线示例

总结: 主要还是推荐使用对象语法,:class="{ active: isActive}" 或者直接 :class="{active}" 都可以,只不过后面这种是省略形式的写法,依旧需要在 data 中定义

v-model .sync修饰符 数据双向绑定

v-model .sync修饰符 表单 数据双向绑定

模板与指令

xml VS html

Vue的template中运用的是xml而不是html

  • xml中标签必须闭合比如 <input name="username"/>
  • html则不必比如 <input name="username"/ ><input name="username">都算对
  • xml可以允许<div/>表示无内容的div标签,而html则不可以允许这种写法出现 | | xml | html | |------|------------|------------| | <input name="username"/> | yes | yes | | <input name="username"> | no | yes | | <div/>表示无内容的div | yes | no |

模板中的胡子语法支持js运算但不支持if else

  • v-html会对内容进行编译
  • v-pre不会对内容进行编译
  • v-bind
  • v-on
  • v-if
  • v-show
  • v-cloak v-cloak用于解决网络不畅时页面显示过多的{{ }}问题。

当网络阻塞时,vuejs还不能够及时加载进来,页面中会出现很多的插值表达式,v-cloak的作用是在阻塞时生效一个样式,当恢复时自动把样式移除

通常与display:none 一同使用

指令修饰符

@click.stop // 阻止事件冒泡
@click.prevent
@click.stop.prevent // 同时表示两种意思
@keypress.keyCode //  比如@keypress.13表示回车

这里提一下input,change,keypress事件

  • input事件大体是指在input输入框之类的进行文本的值的修改时触发(触发频率非常高),你敲打回车是不会触发input事件的,因为没有值的修改
  • change事件大体是指在失焦或者提交时触发,(触发频率不高)
  • keypress事件大体是指按下键盘时触发(触发频率很高),想识别敲下的是回车键就用keypress

自定义指令

Vue自定义指令

mixins作用是重复利用组件间相同的options

点击查看一个很简单的示例

Provide和Inject

什么是Provide Inject? Provide Inject是一种依赖注入模式,实现了祖先组件与后代组件之间的通信,祖先组件中provide一些data和method,在需要使用这些东西的子组件中inject即可
点击查看在线示例 provide inject的特性是数据不可响应的,意思是说通过祖先组件provide出去的data一旦改变,那些注入了data到自身组件中使用的后代组件们是无法得到更新的

Vue路由

前端框架中指的路由就是当你输入不同url时,页面会展示不同的内容

  • 路由三种模式: hash,history,memory
  • hash就是# window.location.hash,服务器是收不到#后面的内容的,因此seo不友好 window.location.hash.substr(1) hashchange事件
  • history window.location.pathname
  • memory就是利用了localstorage去存储,但是无法分享了因为是本地的

Vue数据传递的例子

Vue组件间通信

is属性 切换子组件

在线示例

slot 插槽

在线示例

  • 基础插槽,具名插槽,作用域插槽
  • 作用域插槽主要用于封装组件 父组件和子组件可以各司其职
  • 写作用域插槽时当然不能直接在子组件内直接写 <slot v-for="item in arr">{{ item }}</slot>
  • 因为这里面的内容是插槽的默认内容,只要你父组件传递了东西,里面就会被覆盖掉。
  • 子组件如何访问插槽中传来的的内容 this.$slots.slotName 得到一个数组 在线示例 在线示例

render函数

Vue render函数

router

Vue router

Vue中使用axios

Vue中使用axios

Vuex

Vuex