【Vue框架】基础学习笔记

80 阅读8分钟

Vue框架基础

认识Vue:

  1. 需要创建一个Vue实例,传入一个配置对象;
  1. 需要准备一个DOM元素当作root容器(与react类似),root容器中的代码依然符合html规范,不过混入了一些Vue语法;
  1. root容器里的代码被称为【Vue模板】;
  1. Vue实例与容器一一对应;
  1. 真实开发中一般只有一个Vue实例,配合组件一起使用;
  1. {{xxx}}语法只能写js表达式,而且可以自动读取data中的所有属性;
  1. 一旦data中的数据发生改变,那么页面中使用到其数据的地方也会自动更新;(react需要使用setData);

Vue模板语法:

  1. 插值语法: 功能:用于解析标签体内容; 用法:{{xxx}} xxx ==> js表达式,可以读取data中的所有属性;
  1. 指令语法: 功能:用于解析标签(eg. 标签属性、标签体内容、绑定事件...)
    eg.

    v-bind:href=“xxx” or 简写 :href="xxx" ,xxx写js表达式;

Vue数据绑定(2种):

  1. 单向绑定v-bind:数据只能从data流向页面;
    eg.
<input type="text" :value="name"/>
<script>
    Vue.config.productionTip = false; //阻止 vue 在启动时生成生产提示。
    new Vue({
        el:'#root',
        data:{
            name:'greeny'
        }
    })
</script>
  1. 双向绑定v-model:数据从data流向页面,也可以从页面流向data;
    实现原理:value与input事件实现,可以通过v-model实现父子组件数据同步;

vue之组件间v-model通信

备注

  1. 双向绑定一般应用在表单类元素上(eg. input、select);
  2. v-model:value 可以简写为 v-model (因为v-model默认收集value值);
    eg.
<input type="text" v-model="name"/> 
    
<script>
    Vue.config.productionTip = false; //阻止 vue 在启动时生成生产提示。
    new Vue({
        el:'#root',
        data:{
            name:'greeny'
        }
    })
</script>

data与el的写法:

  1. el:2 种:
    (1)new Vue 实例时配置el属性;
    (2)先创建Vue实例,后通过实例vm.$mount("#root")指定el的值;
  1. data :2种:
    (1)对象式
    data:{ name:"xxx" }
    (2)函数式
    data(){ return { name:"xxx" } }

原则

不要写箭头函数,this指向会丢失,不会再是Vue实例;

Vue中的MVVM:

MVVM模型:

  1. M 模型 (Model) : data中的数据
  1. V 视图 (View) : 模板代码
  1. VM 视图模型 (ViewModel) : Vue 实例(通常为vm)

Vue中的MVVM:

  1. data中的所有属性,最后都出现在实例vm上;
  1. 实例vm上所有的属性及Vue原型上所有属性,在Vue模板中都可以直接使用;

eg.

<div id="root">
    <h1>学校名称:{{name}}</h1>
    <h1>学校地址:{{address}}</h1>
    <!--
    <h1>测试一下2:{{$options}}</h1>
    <h1>测试一下3:{{$emit}}</h1>
    <h1>测试一下4:{{_c}}</h1> 
	-->
</div>
<script type="text/javascript">
    Vue.config.productionTip = false; //阻止 vue 在启动时生成生产提示。

    const vm = new Vue({
        el:'#root',
        data:{
            name:'greeny',
            address:'广州',
        }
    })
    console.log(vm)
</script>

Vue数据代理:

Object.defineproperty方法

简书:深入浅出Object.defineProperty()

用法:Object.defineproperty(obj, prop, desc)

obj:需要定义属性的当前对象

prop:当前需要定义的属性名

desc:属性描述符


注意,如果描述符中的某些属性被省略,会使用以下默认规则:


eg.

