Vue 学习笔记

Posted by Wei on October 26, 2017

Vue.js 介绍

Vue.js 也称为 Vue,读音类似 view。

Vue 有以下特点:

  • 是一个构建用户界面的框架
  • 是一个轻量级 MVVM(Model-View-ViewModel)框架,和 angular、react 类似
  • 数据驱动 + 组件化的前端开发(核心思想)
  • 通过简单的 API 实现响应式的数据绑定和组合的视图组件
  • 更容易上手、小巧

参考:官网文档

第一个 vue 程序

<div id="main">
    {.{msg}.}  //字符串模板
</div>

<script src="./js/vue.js"></script>   //引入vue文件
<script>
    new Vue({   //创建vue实例
        el: '#main',  //绑定元素
        data: {
            msg: 'hello Vue.js'
        },
        methods:{  //用于存放方法
        }
    })
</script>

以上就是一个非常简单的 vue 程序。绑定元素这里不但可以使用 id 选择器,我们还可以使用类选择器或者标签选择器。但是,vue2.0 中不允许将 vue 实例挂在到 html 或者 body 元素上。

常用指令

指令用来扩展 HTML 功能。vue 内置了很多指令。

v-model

实现双向数据绑定,实时监控数据变化,一般用于表单。

 <div id="main">
    <input type="text" v-model="content">
    
    <br> {.{ content111 }.}
</div>

<script src="./js/vue.js"></script>
<script>
    new Vue({
        el: '#main',
        data: {
            content: ''
        }
    })
</script>

在这里,使用v-model指令将输入框的值与 vue 实例中的 content 进行绑定。此后,二者中的任一值发生变化,另一个值都会跟随变化。

v-for

用于遍历数组、对象等。

<div id="main">
    <ul>
        <li v-for="item in arr">  //遍历数组
            {.{item}.}
        </li>
    </ul>
    
    <ul>
        <li v-for="item in obj">   //遍历对象
            {.{item}.}
        </li>
    </ul>
    
    <ul>      
        <li v-for="(value,key) in obj">   //键值循环,数组也适用,注意key在后面
            {.{key}.}----{.{value}.}
        </li>
    </ul>
</div>

<script src="./js/vue.js"></script>
<script>
    new Vue({
        el: '#main',
        data: {
            arr: [1, 2, 3, 4, 5, 6],
            obj: {
                name: 'hedawei',
                age: 22,
                gender: 'man'
            }
        }
    })
</script>

v-on

用于绑定事件,用法:v-on: 事件 =”函数”。

示例:点击事件

<div id="main">
        <button type="button" v-on:click="showHello()">点击显示</button>
        <br>
        {.{msg}.}
</div>

<script src="./js/vue.js"></script>
<script>
    new Vue({
        el: '#main',
        data: {
            msg:''
        },
        methods: {
            showHello() {
                this.msg = 'Hello Vue.js';
            }
        }
    })
</script>

this指向当前 vue 实例,由此可获取实例的其他属性。除了点击事件外还有很多其他事件,具体参考官网 API。

v-show

用来显示或隐藏元素,v-show 是通过 display 实现。当v-show的值为 true 时显示,为 false 时隐藏。

<div id="main">
    <button type="button" v-on:click="change()">隐藏</button>
    <div style="width:100px;height:100px;background:red" v-show="flag"></div>
</div>

<script src="./js/vue.js"></script>
<script>
    new Vue({
        el: '#main',
        data: {
            flag: true
        },
        methods: {
            change() {
                this.flag = !this.flag;
            }
        }
    })
</script>

事件

之前说了一些关于事件的指令,这里详细学习一下事件的相关知识。

事件简写

