vue2.0 从入门到精通 (本文特别长,但是文章右上角有目录导航,可以定位,更新中)

1vue.js安装(3种方式)

1.1下载和引入(vue官网:https://cn.vuejs.org/v2/guide/installation.html)

开发环境 https://vuejs.org/js/vue.js 
生产环境 https://vuejs.org/js/vue.min.js 

1.1.1安装步骤

1.1.1.1官网下载vue.js,右键链接另存为。

 

 

 

 1.1.1.2idea新建工程,打开idea ->Create New Projec->Empty Project。
 1.1.1.3新建module。
 1.1.1.4选中static web,静态web项目。
 1.1.1.5项目右键,新建js文件夹,NEW->Directory,把下载的vue.js文件放到该目录下。
 1.1.1.6新建src文件夹,NEW->HTML文件。

1.2直接CDN引入

或者也可以直接使用公共的CDN服务:<!-- 开发环境版本,包含了用帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
或者:<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>

1.3npm安装

详细参考:https://www.cnblogs.com/konglxblog/p/14489251.html

2vue语法

2.1vue生命周期

请参照官网的生命周期图示。

<div>{{name}}</div>

  • beforeCreated:我们在用Vue时都要进行实例化,因此,该函数就是在Vue实例化时调用,也可以将他理解为初始化函数比较方便一点,在Vue1.0时,这个函数的名字就是init。
  • created:在创建实例之后进行调用。
  • beforeMount:页面加载完成,没有渲染。如:此时页面还是{{name}}
  • mounted:我们可以将他理解为原生js中的window.onload=function({.,.}),可以理解为jquery中的$(document).ready(function(){….}),他的功能就是:在dom文档渲染完毕之后将要执行的函数,该函数在Vue1.0版本中名字为compiled。 此时页面中的{{name}}已被渲染成相对应的name的值。
  • beforeDestroy:该函数将在销毁实例前进行调用 。
  • destroyed:改函数将在销毁实例时进行调用。
  • beforeUpdate:组件更新之前。
  • updated:组件更新之后。

2.2vue实例

var vm = new Vue({ // 选项 })

2.3插值(6种插值方式以及对比)

Mustache:双大括号:{{val}}

v-once

  • 在某些情况下,我们可能不希望界面随意的跟随改变,这个时候,我们就可以使用一个Vue命令
  • 该指令后面不需要跟任何表达式(比如v-for后面是有跟表达式的)
  • 该指令表示元素和组件(组件后面会写)只渲染一次,不会随着数据的改变而改变。

v-html

  • 如果我们直接通过{{}}来输出,会将HTML代码也一起输出,但是我们可能希望的是按照HTML格式进行解析,并且显示对应的内容。
  • 如果我们希望解析出HTML展示
  • 可以使用v-html指令,在该指令后面往往会跟上一个string类型,会将stringhtml解析出来并且进行渲染

v-text

  • v-text作用和Mustache比较相似,都是用于数据显示在界面中,v-text通常情况下,接受一个string类型

v-pre

  • v-pre用于跳过这个元素和它之元素的编译过程,用于显示原本的Mustache语法,比如下面的代码:
  • 第一个h1元素中的内容会被编译解析出来
  • 第二个h1元素中会直接显示{{message}}

v-cloak

  • 在某些情况下, 我们浏览器可能会直接显示出未编译的Mustache标签(解决vue语法会有延迟加载显现{{xxx}}的问题)。

代码示例:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="hello">
<p id="mustache" >{{message}}</p>
<p id="text" v-text="message"></p>
<p id="once" v-once="message"></p>
<p id="html" v-html="message"></p>
<p id="pre" v-pre="message"></p>
<p id="cloak" v-cloak="message"></p>
<p id="p1" >====================================</p>
<p id="text1" v-text="message">text</p>
<p id="once1" v-once="message">once</p>
<p id="html1" v-html="message">html</p>
<p id="pre1" v-pre="message">pre</p>
<p id="cloak1" v-cloak="message">cloak</p>
<p id="p2" >p2</p>
<p id="mustache-v">{{message}}</p>
<p id="v-pre" v-pre>{{message}}</p>

</div>
</body>
<script src="../js/vue.js"></script>
<script>
var vm = new Vue({
el:"#hello",
data:{
message:"<div id='msg'>hello my name is vue</div>"
}
});
</script>
</html>

运行结果:

 修改message的值

2.4指令

2.4.1插值表达式,花括号

格式:{{表达式}}。

说明:

  • 该表达式支持JS语法,可以调用js内置函数(必须有返回值)。

  • 表达式必须有返回结果。例如 1 + 1,没有结果的表达式不允许使用,如:var a = 1 + 1。

  • 可以直接获取Vue实例中定义的数据或函数。

插值闪烁

使用{{}}方式在网速较慢时会出现问题。在数据未加载完成时,页面会显示出原始的{{}},加载完毕后才显示正确数据,我们称为插值闪烁。

我们将网速调慢一些,测试插值闪烁方法:

说明:

  • 该表达式支持JS语法,可以调用js内置函数(必须有返回值)。

  • 表达式必须有返回结果。例如 1 + 1,没有结果的表达式不允许使用,如:var a = 1 + 1。

  • 可以直接获取Vue实例中定义的数据或函数。

插值闪烁

使用{{}}方式在网速较慢时会出现问题。在数据未加载完成时,页面会显示出原始的{{}},加载完毕后才显示正确数据,我们称为插值闪烁。

我们将网速调慢一些,测试插值闪烁方法:

  

然后刷新页面。

2.4.2v-text和v-html

使用v-text和v-html指令来替代{{}}

说明:

  • v-text:将数据输出到元素内部,如果输出的数据有HTML代码,会作为普通文本输出。

  • v-html:将数据输出到元素内部,如果输出的数据有HTML代码,会被渲染。

2.4.3v-model

  v-text和v-html都是单向绑定,数据影响了视图渲染,但是反过来就不行。v-model是双向绑定,视图(View)和模型(Model)之间会互相影响。

双向绑定,一定是在视图中可以修改数据,这样就限定了视图的元素类型。目前v-model的可使用元素有:

  • input

  • select

  • textarea

  • checkbox

  • radio

  • components(Vue中的自定义组件)

      基本上除了最后一项,其它都是表单的输入项。

  • 多个CheckBox对应一个model时,model的类型是一个数组,单个checkbox值默认是boolean类型

  • radio对应的值是input的value值

  • texttextarea 默认对应的model是字符串

  • select单选对应字符串,多选对应也是数组

2.4.4v-on

v-on指令用于给页面元素绑定事件。

语法:

v-on:事件名="js语句或函数名"。

另外,事件绑定可以简写,例如v-on:click='add'可以简写为@click='add'。 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <div >计数器,当前基数:{{count}}</div>
<!--    <button v-on:click="count++">加加</button>
    <button v-on:click="count++">减减</button>-->
<!--    <button v-on:click="add">加加</button>
    <button v-on:click="minus">减减</button>-->
    <button @click="add">加加</button>
    <button @click="minus">减减</button>
</div>
</body>
<script src="../../js/vue.js"></script>
<script>
    var vm = new Vue({
        el:"#app",
        data:{
            count:1
        },methods:{
            add(){
               this.count++
            },
            minus(){
               this.count--
            }

        }
    });
</script>
</html>

2.4.5事件修饰符和按键修饰符

在事件处理程序中调用 event.preventDefault()event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。

为了解决这个问题,Vue.js 为 v-on 提供了事件修饰符。修饰符是由点开头的指令后缀来表示的。

  • stop :阻止事件冒泡到父元素

  • prevent:阻止默认事件发生

  • capture:使用事件捕获模式

  • self:只有元素自身触发事件才执行。(冒泡或捕获的都不执行)

  • once:只执行一次

代码示例:效果:(右键“增加一个”,不会触发默认的浏览器右击事件;右键“减少一个”,会触发默认的浏览器右击事件)

<div id="app">
    <!--右击事件,并阻止默认事件发生-->
    <button v-on:contextmenu.prevent="num++">增加一个</button>
    <br/>
    <!--右击事件,不阻止默认事件发生-->
    <button v-on:contextmenu="decrement($event)">减少一个</button>
    <br/>
    <h1>{{num}}</h1>
</div>
<script src="../js/vue.js"></script>
<script type="text/javascript">
    var app = new Vue({
        el: "#app",
        data: {
            num: 100
        },
        methods: {
            decrement(ev) {
                // ev.preventDefault();
                this.num--;
            }
        }
    })
</script> 

按键修饰符

  • enter*
  • tab
  • delete (捕获“删除”和“退格”键)
  • esc
  • space
  • up
  • down
  • left
  • right

用法例子:

<!-- 同上 -->
<input v-on:keyup.enter="submit">

<!-- 缩写语法 -->
<input @keyup.enter="submit">

组合按钮

  • .ctrl
  • .alt
  • .shift

例如:

<!-- Alt + C -->
<input @keyup.alt.67="clear">

<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">Do something</div>

2.4.6v-for

遍历数组

语法:v-for="item in items"

  • items:要遍历的数组,需要在vue的data中定义好。

  • item:迭代得到的数组元素的别名

示例

<div id="app">
    <ul>
        <li v-for="user in users">
            {{user.name}} - {{user.gender}} - {{user.age}}
        </li>
    </ul>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
    var app = new Vue({
        el: "#app",
        data: {
            users:[
                {name:'娜美', gender:'', age: 21},
                {name:'路飞', gender:'', age: 18},
                {name:'陆琪', gender:'', age: 24},
                {name:'名人', gender:'', age: 18},
                {name:'鸣人', gender:'', age: 25}
            ]
        },
    })
</script>

数组角标

在遍历的过程中,如果我们需要知道数组角标,可以指定第二个参数:

语法

v-for="(item,index) in items"

  • items:要迭代的数组

  • item:迭代得到的数组元素别名

  • index:迭代到的当前元素索引,从0开始。

示例

    <ul>
        <li v-for="(user, index) in users">
            {{index + 1}}. {{user.name}} - {{user.gender}} - {{user.age}}
        </li>
    </ul>

遍历对象

v-for除了可以迭代数组,也可以迭代对象。语法基本类似

语法

  • v-for="value in object"
  • v-for="(value,key) in object"
  • v-for="(value,key,index) in object"

示例

<div id="app">
    <ul>
        <li v-for="(value, key, index) in user">
            {{index + 1}}. {{key}} - {{value}}
        </li>
    </ul>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
    var vm = new Vue({
        el:"#app",
        data:{
            user:{name:'佐助', gender:'', age: 18}
        }
    })
</script>

2.4.7key

当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。

这个功能可以有效的提高渲染的效率。

但是要实现这个功能,你需要给Vue一些提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key 属性。理想的 key 值是每项都有的且唯一的 id。

示例:

<ul>
    <li v-for="(item,index) in items" :key=index></li>
</ul>
  • 这里使用了一个特殊语法::key="",它可以让你读取vue中的属性,并赋值给key属性

  • 这里我们绑定的key是数组的索引,应该是唯一的

2.4.8v-if和v-show

v-if,顾名思义,条件判断。当得到结果为true时,所在的元素才会被渲染。

语法:

v-if="布尔表达式"

示例

<div id="app">
    <button v-on:click="show = !show">show me</button>
    <br>
    <h1 v-if="show">
        show me
    </h1>
    <h1 v-show="show">
        show me
    </h1>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
    var app = new Vue({
        el: "#app",
        data: {
            show: true
        }
    })
</script>

当v-if和v-for出现在一起时,v-for优先级更高。也就是说,会先遍历,再判断条件。

修改v-for中的案例,添加v-if:

    <ul>
        <li v-for="(user, index) in users" v-if="user.gender == '女'">
            {{index + 1}}. {{user.name}} - {{user.gender}} - {{user.age}}
        </li>
    </ul>

v-else

你可以使用 v-else 指令来表示 v-if 的“else 块”:

<div id="app">
    <h1 v-if="Math.random() > 0.5">
        看到我啦?!if
    </h1>
    <h1 v-else>
        看到我啦?!else
    </h1>
</div>

v-else 元素必须紧跟在带 v-if 或者 v-else-if 的元素的后面,否则它将不会被识别。

v-else-if,顾名思义,充当 v-if 的“else-if 块”,可以连续使用:

<div id="app">
    <button v-on:click="random=Math.random()">点我呀</button><span>{{random}}</span>
    <h1 v-if="random >= 0.75">
        看到我啦?!if
    </h1>
    <h1 v-else-if="random > 0.5">
        看到我啦?!if 0.5
    </h1>
    <h1 v-else-if="random > 0.25">
        看到我啦?!if 0.25
    </h1>
    <h1 v-else>
        看到我啦?!else
    </h1>
</div>
<script src="../js/vue.js"></script>
<script type="text/javascript">
    var app = new Vue({
        el: "#app",
        data: {
            random: 1
        }
    })
</script>

类似于 v-elsev-else-if 也必须紧跟在带 v-if 或者 v-else-if 的元素之后。

v-show

另一个用于根据条件展示元素的选项是 v-show 指令。用法大致一样:

<h1 v-show="ok">Hello!</h1>

不同的是带有 v-show 的元素始终会被渲染并保留在 DOM 中。v-show 只是简单地切换元素的 CSS 属性 display

    <div id="app">
        <!--事件中直接写js片段-->
        <button v-on:click="show = !show">点击切换</button><br/>
        <h1 v-if="show">
            你好
        </h1>
    </div>
    <script src="./node_modules/vue/dist/vue.js"></script>
    <script type="text/javascript">
        var app = new Vue({
            el:"#app",
            data:{
                show:true
            }
        })
    </script>

 

2.4.9v-bind

html属性不能使用双大括号形式绑定,只能使用v-bind指令。

在将 v-bind 用于 class 和 style 时,Vue.js 做了专门的增强。表达式结果的类型除了字符串之外,还可以是对象或数组。

<div id="app">
    <!--可以是数据模型,可以是具有返回值的js代码块或者函数-->
    <div v-bind:title="title" style="border: 1px solid red; width: 50px; height: 50px;"></div>
</div>
<script src="../js/vue.js"></script>
<script type="text/javascript">
    var app = new Vue({
        el: "#app",
        data: {
            title: "title",
        }
    })
</script>

在将 v-bind 用于 class 和 style 时,Vue.js 做了专门的增强。表达式结果的类型除了字符串之外,还可以是对象或数组。

数组语法

绑定class样式

<div id="app">
    <div v-bind:class="activeClass"></div>
    <div v-bind:class="errorClass"></div>
    <div v-bind:class="[activeClass, errorClass]"></div>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
    var app = new Vue({
        el: "#app",
        data: {
            activeClass: 'active',
            errorClass: ['text-danger', 'text-error']
        }
    })
</script>

对象语法

我们可以传给 v-bind:class 一个对象,以动态地切换 class:

<div v-bind:class="{ active: isActive }"></div>

上面的语法表示 active 这个 class 存在与否将取决于数据属性 isActive 的truthiness(所有的值都是真实的,除了false,0,“”,null,undefined和NaN)。

你可以在对象中传入更多属性来动态切换多个 class。此外,v-bind:class 指令也可以与普通的 class 属性共存。如下模板:

<div class="static"
     v-bind:class="{ active: isActive, 'text-danger': hasError }">
</div>

和如下 data:

data: {
  isActive: true,
  hasError: false
}

渲染结果为

<div class="static active"></div>

active样式和text-danger样式的存在与否,取决于isActive和hasError的值。本例中isActive为true,hasError为false,所以active样式存在,text-danger不存在。

绑定style样式

数组语法

数组语法可以将多个样式对象应用到同一个元素上:

<div v-bind:style="[baseStyles, overridingStyles]"></div>

数据

data: {
    baseStyles: {'background-color': 'red'},
    overridingStyles: {border: '1px solid black'}
}

渲染后结果

<div style=" border: 1px solid black;"></div>

对象语法

v-bind:style 的对象语法十分直观——看着非常像 CSS,但其实是一个 JavaScript 对象。CSS 属性名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用单引号括起来) 来命名:

<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>

数据

data: {
  activeColor: 'red',
  fontSize: 30
}

效果

<div style="color: red; font-size: 30px;"></div>

 简写

v-bind:class可以简写为:class

2.5计算属性

在插值表达式中使用js表达式是非常方便的,而且也经常被用到。

但是如果表达式的内容很长,就会显得不够优雅,而且后期维护起来也不方便,例如下面的场景,我们有一个日期的数据,但是是毫秒值:

data:{
    birthday:1529032123201 // 毫秒值
}

我们在页面渲染,希望得到yyyy-MM-dd的样式:

<h1>您的生日是:{{
    new Date(birthday).getFullYear() + '-'+ new Date(birthday).getMonth()+ '-' + new Date(birthday).getDay()
    }}
</h1>

虽然能得到结果,但是非常麻烦。

Vue中提供了计算属性,来替代复杂的表达式:

var vm = new Vue({
    el:"#app",
    data:{
        birthday:1429032123201 // 毫秒值
    },
    computed:{
        birth(){// 计算属性本质是一个方法,但是必须返回结果
            const d = new Date(this.birthday);
            return d.getFullYear() + "-" + d.getMonth() + "-" + d.getDay();
        }
    }
})

计算属性本质就是方法,但是一定要返回数据。然后页面渲染时,可以把这个方法当成一个变量来使用。

页面使用:

 <div id="app">
       <h1>您的生日是:{{birth}} </h1>
    </div>

我们可以将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的依赖进行缓存的。计算属性只有在它的相关依赖发生改变时才会重新求值。这就意味着只要birthday还没有发生改变,多次访问 birthday 计算属性会立即返回之前的计算结果,而不必再次执行函数。

2.6watch

watch可以让我们监控一个值的变化。从而做出相应的反应。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<div id="watch">
    <input type="text" v-model="message">
</div>
</body>
<script src="../../js/vue.js"></script>
<script>
    var vm = new Vue({
        el:"#watch",
        data:{
            message:"wacth"
        },
        watch:{
            message(newVal, oldVal){
                console.log(newVal, oldVal);
            }
        }
    });
</script>

</html> 

例子:在页面上的text框里分别输入1,2,3,4,5,6。可以看到控制台的变化,监控输入框的新值和旧值。

3组件

组件的使用分成三个步骤:

  • 创建组件构造器
  • 注册组件
  • 使用组件。

3.1定义全局组件的方式。

3.1.1方法1,使用extend

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

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

<my-tem></my-tem>

<script src="../js/vue.js"></script>
<script>
    // 1.创建组件构造器对象
    const temC = Vue.extend({
        template: `
      <div>
        <h2>组件</h2>
        <p>组件内容</p>

      </div>`
    })

    // 2.注册组件
    Vue.component('my-tem', temC)

    const app = new Vue({
        el: '#app',
        data: {
            message: '组件内容'
        }
    })
</script>

</body>
</html>

3.1.2方法2,使用字符串形式

<div id="app">
    <!--使用定义好的全局组件-->
    <counter></counter>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
    // 定义全局组件,两个参数:1,组件名称。2,组件参数
    Vue.component("counter",{
        template:'<button v-on:click="count++">你点了{{ count }} 次.</button>',
        data(){
            return {
                count:0
            }
        }
    })
    var app = new Vue({
        el:"#app"
    })
</script>

3.1.3方法3,模版字面量

Vue.component("my-content", {
 data: function () {
 return {
  label: "组件",
  content: "组件内容"
 }
 },
 template: `
 <div>
  <button>{{ label }}</button>
  <span>{{ content }}</span>
 </div>
 `
});

3.1.4方法4,内联模版(inline-template)

<my-label inline-template>
 <span>{{label}}</span>
</my-label>
Vue.component('my-label', {
 data: function () {
 return {
  label: "hello"
 }
 }
})

3.1.5方法5,X-template

定义一个 <script> 标签,标记 text/x-template 类型,通过 id 链接。

<script type="text/x-template" id="label-template">
 <span>{{label}}</span>
</script>
Vue.component('my-label', {
 template: "#label-template",
 data: function () {
 return {
  label: "test"
 }
 }
})

3.1.6方法6,template

//tem.vue
<template>
  <div>
    <h1>我是标题一</h1>
  </div>
</template>

<script>
  export default {
    data() {
      return {}
    }
  }
</script>

3.1.7方法7,渲染函数创建节点方式(实现效果和方法6一模一样)

//ren.vue
<script>
  export default {
    render: function(createElement) {
      return createElement('h1', '我是标题一')
    }
  }
</script>

render总共接收三个参数,第一个参数为标签名('ul'),第二个参数为数据对象,第三个参数为子节点(我是标题一),要么文本要么是存储着一个或一个以上的子节点数组.

render 函数创建多个子节点

实现下面的效果:

  • li-1
  • li-2
  • li-3

代码如下:

<script>
  export default {
    render: function(createElement) {
      return createElement('ul', [
        createElement('li', 'li-1'),
        createElement('li', 'li-2'),
        createElement('li', 'li-3')
      ])
    }
  }
</script>

简化后:

<script>
  export default {
    data() {
      return {
        list: ['li-1', 'li-2', 'li-3']
      }
    },
    render: function(createElement) {
      return createElement(
        'ul',
        this.list.map(_ => {
          return createElement('li', _)
        })
      )
    }
  }
</script>

3.1.8方法8,函数渲染返回xml结构方式。

Vue.component('my-label', {
 data: function () {
 return {
  label: ["活动结束"]
 }
 },
 render(){
 return <div>{this.label}</div>
 }
})

3.2全局组件

我们通过Vue的component方法来定义一个全局组件。

<div id="app">
    <!--使用定义好的全局组件-->
    <counter></counter>
</div>
<script src="./vue.js"></script>
<script type="text/javascript">
    // 定义全局组件,两个参数:1,组件名称。2,组件参数
    Vue.component("counter",{
        template:'<button v-on:click="count++">你点了{{ count }} 次.</button>',
        data(){
            return {
                count:0
            }
        }
    })
    var app = new Vue({
        el:"#app"
    })
</script>
  • 组件其实也是一个Vue实例,因此它在定义时也会接收:data、methods、生命周期函数等

  • 不同的是组件不会与页面的元素绑定,否则就无法复用了,因此没有el属性。

  • 但是组件渲染需要html模板,所以增加了template属性,值就是HTML模板

  • 全局组件定义完毕,任何vue实例都可以直接在HTML中通过组件名称来使用组件了。

  • data必须是一个函数,不再是一个对象。

3.3局部组件

一旦全局注册,就意味着即便以后你不再使用这个组件,它依然会随着Vue的加载而加载。

因此,对于一些并不频繁使用的组件,我们会采用局部注册。

我们先在外部定义一个对象,结构与创建组件时传递的第二个参数一致:

const counter = {
    template:'<button v-on:click="count++">你点了我 {{ count }} 次,我记住了.</button>',
    data(){
        return {
            count:0
        }
    }
};

然后在Vue中使用它:

var app = new Vue({
    el:"#app",
    components:{
        counter:counter // 将定义的对象注册为组件
    }
})
  • components就是当前vue对象子组件集合。

    • 其key就是子组件名称

    • 其值就是组件对象名

  • 效果与刚才的全局注册是类似的,不同的是,这个counter组件只能在当前的Vue实例中使用

3.4组件通信

3.4.1props(父向子传递)

  1. 父组件使用子组件时,自定义属性(属性名任意,属性值为要传递的数据)

  2. 子组件通过props接收父组件数据,通过自定义属性的属性名

示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <child_temp v-bind:child_msg="parent_msg" :chlid_movies="parent_movies"></child_temp>
</div>

<template id="child_temp">
    <div>
        <ul>
            <li v-for="item in chlid_movies">{{item}}</li>
        </ul>
        <p>{{child_msg}}</p>
        <p>{{chlid_movies}}</p>
        <p>{{myname}}</p>
        <!--<button @click="child_btn">子按钮</button>-->
    </div>
</template>
</body>
<script src="../../js/vue.js"></script>
<script>

    const child_temp = {
        template:'#child_temp',
        /*props:['chlid_movies','child_msg'],*/
        props:{
            //props的扩展,包括类型,默认值,是否必须等
            //1类型限制
            /*chlid_movies:Array,
            child_msg:String*/
            //2.提供默认值,扩展
            chlid_movies:{
              type:Array,
              default() {
                  return [];
              }
            },
            child_msg: {
                type: String,
                required: true,
                default() {
                    //如果把child_temp模板里的v-bind:child_msg="parent_msg"去掉,页面就会显示这里的值
                    return ["子_我是子组件默认值,当使用父组件data里的属性值得时候,如果没有用v-bind绑定,会取到我这一串值"];
                }
            }/*,
            methods:{
                child_btn(){
                    alert("我是子组件的方法")
                }
            }*/
        },
        data(){
            return {
                myname:"子_我是子属性自己的值,我使用的是自己组件里的data的属性值"
            }
        }
    }
    var vm = new Vue({
            el:"#app",
        data:{
            parent_msg:"父_我是父组件里的信息,传到了子组件",
            parent_movies:['父_火影','父_海贼王','父_柯南']
        },
        components:{
            child_temp
            }
        })
</script>
</html>

 

效果:

3.4.2props验证

props:定义需要从父组件中接收的属性

  • items:是要接收的属性名称

  • type:限定父组件传递来的必须是数组
  • default:默认值
  • required:是否必须

验证支持的数据类型

  • String
  • Number
  • Boolean
  • Array
  • Object
  • Date
  • Function
  • Symbol

动态静态传递

给 prop 传入一个静态的值:

<temp child_msg="大家好,我是组件"/>

给 prop 传入一个动态的值: (通过v-bind从数据模型中,获取title的值)

<temp :child_msg="parent_msg"/>

3.4.3子向父的通信:$emit

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <!--父组件模板-->
    <div id="app">
        <!--监听子组件发射出的btn_child_click事件,find_parent_click要在父组件里定义methods-->
        <chlid_temp v-on:btn_child_click="find_parent_click"></chlid_temp>
    </div>
    <!--子组件模板-->
    <template id="chlid_temp">
        <div>
            <button v-for="item in movies"
                    @click="btn_ckik(item)">
                    {{item.id}}-{{item.name}}
            </button>
        </div>
    </template>
</body>
<script src="../../js/vue.js"></script>
<script>
    //子组件
    const chlid_temp = {
        template:"#chlid_temp",
        data(){
            return{
                movies:[
                    {id:"1",name:"火影"},
                    {id:"2",name:"海贼"},
                    {id:"3",name:"七大罪"},
                    {id:"4",name:"菜鸟java是怎么炼成的"},
                    {id:"5",name:"菜鸟是怎么变菜的"},
                ]
            }
        },
        methods:{
            btn_ckik(ev){
                //自定义事件
                this.$emit("btn_child_click",ev)
            }
        }
    }
    //父组件
    var vm =  new Vue({
        el:"#app",
        data:{
            msg:"我是父组件的信息-msg"
        },
        components:{
            chlid_temp
        },
        methods:{
            find_parent_click(ev){

                 console.log(ev)
                 console.log(ev.id +"  "+ev.name)

            }
        }
    });
</script>
</html>

效果:

 3.5父子通信示例:

需求:父组件里的num1和num2,和子组件里的num1和num2实现双向绑定,并且input1里的num1输入后input2里num2的值会相应的变为num1值得100倍,反之num2是num1的100分之1.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div id="app">
        <temp :c_num1="p_num1"
              :c_num2="p_num2"
              @data_cnum1_change="parent_cnum1_change"
              @data_cnum2_change="parent_cnum2_change"
        ></temp>
    </div>
    <template id="temp">
        <div>

            <h3>props:{{c_num1}}</h3>
            <h3>data:{{data_cnum1}}</h3>
            <!--<input type="text" v-model="data_cnum1">-->
            input1:<input type="text" :value="data_cnum1" @input="num1_input">
            <h3>props:{{c_num2}}</h3>
            <h3>data:{{data_cnum2}}</h3>
            <!--<input type="text" v-model="data_cnum2">-->
            <!--<input type="text" :value="data_cnum2" @input="data_cnum2=$event.target.value">-->
            input2:<input type="text" :value="data_cnum2" @input="num2_input">
        </div>
    </template>
</body>
<script src="../../js/vue.js"></script>
<script>
    const temp={
        template:"#temp",
        props:{
            c_num1:Number,
            c_num2:Number

        },
        data(){
           return{
               data_cnum1:this.c_num1,
               data_cnum2:this.c_num2
           }
        },
        methods:{
            num1_input(e){
                //1 将input的value赋值到data_cnum1上
                this.data_cnum1 = e.target.value;
                //2 为了让父组件可以改值,发出一个事件
                this.$emit("data_cnum1_change",this.data_cnum1);
                //3 同事修改data_cnum2的值(data_cnum2的值是data_cnum1的100倍)
                this.data_cnum2 = this.data_cnum1 * 100;
                this.$emit("data_cnum2_change",this.data_cnum2)
            },
            num2_input(e){
                this.data_cnum2 = e.target.value;
                this.$emit("data_cnum2_change",this.data_cnum2);
                //(data_cnum2的值是data_cnum1的100分之一倍)
                this.data_cnum1 = this.data_cnum2 / 100;
                this.$emit("data_cnum1_change",this.data_cnum1)
            }
        }
    }
    var vm = new Vue({
        el:"#app",
        data:{
            p_num1:1,
            p_num2:0
        },
        components:{
            temp
        },
        methods:{
            parent_cnum1_change(data_cnum1){
                //默认传过来的是Strnig类型,需要转换成number
                console.log(typeof data_cnum1)

                this.p_num1 = parseInt(data_cnum1);
            },
            parent_cnum2_change(data_cnum2){
                this.p_num2 = parseInt(data_cnum2);

            }
        }
    })
</script>
</html>

 

 效果图:

 

 

 

 

 

 

 

 

 

posted @ 2021-03-10 16:22  程序员小明1024  阅读(147)  评论(0编辑  收藏  举报