<script type="text/javascript" >
    let number = 18
    let person = {
        name:'张三',
        sex:'男',
    }

    Object.defineProperty(person,'age',{
        // value:18,
        // enumerable:true, //控制属性是否可以枚举,默认值是false
        // writable:true, //控制属性是否可以被修改,默认值是false
        // configurable:true //控制属性是否可以被删除,默认值是false

        //当有人读取person的age属性时,get函数(getter)就会被调用,且返回值就是age的值
        get(){
            console.log('有人读取age属性了')
            return number
        },

        //当有人修改person的age属性时,set函数(setter)就会被调用,且会收到修改的具体值
        set(value){
            console.log('有人修改了age属性,且值是',value)
            number = value
        }

    })

    // console.log(Object.keys(person))

    console.log(person)
</script>
数据代理:

通过一个对象代理对另一个对象中属性的操作(读/写)

eg.

<script type="text/javascript" >
    let obj = {x:100} //对象代理
    let obj2 = {y:200} //被代理的对象,其x属性值被obj代理操作

    Object.defineProperty(obj2,'x',{
        get(){
            return obj.x
        },
        set(value){
            obj.x = value
        }
    })
</script>
Vue中的数据代理

通过vm对象来代理data对象中属性的操作(读/写);

基本原理:

  1. 通过Object.defineProperty()把data对象中所有属性添加到vm实例身上;
  1. 给每个添加到vm上的属性添加getter和setter;
  1. 在getter/setter内部操作(读/写)data中对应的属性;

事件处理v-on

基本使用
  1. 使用 v-on:事件名@xxx 绑定事件;
  1. 事件回调需要配置在methods对象中,最终挂载在vm上;
  1. methods中配置的函数不能使用箭头函数,要保证this不会丢失;
  1. methods中配置得到函数都是被Vue管理的函数,所以this指向为vm 或 组件实例;
  1. @click="demo"@click="demo($event)"效果一样,但后者可以传参;

事件修饰符

Vue提供的事件修饰符:
  1. prevent:阻止默认事件(常用);
  1. stop:阻止事件冒泡(常用);
  1. once:事件只触发一次(常用);
  1. capture:使用事件的捕获模式;
  1. self:只有event.target是当前操作的元素时才触发事件;
  1. passive:事件的默认行为立即执行,无需等待事件回调执行完毕;

eg.

<div id="root">
    <!-- 阻止默认事件(常用) -->
    <a href="http://www.baidu.com" @click.prevent="showInfo">点我提示信息</a>

    <!-- 阻止事件冒泡(常用) -->
    <div @click="showInfo">
        <button @click.stop="showInfo">点我提示信息</button>
        <!-- 修饰符可以连续写 -->
        <!-- <a href="http://www.atguigu.com" @click.prevent.stop="showInfo">点我提示信息</a> -->
    </div>

    <!-- 事件只触发一次(常用) -->
    <button @click.once="showInfo">点我提示信息</button>

    <!-- 使用事件的捕获模式 -->
    <div @click.capture="showMsg(1)">
        div1
        <div class="box2" @click="showMsg(2)">
            div2
        </div>
    </div>

    <!-- 只有event.target是当前操作的元素时才触发事件; -->
    <div @click.self="showInfo">
        <button @click="showInfo">点我提示信息</button>
    </div>
</div>

<script type="text/javascript">
    Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

    new Vue({
        el:'#root',
        data:{
            
        },
        methods:{
            showInfo(e){
                alert('同学你好!')
                // console.log(e.target)
            },
            showMsg(msg){
                console.log(msg)
            },
        }
    })
</script>
键盘事件
  1. Vue中常用的按键别名(与真正的按键key值不一致)
回车 => enter

删除 => delete (捕获“删除”和“退格”键)

退出 => esc

空格 => space

换行 => tab (特殊,必须配合keydown去使用)

上 => up

下 => down

左 => left