之前的事件都是这样的写法:v-on:click="showHello()",vue 提供了一种简写方式: @click=”showHello()”`

事件对象 $event

我们可以通过事件对象取得事件相关信息,如事件源、事件类型、偏移量。

下面这个例子通过事件对象取得按钮的值:

 <div id="main">
    <button type="button" @click="print($event)">点击显示按钮的值</button>
        <br> {.{msg}.}
    </div>

    <script src="./js/vue.js"></script>
    <script>
        new Vue({
            el: '#main',
            data: {
                msg: ''
            },
            methods: {
                print(e) {
                    this.msg = e.target.innerHTML;
                }
            }
        })
    </script>

事件冒泡与事件默认行为

这里需要讨论阻止事件冒泡与阻止默认行为,原生 js 阻止事件冒泡首先得取得事件对象,然后调用事件对象的stopPropagation方法。在 vue 里,则不需要依赖于事件对象,只需要调用相应的事件修饰符stop即可:

@click.stop = "print()"

阻止事件默认行为和阻止事件冒泡基本一致,在 vue 里也有十分便利的操作方法:

@click.prevent = "print()"

键盘事件

vue 里内置了一些键盘事件,便于开发者操作。语法如下:

@keydown.13 = "print()"
@keydown.enter = "print()"

除了回车事件外,还有很多其他键盘事件,例如下:@keydown.38="print()"。还有一些其他键盘事件,具体参考官方文档。

默认没有 @keydown.a/b/c… 事件,可以全局自定义键盘事件,也称为自定义键码或自定义键位别名:

Vue.config.keyCodes = {
  v: 86,
  f1: 112,
  // camelCase 不可用
  mediaPlayPause: 179,
  // 取而代之的是 kebab-case 且用双引号括起来
  "media-play-pause": 179,
  up: [38, 87]
}

除了stoppreventkeyCode这些事件修饰符以外,还有一些比较常用:

  • .native - 监听组件根元素的原生事件。
  • .once - 只触发一次回调。

属性

vue 提供了绑定属性的方法:v-bind:属性名="",这样我们即可动态的改变属性值。

属性简写

属性和事件一样,也有简写方式::属性名=""

class 属性和 style 属性

绑定 class 和 style 属性时的语法比较复杂。

变量形式

html 部分:

<p :class="myClass">Hello vue.js</p>

对应的 vue 的 data 部分:

data:{
    myClass:className
}
数组形式,同时引入多个类

html 部分:

<p :class="[myClass1,myClass2]">Hello vue.js</p>

对应的 vue 的 data 部分:

data:{
    myClass1:className1,
    myClass2:className2,
}
JSON 形式(常用)

html 部分:

<p :class="{className1:true,className2:false}">Hello vue.js</p>
变量引用 JSON 形式

html 部分:

<p :class="myClass">Hello vue.js</p>

对应的 vue 的 data 部分:

data:{
    myClass:{
        className:true
    }
}

style 的用法和 class 的用法基本一致,但是不常用。

模板

Vue.js 使用基于 HTML 的模板语法,可以将 DOM 绑定到 Vue 实例中的数据。模板就是{.{ }.},用来进行数据绑定,显示在页面中,也称为 Mustache 语法。

数据绑定的方式

双向数据绑定

使用v-model指令,前面已经学习过。

单向数据绑定
使用两对大括号 {.{}.}

这个在之前也经常使用,但是有一个缺点,就是 vue 实例需要长时间编译时会在页面中出现{.{}.}(闪烁现象)。vue 提供了一个解决办法:使用v-cloak配合 css。

//html内容
<div id="app" v-cloak>
  {.{msg}.}
</div>

//css内容
[v-cloak] {
 display: none;
}
使用指令 v-text、v-html

v-text也可达到与使用v-cloak相同的效果。

//html内容
<div id="app" v-text="msg">
</div>

v-html会将文本中的 html 解析为 html 标签,然后渲染到页面中。

//html内容
<div id="app" v-html="msg">
</div>

//vue实例中data部分内容
 data: {
    msg: 'hello<mark>vue.js<mark>'
 },

这里的 vue.js 会有一个黄色的背景颜色。

过滤器

过滤器用来过滤模型数据,在显示之前进行数据处理和筛选。语法:{.{ data | filter1(参数) | filter2(参数)}.}

vue1.0 中内置了很多过滤器,但是在 2.0 中全部删除了。使用过滤器我们可以通过使用第三方库:lodash、date-fns 日期格式化、accounting.js 货币格式化。或者我们可以自定义过滤器。

自定义过滤器

过滤器分为全局过滤器和局部过滤器。

全局过滤器

使用全局方法 Vue.filter(过滤器ID,过滤器函数)。

示例:

<p>{.{8|addZero}.}</p>//数据会自动作为传过去

 Vue.filter('addZero', data => {
    return data > 10 ? data : '0' + data;
 });

有时过滤器也要传递自己的参数:

<p>{.{12.3456|number(3)}.}</p>

 Vue.filter('number', (data,n) => {
    return data.toFixed(n);
 });
局部过滤器

局部过滤器的使用方法与全局过滤器的使用方法一致。

不过过滤器写在 vue 实例中 filters 选项中。

new Vue({
    el:'#app',
    data:{},
    filters:{
        number:data => {
            //具体操作
        }
    }
})

vue 生命周期

vue 实例从创建到销毁的过程,称为生命周期,共有八个阶段。

这八个阶段里分别有一个叫做钩子函数的实例选项。供用户在相应的阶段对其进行操作。

beforeCreate(){  //组件实例刚刚创建,还未进行数据观测和事件配置
                
},
created(){  //实例已经创建完成,并且已经进行数据观测和事件配置
                
},
beforeMount(){//模板编译之前,还没挂载
                
},
mounted(){ //模板编译之后,已经挂载,此时才会渲染页面,才能看到页面上数据的展示
                    
},
beforeUpdate(){//组件更新之前
                
},
updated(){//组件更新之后
                
},
beforeDestroy(){//组件销毁之前
                
},
destroyed(){  //组件销毁之后
                    
}

这几个钩子中,最常用的是created()mounted()

计算属性

计算属性也是用来存储数据,但具有以下几个特点:

  • 数据可以进行逻辑处理操作
  • 对计算属性中的数据进行监视

基本用法

<div id="app">
    {.{addZero}.}
</div>
    
new Vue({
    el: '#app',
    data: {
        num: 8
    },
    computed: {
        //这是计算属性的get方法,用于取值
        addZero() {
            return this.num > 10 ? this.num : '0' + this.num;
        }
    }
})

这里的addZeronum一样,都是属性。不过addZero是依赖于num、进行计算后的值。一旦num的值发生变化,addZero的值也会随之变化。

 <div id="app">
    {.{num}.}----{.{addZero}.}
    <br>
    <button type="button" @click="change">点击改变num</button>
 </div>
    
 new Vue({
    el: '#app',
    data: {
        num: 8
    },
    methods: {
        change: () => {
            this.num++;
        }
    },
    computed: {
        addZero:() => {
            return this.num > 10 ? this.num : '0' + this.num;
        }
    }
 })

一旦我们点击按钮改变num的值,那么因为计算属性实时监测依赖项,addZero也会跟着发生变化。

计算属性 vs 方法

将计算属性的 get 函数定义为一个方法也可以实现和计算属性类似的功能。那么二者之间有什么区别?

  • 区别一:计算属性是基于它的依赖进行实时更新的,方法则是调用才更新
  • 区别二:计算属性是有缓存的,只要相关依赖没有改变,多次访问计算属性得到的值是之前缓存的计算结果,不会多次执行。操作一个没有依赖项的值也是如此。 官方文档给出了下面这个例子:
    computed: {
    now: function () {
      return Date.now()
    }
    }
    

    计算属性存在缓存,这里的now值不会发生变化。

get 和 set

计算属性由两部分组成:get 和 set,分别用来获取计算属性和设置计算属性。默认只有 get,如果需要 set,要自己添加。

        <div id="app">
        {.{num}.}----{.{addZero}.}
        <br>
        <button type="button" @click="change(5)">点击改变num</button>
    </div>
    
   new Vue({
        el: '#app',
        data: {
            num: 8
        },
        methods: {
            change(newNumber) {
                this.addZero = newNumber;
            }
        },
        computed: {
            addZero: {
                get() {
                    return this.num > 10 ? this.num : '0' + this.num;
                },
                set(newNum) {
                    this.num = newNum
                }
            }
        }
    })

我们再change方法中改变addZero属性的值的时候会自动调用它的 set 方法。

实例属性和方法

vue 中给实例和属性提供了若干属性和方法。

属性

获取属性的语法:实例名.属性名 以下是常用的属性:

  • vm.$el: 获取 vue 实例关联的元素 DOM,进而可以对其进行操作
  • vm.$data: 获取数据对象 data
  • vm.$options:获取选项,自定义的选项也可以在这里获取。
  • vm.$refs:获取所有添加 ref 属性的元素 dom 对象,进而可以对其进行操作

方法

vm.$mount()

手动挂载 vue 实例

var vm=new Vue({
    data:{
        msg:'Hello vue.js'
    }
 }).$mount('#app');
vm.$destroy()

销毁实例

vm.$destroy(); //销毁实例所占的内存空间
vm.$nextTick(callback)

在 DOM 更新完成后再执行回调函数,一般在修改数据之后使用该方法,以便获取更新后的 DOM

var vm=new Vue({
    data:{
        msg:'Hello vue.js'
    }
 }).$mount('#app');
 
 //修改数据
 vm.msg='foo';
 
 console.log(vm.$refs.title.textContent);  //Hello vue.js
 vm.$nextTick(function(){
    console.log(vm.$refs.title.textContent); //foo
 });

DOM 还没更新完,Vue 实现响应式并不是数据发生改变之后 DOM 立即变化,需要按一定的策略进行 DOM 更新,需要时间!使用$nextTick方法等 DOM 更新完再获取数据。

vm.$set(target,key,value)

通过 vue 实例的 $set 方法为对象添加属性,可以实时监视。

<div id="app">
    {.{user.name}.}<br> {.{user.age}.}
    <br>
    <button type="button" @click="addAge">添加属性</button>
</div>
    
var vm = new Vue({
    data: {
        msg: 'Hello vue.js',
        user: {
            name: 'hedawei',
            gender: 'man'
        }
    },
    methods: {
        addAge() {
            /* this.user.age = 22; */
            this.$set(this.user, 'age', 22);
        }
    }
}).$mount('#app');

方法中使用原始的添加属性方法的话不会在模板中显示。使用$set方法会实时监控数据,然后添加。

vm.$watch(监听的属性,callback)

监控 vue 实例的变化

 vm.$watch('msg', (newValue, oldValue) => {
    console.log('msg被修改啦,原值:' + oldValue + ',新值:' + newValue);
 });

如果需要监控深度数据变化(例如监控一个对象中的某个属性),则需要在选项中添加{deep:true}

自定义指令

自定义指令分为自定义全局指令和自定义局部指令。

自定义全局指令

使用全局方法 Vue.directive (指令ID,定义对象)。注:使用指令时必须在指名名称前加前缀 v-,即v-指令名称`。

简单示例:

Vue.directive('hello',{
    bind(){ //常用!!
        alert('指令第一次绑定到元素上时调用,只调用一次,可执行初始化操作');
    },
    inserted(){
        alert('被绑定元素插入到DOM中时调用');
    },
    update(){
        alert('被绑定元素所在模板更新时调用');
    },
    componentUpdated(){
        alert('被绑定元素所在模板完成一次更新周期时调用');
    },
    unbind(){
        alert('指令与元素解绑时调用,只调用一次');
    }
 });

这里定义了一个名为hello的指令,指令定义函数提供了几个钩子函数,分别在不同的时期生效。我们像下面这样使用这个指令:

<p v-hello>hello vue.js</p>

大多数情况下,我们只需要使用bindupdate钩子函数。vue 里提供了函数的简写形式:

Vue.directive('hello', function () {
    alert("hello vue.js");
})  

钩子函数有两个常用的参数elbindingel是绑定的 DOM 对象,binding是一个对象,包含若干属性。

拿到 DOM 对象,我们就可以对 DOM 进行一些操作。

<p v-hello="msg">hello vue.js</p>

Vue.directive('hello', function (el,binding) {
    el.style.color = "red";
    
    //属性name是指令的名字(不带v-)
    console.log(binding.name);     //hello
    //属性value是传递给指令的值
    console.log(binding.value);   //alice
    //属性expression是指令值的字符串形式(个人感觉就是类似变量名)
    console.log(binding.expression);  //msg
    //属性arg是传递给指令的参数(和传值写在一起容易令初学者困惑,下面分开写  
    //合在一起写的写法是<p v-hello:123="msg">hello vue.js</p>)
    //<p v-hello:123>hello vue.js</p>
    console.log(binding.arg);       //123
    //属性modifiers是一个包含修饰符的对象。
    //与传参传值合在一起的写法是 <p v-hello:123.bar="msg">hedawei</p>
    //<p v-hello.bar>hello vue.js</p>
    console.log(binding.modifiers);    //{bar:true}
})  

 var vm = new Vue({
    el: '#app',
    data: {
        msg: 'alice'
    }
 })