右 => right
  1. 未提供的按键可以用按键原始的key值绑定,但注意要转为kebab-case(短横线命名)
  2. 系统修饰键(特殊):ctrl、alt、shift、meta
    1. 配合keyup使用:按下修饰键的同时,在按下其他键随后释放其他键时间才会触发;
    2. 配合keydown使用:正常触发事件;
  3. Vue.config.keyCodes.自定义键名 = 键码,可以定制按键别名;

计算属性computed

对于任何复杂逻辑,你都应当使用计算属性。——官网

  1. 定义:不存在data属性中,通过已有的属性计算得来的属性;
  1. 原理:底层借助了Object.defineproperty方法提供的getter和setter;
  1. 对比:与methods相比,内部有缓存机制(若没有改变可以被复用),效率高,调试方便;
  1. get方法
    作用:当计算属性被读取时,get会被调用,且返回值作为fullName的值;
    调用:a.初次读取fullName时;b.所依赖的数据发生变化时;
  1. set方法
    作用:计算属性若要修改,需要写set方法去响应修改,且set中要引起依赖的数据发生改变;
    调用:当fullName被修改时;

注意:

计算属性最终会出现在vm实例身上,和data中的属性一样直接读取即可;

<div id="root">
  姓:<input type="text" v-model="firstName"> <br/><br/>
  名:<input type="text" v-model="lastName"> <br/><br/>
  测试:<input type="text" v-model="x"> <br/><br/>
  全名:<span>{{fullName}}</span> <br/><br/>
</div>

<script>
  const vm = new Vue({
    el:'#root',
    data:{
      firtName:'张',
      lastName:'三'
    },
    computed:{
      // 完整写法
      fullName:{
        get(){
          consle.log('get被调用')
          return this.firtName + '-' + this.lastName
        }
        set(value){ //value 全名
          console.log('set',value)
          const arr = value.split('-')
          this.firstName = arr[0]
          this.lastName = arr[1]
        }
    },
      //简写 只读不改
      fullName1(){
        console.log('get被调用')
        return this.firstName + '-' + this.lastName
      }
    }
  })
<script/>

侦听属性watch

  1. 当被监视的属性变化时,回调函数会自动调用,执行函数中的代码;
  1. 监视的属性必须存在才能被监视;
  1. 两种写法:
    1. 和data等属性一样在配置对象中传入watch配置;
    2. 通过vm.$watch()方法监视;
  1. 方法内的配置:
    immediate: true 初始化时让handler调用一下,默认值为false;
    handler(newValue, oldValue){} 简写可以不用写
    deep: true 深度检测
// 写法一
watch:{
  isHot:{
    // immediate:true, //初始化时让handler调用一下
    // deep:true,//深度监视
    handler(newValue,oldValue){
      console.log('isHot被修改了',newValue,oldValue)
    }
  }, 
    //简写
    /* isHot(newValue, oldValue){
    console.log('isHot被修改了',newValue,oldValue,this)
    } */
}
// 写法二
vm.$watch('isHot',{
  immediate:true,
  handler(newValue, oldValue){
  console.log('监听的属性被修改', newValue, oldValue)
}
})
//简写
/* vm.$watch('isHot',(newValue,oldValue)=>{
console.log('isHot被修改了',newValue,oldValue,this)
}) */
computed 和 watch 的对比
  1. computed能完成的功能,watch也能实现;
  1. watch能够进行异步操作,但computed不可以;

两者使用原则

  1. 不能用箭头函数形式;
  1. 不被Vue管理的方法(定时器的回调,Ajax的回调,promise的回调)最好用箭头函数写法,保证this的指向为vm实例或组件实例对象;

绑定样式

class样式

写法 class="xxx" xxx可以为字符串/对象/数组;

字符串适用于类名不确定要动态获取;

对象适用于绑定多个样式,个数确定,名字确定,但不确定是否使用;

数组适用于绑定多个样式,个数不确定,名字也不确定;

style样式

:style="{fontSize: xxx}" xxx 为动态值;