局部自定义指令

局部自定义指令写在实例的directives选项中。

  var vm = new Vue({
    el: '#app',
    data: {
        msg: 'alice'
    },
    methods: {
    },
    directives: {
        word: function(el, binding) {
            console.log(binding.name);
        }
    }
 })

其他用法与全局自定义指令一致。

过渡(动画)

Vue 在插入、更新或者移除 DOM 时,提供多种不同方式的应用过渡效果。本质上还是使用 CSS3 动画:transition、animation 属性。

基本用法

使用 transition 组件,将要执行动画的元素包含在该组件内:

<transition name="fade">
        运动的元素
</transition>

我们需要为其定义一个name属性,以便后面为其添加 css 样式。

动画有 6 个 CSS 类名,下面结合的例子说明:

<style>
        button {
            display: block;
            margin: 20px auto;
        }
        
        p {
            width: 100px;
            height: 100px;
            background-color: red;
            margin: 0 auto;
        }
        
        .fade-enter-active,
        .fade-leave-active {   //定义整个过渡期间的效果
            transition: all 2s ease;
        }
        
        .fade-enter-to {    //定义过渡进入的最终效果
            opacity: 1;
            width: 100px;
            height: 100px;
        }
        
        .fade-leave-to {    //定义过渡离开的最终效果
            opacity: 0;
            width: 50px;
            height: 50px;
        }
        
        .fade-enter {      //定义过渡进入的开始效果
            opacity: 0;
            width: 50px;
            height: 50px;
        }
    </style>
    
    <div id="app">
        <button type="button" @click="flag = !flag">点 击</button>
        <transition name="fade">
            <p v-show="flag">
            </p>
        </transition>
    </div>
    
    <script>
        new Vue({
            el: '#app',
            data: {
                flag: false
            }
        });
    </script>