:style-"[a,b]" 其中,a和b为样式对象;

条件渲染

  1. v-if 指令
    写法: v-if = "表达式" 、v-else-if = "表达式" 、v-else = "表达式" ;
    适用于:切换频率低的场景;
    特点:不展示的DOM元素直接被移除;
    注意:v-ifv-else-ifv-else 可以搭配使用,但结构不能被打断;
  1. v-show 指令
    写法:v-show = "表达式"
    适用于:切换频率较高的场景;
    特点:不展示的DOM元素未被移除,仅仅是通过样式 display=none隐藏;

备注: 使用 v-if 的元素可能无法被获取,但使用 v-show 的元素一定能被找到;

<div id="root">
    <!-- 使用v-show做条件渲染 -->
    <h2 v-show="false">欢迎{{name}}</h2>
    <h2 v-show="1 === 1">欢迎{{name}}</h2>
    <!-- 使用v-if做条件渲染 -->
    <h2 v-if="false">欢迎{{name}}</h2>
    <h2 v-if="1 === 1">欢迎{{name}}</h2>
    
    <!-- v-else和v-else-if -->
    <!-- <div v-if="n === 1">Angular</div>
	<div v-else-if="n === 2">React</div>
	<div v-else-if="n === 3">Vue</div>
	<div v-else>哈哈</div> -->
    
    <!-- v-if 与 template 搭配-->
    <!-- 可以将多个结构使用一个v-if指令,且template不会被解析为DOM结构-->
    <template v-if="n === 1">
        <h2>你好</h2
        <h2>北京</h2>
    </template>
    
    
</div>

<script type="text/javascript">
	Vue.config.productionTip = false

	const vm = new Vue({
	el:'#root',
	data:{
		name:'greeny',
		n:0
		}
	})
</script>

列表渲染

v-for 指令

  1. 用于展示列表数据;
  1. 语法:v-for = "( item,index ) in obj" :key="id"
  1. 可遍历类型:数组、对象、字符串(少)、指定次数(少);
<div id="root">
	<!-- 遍历数组 -->
    <h2>人员列表(遍历数组)</h2>
    <ul>
        <li v-for="(p,index) in persons" :key="index">
            {{p.name}}-{{p.age}}
        </li>
    </ul>

    <!-- 遍历对象 -->
    <h2>汽车信息(遍历对象)</h2>
    <ul>
        <li v-for="(value,k) in car" :key="k">
            {{k}}-{{value}}
        </li>
    </ul>

    <!-- 遍历字符串 -->
    <h2>测试遍历字符串(用得少)</h2>
    <ul>
        <li v-for="(char,index) in str" :key="index">
            {{char}}-{{index}}
        </li>
    </ul>

    <!-- 遍历指定次数 -->
    <h2>测试遍历指定次数(用得少)</h2>
    <ul>
        <li v-for="(number,index) in 5" :key="index">
            {{index}}-{{number}}
        </li>
    </ul>
</div>

<script type="text/javascript">
    Vue.config.productionTip = false

    new Vue({
        el:'#root',
        data:{
            persons:[
                {id:'001',name:'张三',age:18},
                {id:'002',name:'李四',age:19},
                {id:'003',name:'王五',age:20}
            ],
            car:{
                name:'奥迪A8',
                price:'70万',
                color:'黑色'
            },
            str:'hello'
        }
    })