钩子函数

vue 中给过渡的不同时期提供了不同的钩子函数。

<transition name="fade" @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter" @before-leave="beforeLeave" @leave="leave" @after-leave="afterLeave">
        <p v-show="flag">
        </p>
</transition>
        
 new Vue({
    methods: {
        beforeEnter(el) {
            alert('动画进入之前');
        },
        enter(el) {
            alert('动画进入');
        },
        afterEnter(el) {
            alert('动画进入之后');
        },
        beforeLeave(el) {
            alert('动画离开之前');
        },
        leave(el) {
            alert('动画离开');
        },
        afterLeave(el) {
            alert('动画离开之后');
        }
    }
 });

在这不同的时期,我们可以取到过渡元素的 DOM 对象,从而对其进行操作。

多元素过渡

上面的标签只适用于单元素过渡。若要对多元素进行过渡,则需要使用标签,并且绑定key属性,设置不同的值。

<button type="button" @click="flag = !flag">点 击</button>
<transition-group name="fade">
    <p v-show="flag" :key="1">
    </p>
    <p v-show="flag" :key="2">
    </p>
</transition-group>

结合第三方库一起使用(animate.css)

我们可以使用 vue 的自定义过渡类名结合第三方动画库实现自定义动画效果。这六个自定义类名和 vue 内置的类名类似:

  • enter-class
  • enter-active-class
  • enter-to-class
  • leave-class
  • leave-active-class
  • leave-to-class

示例:

p {
    width: 300px;
    height: 300px;
    background-color: red;
    margin: 0 auto;
 }

 <div id="app">
    <button type="button" @click="flag = !flag">点 击</button>
    <transition enter-active-class="animated tada" leave-active-class="animated bounceOutRight">
        <p v-show="flag">
        </p>
    </transition>
</div>

 <script>
    new Vue({
        el: '#app',
        data: {
            flag: false
        }
    });
 </script>

组件

什么是组件

组件(Component)是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码组件是自定义元素(对象)。

创建组件的两种方式

官方推荐组件标签名是使用-连接的组合词,例如:<my-hello></my-hello>

使用构造器创建组件

使用这种方式创建组件首先需要使用Vue.extend()创建一个组件构造器,然后使用Vue.component(标签名,组件构造器),根据组件构造器来创建组件。

//1.创建构造器
var MyComponent=Vue.extend({
    template:'<h3>Hello World</h3>'
});
//2.创建组件
Vue.component('my-hello',MyComponent);

//3.使用组件
<div id="app">
    <my-hello></my-hello>
</div>

这种创建组件的方式比较麻烦,使用的较少。

直接创建组件