</script>
key的作用原理
  1. 虚拟DOM中的key作用:
    key为虚拟DOM对象的唯一标识,当数据发生变化时,Vue会根据变化的数据生成新的虚拟DOM,随后Vue进行新,旧虚拟DOM的差异比较;
  1. 对比规则:
    1. 旧虚拟DOM中找到与新虚拟DOM相同的key:
      ①若虚拟DOM中内容没变,直接使用之前的真实DOM;
      ②若虚拟DOM中内容变了,生成新的真实DOM,随后替换掉页面之前的真实DOM;
    2. 旧虚拟DOM中未找到与新虚拟DOM相同的key:
      创建新的真实DOM,随后渲染到页面; 备注: 对比的虚拟DOM体内容:标签体中的属性值 <input type="text" .../>
  1. index作为key的问题:
    (1) 若对数据进行:逆序添加、逆序删除等破坏顺序的操作,会产生没有必要的真实DOM的更新 ====> 页面渲染没有问题,但是效率低;
    (2) 如果结构中包含输入类的DOM,会产生DOM的错误更新 ====> 页面渲染有问题;
  1. 开发中的key定义:
    (1) 最好使用每条数据的唯一标识作为key,eg. id、手机号、身份证号、学号;
    (2) 如果不存在数据的逆序添加、删除等破坏顺序的操作,仅用于渲染列表展示则使用index作为key没有问题;
<div id="root">
    <!-- 遍历数组 -->
    <h2>人员列表(遍历数组)</h2>
    <button @click.once="add">添加一个老刘</button>
    <ul>
        <li v-for="(p,index) of persons" :key="index">
            {{p.name}}-{{p.age}}
            <input type="text">
        </li>
    </ul>
</div>

<script type="text/javascript">
    Vue.config.productionTip = false

    new Vue({
        el:'#root',
        data:{
            persons:[
                {id:'001',name:'张三',age:18},
                {id:'002',name:'李四',age:19},
                {id:'003',name:'王五',age:20}
            ]
        },
        methods: {
            add(){
                const p = {id:'004',name:'老刘',age:40}
                this.persons.unshift(p)
            }
        },
    })
</script>
模拟数据检测(修改操作的监测)

依靠Object.defineProperty()方法

js 里的连等复习

<script type="text/javascript" >
	let data = {
        name:'greeny',
        address:'广州'
    }
    // 创建一个监视的实例对象,用于监视data中的属性变化
    const obs = new Observer(data)
    console.log(obs)
    
    //准备一个vm实例
    let vm = {}
    vm._data = data = obs
    
    // 执行前,将 vm 的引用 和 data 一致 都是 vm的指向
    // 内存中创建新的对象为obs
    // data = obs : 将data中的指向改为新的obs地址
    // vm._data = data : 此时data已经指向新对象(与vm一致),但vm._data的vm没有改变
    //   给vm添加一个属性_data,内容为obs(此刻的data)
    // 原对象vm添加了_data属性,data指向obs
    
    function Observer(obj){
        //汇总监视对象的所有属性形成一个数组
        const keys = Object.keys(obj)
        //遍历
        keys.forEach((k)=>{
            Object.defineProperty(this, k, {
                get(){
                    return obj[k]
                }
                set(val){
                	console.log(`${k}被修改`)
                	obj[k] = val
            	}
            })
        })
    }
    
</script>
Vue.set 的使用
<div id="root">
    <h1>学校信息</h1>
    <h2>学校名称:{{school.name}}</h2>
    <h2>学校地址:{{school.address}}</h2>
    <h2>校长是:{{school.leader}}</h2>
    <hr/>
    <h1>学生信息</h1>
    <button @click="addSex">添加一个性别属性,默认值是男</button>
    <h2>姓名:{{student.name}}</h2>
    <h2 v-if="student.sex">性别:{{student.sex}}</h2>
    <h2>年龄:真实{{student.age.rAge}},对外{{student.age.sAge}}</h2>
    <h2>朋友们</h2>
    <ul>
        <li v-for="(f,index) in student.friends" :key="index">
            {{f.name}}--{{f.age}}
        </li>
    </ul>
</div>

<script>
	const vm = new Vue({
        el:'#root',
        data:{
            school:{
                name:'xxx大学',
            	address:'广州',
            },
            student:{
                name:'tom',
                age:{
                    realAge:40,
                    fakeAge:18
                },
                friends:[
                    {name:'jerry',age:35},
                	{name:'tomy',age:36}
                ]
            }
        },
        methods:{
            addSex(){
                // Vue.set(this.student,'sex','男')
                this.$set(this.student, 'sex', '男')
            }
        }
    })
</script>

Vue数据监测原理:

  1. Vue会监视data中所有层次的数据;
  1. 监测对象中的数据:
    通过setter实现监视,且需要在new 实例的时候传入监测的数据;
    (1) 对象中后追加的属性,Vue默认不做响应式处理;
    (2) 后添加的属性需要做响应式,需使用特定API:

    Vue.set(target, propertyName/index, value)
    vm.$set(target, propertyName/index, value)

  2. 监测数组中的数据:
    通过包裹数组更新元素的方法实现,本质做了以下两件事:
    (1) 调用原生对应的方法对数组进行更新;
    (2) 重新解析模板,进而更新页面;

  1. 在Vue修改数组中某个元素的数据时一定要使用如下方法,才能被Vue监测到:
    (1) 使用这些API: push()、pop()、shift()、unshift()、splice()、sort()、reverse()
    (2) Vue.set()vm.$set()

注意:

Vue.set() 和 vm.$set() 不能给vm 或 vm的根数据对象 添加属性!!!

表单数据收集

<input type="text"/>,则v-model收集的是value值,用户输入的就是value值;

<input type="radio"/>,则v-model收集的是value值,且要给标签配置value;

<input type="checkbox"/>

  1. 没有配置input的value属性,收集的是checked值[true/false];
  1. 配置了input的value属性:
    (1)v-model的初始值是非数组,收集的是checked[true/false];
    (2)v-model的初始值是数组,收集的是value组成的数组

备注: v-model的 3 个修饰符:

  1. lazy 失去焦点再收集
  1. number 输入字符串转为有效数字
  1. trim 输入首尾空格过滤【中间的不过滤】

过滤器

对要显示的数据进行特定格式化后再显示(适用于一些简单的逻辑处理)
语法:

  1. 注册过滤器: Vue.filter(name, callback) 【全局过滤器】或 new Vue{filters:{}} 【局部过滤器】;
  1. 使用过滤器:{{xxx | 过滤器名}}v-bind:属性 = "xxx | 过滤器名"

备注:

  1. 过滤器也可以接收额外参数、多个过滤器可以串联;
  1. 没有改变原本的数据,是产生新的对应的数据;

eg.

<!-- html标签内,引用一下dayjs -->
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript" src="../js/dayjs.min.js"></script>

<!-- body标签内 -->
<div id="root">
    <h2>显示格式化后的时间</h2>
    <!-- 计算属性实现 -->
    <h3>现在是:{{fmtTime}}</h3>
    <!-- methods实现 -->
    <h3>现在是:{{getFmtTime()}}</h3>
    <!-- 过滤器实现 -->
    <h3>现在是:{{time | timeFormater}}</h3>
    <!-- 过滤器实现(传参) -->
    <h3>现在是:{{time | timeFormater('YYYY_MM_DD') | mySlice}}</h3>
    <h3 :x="msg | mySlice">greeny</h3>
</div>

<div id="root2">
    <h2>{{msg | mySlice}}</h2>
</div>

<!-- body标签外 -->
<script type="text/javascript">
    Vue.config.productionTip = false
    //全局过滤器
    Vue.filter('mySlice',function(value){
        return value.slice(0,4)
    })

    new Vue({
        el:'#root',
        data:{
            time:1642149874736, //时间戳
            msg:'你好,同学'
        },
        computed: {
            fmtTime(){
                return dayjs(this.time).format('YYYY年MM月DD日 HH:mm:ss')
            }
        },
        methods: {
            getFmtTime(){
                return dayjs(this.time).format('YYYY年MM月DD日 HH:mm:ss')
            }
        },
        //局部过滤器
        filters:{
            timeFormater(value,str='YYYY年MM月DD日 HH:mm:ss'){
                // console.log('@',value)
                return dayjs(value).format(str)
            }
        }
    })

    new Vue({
        el:'#root2',
        data:{
            msg:'hello,nihao!'
        }
    })