使用Vue.component(标签名,组件模板)`,根据组件构造器来创建组件。

//1.创建组件
 Vue.component('my-world', {
    template: '<h2>hello vue.js</h2>'
 });
 
//2.使用组件
<div id="app">
    <my-world></my-world>
</div>

组件的分类

组件分为全局组件和局部组件。

全局组件

使用Vue.component()创建的组件都是全局组件。这样的组件在任何组件内都能使用。上面我们创建就是全局组件。

局部组件

局部组件一般都是定义在实例的选项中,称为实例的子组件。相应的,实例也被称为父组件。

//1.定义组件
 new Vue({
    el: '#app',
    components: {
        dawei: {
            template: '<h2>my name is dawei</h2>'
        }
    }
});
//2.使用组件
<div id="app">
    <dawei></dawei>
</div>

引用模板

很多时候我们的template模板中需要存放很多标签内容,这样的话写起来会很麻烦。这时候我们可以使用template标签。

用法如下:

<template id="wbs">    //使用template标签
    <div>
        <h2>hello {.{msg}.}</h2>
        <ul>
            <li v-for="value in arr">
                {.{value}.}
            </li>
        </ul>
    </div>
</template>
    
    new Vue({
        el: '#app',
        components: {
            'my-dawei': {
                template: '#wbs',  //选择template标签
                data() {
                    return {
                        msg: 'vue.js',
                        arr: ["a", "b", "c", "d"]
                    }
                }
            }
        }
    });

这里涉及到的几个知识点得着重提一下:

  • template模板中,所有的元素必须放置在一个根元素中,要不然会报错。例子中我们将元素放置在了<div>标签中。
  • 组件中的data选项必须是一个函数类型,使用return返回所有的数据。

动态组件

很多时候项目中需要在某一个地方动态的使用不同的组件,这时候就需要使用动态组件。 动态组件的使用需要绑定is属性:

<component :is="flag"></component>

简单示例:

//点击按钮显示不同的组件
 <div id="app">
    <button type="button" @click="flag='my-a'">显示a组件</button>
    <button type="button" @click="flag='my-b'">显示b组件</button>

    <component :is="flag"></component>  //传入flag
</div>

new Vue({
    el: '#app',
    data: {
        flag: 'my-a'   //给flag赋值
    },
    components: {
        'my-a': {
            template: '<p>我是a组件</p>',
        },
        'my-b': {
            template: '<p>我是b组件</p>'
        }
    }
});

keep-alive 组件

使用keep-alive组件缓存非活动组件,可以保留状态,避免重新渲染,默认每次都会销毁非活动组件并重新创建。

使用范例:

<keep-alive>
     <component :is="flag"></component>
</keep-alive>

 <div id="app">
    <button type="button" @click="flag='my-x'">x</button>
    <button type="button" @click="flag='my-y'">y</button>
    <keep-alive>
        <component :is="flag"></component>
    </keep-alive>
 </div>
 
 new Vue({
    el: '#app',
    data: {
        flag: 'my-x'
    },
    components: {
        'my-x': {
            template: '<p>{.{x}.}</p>',
            data() {
                return {
                    x: Math.random()
                }
            }
        },
        'my-y': {
            template: '<p>{.{y}.}</p>',
            data() {
                return {
                    y: Math.random()
                }
            }
        }
    }
 });

这样的话,第一次产生的随机数就会被缓存,再次切换的时候也不会发生改变。

组件间数据传递

父子组件

在一个组件内部定义另一个组件,那么这对组件称为父子组件。子组件只能在父组件内部使用。默认情况下,每个组件实例的作用域是独立的,子组件无法访问父组件中的数据,同样,父组件也无法访问子组件中的数据。

<div id="app">
    <my-a></my-a>
        <!-- 父组件 -->
</div>

<template id="a">
    <div>
        <p>{.{msg}.}</p> 
        <my-b></my-b>    <!-- 在父组件中调用子组件 -->
    </div>
</template>

<template id="b">
    <div>
        <p>{.{mydata}.}</p>
    </div>
</template>

<script>
    new Vue({   //根组件
        el: '#app',
        components: {     //子组件写在components选项中
            "my-a": {     //b组件的父组件
                template: "#a",
                data() {
                    return {
                        msg: '我是父组件',
                    }
                },
                components: { //子组件写在父组件的components选项中
                    "my-b": {
                        template: "#b",
                        data() {
                            return {
                                mydata: "我是子组件"
                            }
                        }
                    }
                }
            }
        }
    });
</script>

组件间数据传递(通信)

子组件访问父组件的数据

步骤:

  • a、调用子组件时,绑定想要获取的父组件中的数据
  • b、在子组件内部,使用 props 选项声明获取的数据,即接收来自父组件的数据 改进上面的例子:
<div id="app">
    <my-a></my-a>
</div>

<template id="a">
    <div>
        <p>{.{msg}.}</p> 
        <p>这是要传递给子组件的值:{.{myname}.}</p>
        <my-b :name="myname"></my-b>   <!-- 绑定子组件想要获取的数据 -->
    </div>
</template>

<template id="b">
    <div>
        <p>{.{mydata}.}</p>
        <p>这是父组件传递过来的数据:{.{name}.}</p>
    </div>
</template>

<script>
    new Vue({
        el: '#app',
        data: {},
        components: {
            "my-a": {
                template: "#a",
                data() {
                    return {
                        msg: '我是a组件',
                        myname: '子组件b你好,我是父组件a'
                    }
                },
                components: {
                    "my-b": {
                        template: "#b",
                        data() {
                            return {
                                mydata: "我是b组件"
                            }
                        },
                        props: ["name"] //子组件使用props声明想要获取的数据
                    }
                }
            }
        }
    });
</script>
父组件访问子组件的数据

步骤:

  • a 在子组件中使用 vm.$emit(事件名, 数据) 触发一个自定义事件,将数据发送给父组件,事件名自定义
  • b 父组件在使用子组件的地方监听子组件触发的事件,并在父组件中定义方法,用来获取数据
//子组件‘my-b’内部
methods:{
    send(){//使用$emit()触发一个事件,发送数据,this指当前子组件实例
        this.$emit('e-world', this.senddata);         
    }
}

//在调用子组件的地方监听子组件触发的事件,调用自己的方法获取数据
<my-b @e-world="getData"></my-b>   


 methods: {
    getData(data) {  //参数是子组件传递过来的数据
        this.revicedata = data;
    }
 }
单向数据流

props 是单向数据绑定的,当父组件数据发生变化时,将传递给子组件,但是不会反过来。而且不允许子组件直接修改父组件中的数据,强制修改会报错。

解决方案:

  • 如果子组件想把它作为局部数据来使用,可以将数据存入另一个变量中再操作,不影响父组件中的数据
  • 如果子组件想修改数据并且同步更新到父组件,两个方法:
  • 使用.sync显式地触发一个更新事件(1.0 版本中支持,2.0 版本中不支持,2.3 版本又开始支持)
//使用.sync
 <my-b :name.sync="myname"></my-b> 
 
//子组件修改父组件传入的值name,触发update更新事件
this.$emit('update:name', "vuejs"); 
  • 可以将父组件中的数据包装成对象,然后在子组件中修改对象的属性 (因为对象是引用类型,指向同一个内存空间),推荐使用这种方式。
 data() {
    return { //将要传递的数据放入message对象中
        message: {
            hello: '子组件b你好,我是父组件a'
        }
    }
}

<my-b :message="message"></my-b>   //传递这个对象给子组件

 methods: {   //在子组件内部修改这个值,这样就会同步传递给父组件。
    edit() {
        this.message.hello = "hahahahh";
    }
 }
非父子组件间的通信

非父子组件间的通信,可以通过一个空的 Vue 实例作为中央事件总线(事件中心),用它来触发事件和监听事件,从而实现非父子组件间的通信。

var Event = new Vue();    //空vue实例

 methods: {  
    send() {  //触发emit事件
        Event.$emit("hello", this.asmsg);
    }
 }
 
 mounted() {    //在子组件的钩子函数中监听该事件
    Event.$on('hello', data => {   //获取值
        this.bsmsg = data;  
    })
 }

slot 内容分发

用来获取组件中的原内容

var vm = new Vue({
    el: '#app',
    components: {
        'my-hello': {
            template: '#hello'
        }
    }
});

<div id="app">
    <my-hello>hello vue.js</my-hello>
</div>


<template id="hello">
    <div>
        <slot>如果没有原内容,则显示该内容</slot>
    </div>
</template>

如果组件标签中没有内容就会显示 slot 中的内容,这也就是所谓的单个插槽。

还可以对显示的内容进行分组,这就是具名插槽,可以操作标签组中的内容:

<div id="app">
    <my-hello>
        <ul slot="s1">
            <li>aaa</li>
            <li>bbb</li>
            <li>ccc</li>
        </ul>
        <ol slot="s2">
            <li>111</li>
            <li>222</li>
            <li>333</li>
        </ol>
    </my-hello>
</div>

<template id="hello">
    <div>
        <slot name="s2"></slot> //为插槽指定名称  将名为s2的内容放置在这里
        <p>hello vue.js</p>
        <slot name="s1"></slot>  //将名为s1的内容放置在这里
    </div>
</template>

这样,就可以对组件中的内容实时操作。

vue-router

简介

我们经常使用 vue 开发单页面应用程序(SPA)。在开发 SPA 过程中,路由是必不可少的部分,vue 的官方推荐是 vue-router。单页面应用程序看起来好像是一个页面,其实是在一个页面中切换不同的 html 部分,从而达到所谓的单页面, 在这切换之中,就需要使用路由来实现不同的页面内容的展现。

基本用法

使用步骤

vue-router 的基本使用步骤如下:

  • 定义需要切换的组件
  • 配置路由,规定路径到组件的映射关系
  • 创建路由实例
  • 将路由挂载到 vue 实例
//1.定义组件,用于路由切换
var Home = {
    template: '<div>我是主页</div>'
}
var News = {
    template: '<div>我是新闻</div>'
}

//2.配置路由
const routes = [{
        path: '/home',
        component: Home
    },{
        path: '/news',
        component: News
    },{ //这一路由配置用于首次访问或者找不到所请求路由,自动跳转home页
        path: '*',
        redirect: '/home'
}];

//3.创建路由实例
var router = new VueRouter({
    routes  //传入配置好的路由信息
});

//4.挂载路由到根组件
new Vue({
    el: '#app',
    router 
});

这样我们就配置好了一个完整的路由。在切换组件的时候会根据路由加载不同的组件。我们使用类似 a 标签的<router-link to="url"></router-link>触发组件的切换,to属性存放的是路径。使用<router-view></router-view>来显示所切换组件。

<div id="app">
    <router-link to="/home">主页</router-link>
    <router-link to="/news">新闻</router-link>

    <router-view></router-view>
</div>

这样我们就可以实现主页和新闻组件间的切换。

参数传递

可能我们需要向所切换组件传递参数。vue 提供了两种向组件传递参数的方式。

  • 查询字符串的形式
  • /home?name=dawei&pwd=666
  • 在组件内部使用{.{$route.query}.}接收参数
  • rest 风格
  • /news/param1/param2
  • 在组件内部使用{.{$route.params}.}接收参数
路由嵌套

路由还可以多层嵌套使用,使用children属性。

{
    path:'/user',
    component:User,
    children:[
        {
            path:'login',  
            component:Login
        },
        {
            path:'regist',
            component:Regist
        }
    ]
}

子路由项路径不要使用/开头,以/开头的嵌套路径会被当作根路径。

在组件中就可以使用该路由:

<div>
    <h3>用户信息</h3>
    <ul>
        <router-link to="/user/login">用户登陆</router-link>
        <router-link to="/user/regist">用户注册</router-link>
    </ul>
    <router-view></router-view>
</div>

注意路径的写法。

路由实例的方法

这里学习两个路由实例的方法:router.push()router.replace()

  • router.push():添加路由,功能上与相同
  • router.replace(): 替换路由,不产生历史记录
router.push({path:'home'})
router.replace({path:'user'})

路由结合动画

路由结合动画使用很简单,我们可以用 组件给它添加一些动画效果:

<transition>
  <router-view></router-view>
</transition>

单文件组件

.vue 文件

.vue文件称为单文件组件,是 Vue.js 自定义的一种文件格式,一个. vue 文件就是一个单独的组件,在文件内封装了组件相关的代码:html、css、js 代码。

.vue文件由三部分组成:<template><style><script>:

<template>
    //html  
</template>

<script>
    //js    
</script>

<style>
    //css      
</style>

vue-loader

浏览器本身并不认识. vue 文件,此时需要 vue-loader 对. vue 文件进行加载解析,。类似的 loader 还有许多,如:html-loader、css-loader、style-loader、babel-loader 等。需要注意的是 vue-loader 是基于 webpack 的。

webpack

webpack 是一个前端资源模板化加载器和打包工具,它能够把各种资源都作为模块来使用和处理。实际上,webpack 是通过不同的 loader 将这些资源加载后打包,然后输出打包后文件。简单来说,webpack 就是一个模块加载器,所有资源都可以作为模块来加载,最后打包输出。

vue-cli

简介

vue-cli 是一个 vue 脚手架,可以帮助我们快速构造项目结构,减少开发人员开发阻力。vue-cli 集成了多种版本:

  • simple :比较简单
  • webpack :包含 ESLint 代码规范检查和 unit 单元测试等
  • webpack-simple: 没有代码规范检查和单元测试
  • browserify: 使用的也比较多
  • browserify-simple

安装、操作步骤

//安装vue-cli,配置vue命令环境 
    cnpm install vue-cli -g
    vue --version
    vue list

// 初始化项目,生成项目模板
    vue init 模板名  项目名

//进入生成的项目目录,安装模块包
    cd vue-cli-demo
    cnpm install

//运行
    npm run dev  //启动测试服务
    npm run build //将项目打包输出dist目录,项目上线的话要将dist目录拷贝到服务器上

文件介绍

.
|-- build                            // 项目构建(webpack)相关代码
|   |-- build.js                     // 生产环境构建代码
|   |-- check-version.js             // 检查node、npm等版本
|   |-- dev-client.js                // 热重载相关
|   |-- dev-server.js                // 构建本地服务器
|   |-- utils.js                     // 构建工具相关
|   |-- webpack.base.conf.js         // webpack基础配置
|   |-- webpack.dev.conf.js          // webpack开发环境配置
|   |-- webpack.prod.conf.js         // webpack生产环境配置
|-- config                           // 项目开发环境配置
|   |-- dev.env.js                   // 开发环境变量
|   |-- index.js                     // 项目一些配置变量
|   |-- prod.env.js                  // 生产环境变量
|   |-- test.env.js                  // 测试环境变量
|-- src                              // 源码目录
|   |-- components                     // vue组件
|   |-- store                          // 状态管理
|   |-- App.vue                        // 页面入口vue文件
|   |-- main.js                        // 程序入口文件,加载各种公共组件
|-- static                           // 静态文件
|   |-- data                           
|-- .babelrc                         // ES6语法编译配置
|-- .editorconfig                    // 定义代码格式
|-- .gitignore                       // git上传需要忽略的文件格式
|-- README.md                        // 项目说明
|-- favicon.ico                      //网页图标
|-- index.html                       // 入口页面
|-- package.json                     // 项目配置信息
.

此列表拷贝自: 这里

Reference


This is the end of post