</script>

内置指令

v-text

  1. 作用:向其所在的节点中渲染文本内容;
  1. 与插值语法区别:v-text 会替换掉节点中的内容,插值语法{{xxx}} 不会;

v-html

  1. 作用:向指定的节点中渲染包含html标签结构的内容;
  1. 与插值语法区别:
    (1)v-html 会替换掉节点中的所有内容,{{xxx}}不会;
    (2)v-html 可以识别到html结构;
  1. 注意:v-html 存在安全问题
    (1)在网站上动态渲染任意HTML是危险的,容易导致xss攻击;
    (2)要在可信的内容上使用v-html,不能在用户提交的内容上使用;

v-cloak

  1. 本质是一个特殊属性,Vue实例创建完毕并接管容器后,会将这个属性删除;
  1. 使用css配合v-cloak可以解决网速慢时页面出现插值语法{{内容}}的问题;

v-once

  1. v-once所在节点在初次动态渲染后,就被视为静态的内容;
  1. 以后的数据变化不会引起v-once所在结构的更新,所以可以用于优化性能;

v-pre

  1. 跳过其所在节点的编译过程;
  1. 可以利用它跳过没有使用指令语法/插值语法的节点,可以优化编译;

自定义指令

自定义指定的回调函数会传入指令绑定的元素节点、以及一个binding对象

其配置对象中的回调函数的 this指向===>window

其配置对象中常用的3个回调:

(1)bind: 指令与元素成功绑定时调用;

(2)inserted: 指令所在元素被插入页面时调用;

(3)update: 指令所在模板结构被重新解析时调用;

eg.

定义一个 v-fbind 指令,与v-bind相似,但可以把其所绑定的input元素默认获取焦点

  1. 全局定义

Vue.directive(指令名称, 配置对象)Vue.directive(指令名, 回调函数)

<div id="root">
    <input type="text" v-fbind:value="n"/>
</div>

<script>
	//定义全局的自定义指令
    Vue.directive('fbind'),{
        //指令与元素成功绑定时(一开始)
        bind(element, binding){
            element.value = binding.value;
        },
        //指令所在元素被插入页面时(页面已经存在该元素)
        inserted(element, binding){
            element.focus();
        },
        //指令所在的模板被重新解析时
        update(element, binding){
            element.value = binding.value;
        }
    }
</script>
  1. 局部定义

new Vue({ directives: {指令名 : 配置对象} })new Vue({ directives: {指令名:回调函数 } })

<div id="root">
    
</div>

<script>
	new Vue({
		el:'#root',
        data:{
            n:1
        },
        directives:{
            fbind:{
                //指令与元素成功绑定时(一开始)
                bind(element, binding){
                    element.value = binding.value;
                },
                //指令所在元素被插入页面时(页面已经存在该元素)
                inserted(element, binding){
                    element.focus();
                },
                //指令所在的模板被重新解析时
                update(element, binding){
                    element.value = binding.value;
                }
            }
        }
	})
</script>

Vue的生命周期

常用的生命周期钩子:

  1. mounted 发送Ajax请求、启动定时器、绑定自定义事件、订阅消息等初始化操作
  1. beforeDestroy 清除定时器、解绑自定义事件、取消订阅消息等收尾工作

备注:

  1. 第一个生命钩子,所谓的 before Create 是在数据监测、数据代理初始化之前,并不是vm实例创建之前 ;

  2. 与第一个钩子对应,所谓的 created 是数据监测、数据代理初始化完成,所以可以通过vm访问到data中的数据、methods中配置的方法;

关于销毁Vue实例:

  1. 销毁后在Vue开发者工具中不能看到任何信息(除非有缓存);
  1. 销毁后自定义事件失效,但原生的DOM事件会存在依然有效;
  1. 一般不在beforeDestroy中操作数据,因为即使操作数据也无法触发更新流程;
<!-- body内 -->
<div id="root" :x="n">
    <h2 v-text="n"></h2>
    <h2>当前的n值是:{{n}}</h2>
    <button @click="add">点我n+1</button>
    <button @click="bye">点我销毁vm</button>
</div>
<!-- body内 -->

<script type="text/javascript">
    Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

    new Vue({
        el:'#root',
        // template:`
        // 	<div>
        // 		<h2>当前的n值是:{{n}}</h2>
        // 		<button @click="add">点我n+1</button>
        // 	</div>
        // `,
        data:{
            n:1
        },
        methods: {
            add(){
                console.log('add')
                this.n++
            },
            bye(){
                console.log('bye')
                this.$destroy()
            }
        },
        watch:{
            n(){
                console.log('n变了')
            }
        },
        beforeCreate() {
            console.log('beforeCreate')
        },
        created() {
            console.log('created')
        },
        beforeMount() {
            console.log('beforeMount')
        },
        mounted() {
            console.log('mounted')
        },
        beforeUpdate() {
            console.log('beforeUpdate')
        },
        updated() {
            console.log('updated')
        },
        beforeDestroy() {
            console.log('beforeDestroy')
        },
        destroyed() {
            console.log('destroyed')
        },
    })
</script>

Vue组件

使用步骤:

  1. 定义组件 ( 创建组件 ) ;

    使用Vue.extend(options)创建,其中optionsnew Vue(options)时传入的那个options几乎一样,但也有点区别;

区别如下:

      el不要写,为什么? ——— 最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器。

      data必须写成函数,为什么? ———— 避免组件被复用时,数据存在引用关系。

 备注: 使用template可以配置组件结构。

  1. 注册组件;

    (1) 局部注册:new Vue的时候传入components选项;

    (2) 全局注册:Vue.component('组件名',组件);

  2. 使用组件( 写组件标签 );

<Demo></Demo>

注意:

  1. 关于组件名:

    一个单词:demo 【首字母小写】 / Demo 【首字母大写】;

    多个单词:my-demo 【kebab-case 命名】/ MyDemo【CamelCase命名】;

备注:

1. 组件名尽可能回避HTML中已有的元素名称;

2. 可以使用name配置项指定组件在开发者工具中呈现的名称;

2. 关于组件标签:

写法一: `<demo></demo>`

写法二:`<demo/>`

备注: 写法二需要使用脚手架才能处理渲染到页面上;

  1. 简写方式
//正常写法
const demo = Vue.extend(options) 
//简写
const demo = options
关于VueComponent

组件实例本质是通过名为VueComponent的构造函数创建的,由Vue.extend方法生成;

部分源码:

Vue.extend = function (extendOptions) {
    /*....*/
    var Sub = function VueComponent (options) {
        this._init(options);
    };
    Sub.prototype = Object.create(Super.prototype);
    Sub.prototype.constructor = Sub;
    /*....*/
    return Sub
};

组件中的this指向  ===>  均是VueComponent的实例对象,简称vc【与Vue的实例对象vm要区别开来】;

注意一个内置关系:

VueComponent.prototype.__proto__ === Vue.prototype

通过修改后可以让组件实例访问到Vue原型上的属性和方法;

Vue CLI 脚手架

  1. main.js文件

    整个项目的入口文件

  2. vue.jsvue.runtime.xxx.js的区别

    (1)vue.js 是完整版的Vue,包含 核心功能 + 模板解析器;

    (2)vue.runtime.xxx.js 是只包含核心功能;

  3. 由于入口文件 main.js 中引用的文件不包含模板解析器,不能使用template配置项,需要通过使用 render 函数接收到的createElement函数去指定具体内容;