Vue基础1

Vue基础1

 

 

API:https://vue.docschina.org/v2/guide/installation.html

动画曲线函数:https://cubic-bezier.com/#.63,.11,.51,.69

 

  

 

 

基本语法

基本代码结构

插值表达式

闪烁问题

指令

v-cloak

v-text

v-html

v-html动态添加的元素怎么绑定事件?

v-bind:

v-on

v-model

v-for

v-show 和 v-if

自定义指令

过滤器

事件修饰符

按键修饰符

常用的按键修饰符别名

基本使用

系统辅助按键

鼠标按键修饰符

class与style绑定

组件

概念

什么是组件

组件化和模块化的不同

创建组件的方式

方式1

方式2

方式3

私有组件

组件中的data和method

组件动画

父组件给子组件传值

父子组件的概念图

父组件给子组件传递值

父组件给子组件传递方法

子组件给父组件传递值【事件调用机制】

使用ref引用DOM或组件

使用render渲染组件

 

 

 

基本语法

 

基本代码结构

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <!-- 1. 导入Vue的包 -->
  <script src="./lib/vue-2.4.0.js"></script>
</head>

<body>
  <!-- 将来 new 的Vue实例,会控制这个 元素中的所有内容 -->
  <!-- Vue 实例所控制的这个元素区域,就是我们的 V  -->
  <div id="app">
    <p>{{ msg }}</p>
  </div>

  <script>
    // 2. 创建一个Vue的实例
    // 当我们导入包之后,在浏览器的内存中,就多了一个 Vue 构造函数
    //  注意:我们 new 出来的这个 vm 对象,就是我们 MVVM中的 VM调度者
    var vm = new Vue({
      el: '#app',  // 表示,当前我们 new 的这个 Vue 实例,要控制页面上的哪个区域
      // 这里的 data 就是 MVVM中的 M,专门用来保存 每个页面的数据的
      data: { // data 属性中,存放的是 el 中要用到的数据
        msg: '欢迎学习Vue' // 通过 Vue 提供的指令,很方便的就能把数据渲染到页面上,程序员不再手动操作DOM元素了【前端的Vue之类的框架,不提倡我们去手动操作DOM元素了】
      }
    })
  </script>
</body>

注意:不建议直接在根元素body上定义vue

 

 

插值表达式

什么叫插值表达式?类似在元素中使用

{{msg}}

的方式叫插值表达式,使用插值表达式存在闪烁问题。

 

 

闪烁问题

使用插值表达式时,如果vue没有及时被加载出来(网速较慢情况),就会在页面上展现

{{msg}}

而不是具体数据信息,vue的解决方案类似Angular一样,使用属性控制器

<style>
        [v-cloak] {
            display: none;
        }
    </style>
    <script src="./lib/vue-2.4.0.js"></script>
</head>

<body>
<div id="app">
    <p v-cloak>+++++++{{ msg }}------</p>
    <p v-text="msg">+++++++--------</p>
    <!-- 默认v-text 是没有闪烁问题的 -->
    <!-- v-text 会覆盖元素中原本的内容,但是 插值表达式 只会
     替换自己的这个占位符,不会把整个元素的内容清空-->
</div>

指令

 

v-cloak

解决 插值表达式 闪烁问题的指令,使用的同时别忘记添加样式:

<style>
        [v-cloak] {
            display: none;
        }
    </style>

v-text

类似于插值表达式,但是不同于插值表达式的是,使用该指令不会出现闪烁问题,而且其内指定的内容采用覆盖的方式覆盖元素内容,插值表达式不会覆盖只会替换自己占位符的内容。

 

 

v-html

插值表达式和v-text都只能在元素内插入文本,如果使用这两种方式向元素内插入子元素,需要使用v-html。

 

 

v-html动态添加的元素怎么绑定事件?

可以在其父元素上绑定事件,然后:

goWd(e) {
    // 判断触发事件的是不是动态绑定的元素
      if (e.target.nodeName == "A") {
        this.$router.push("/wd");
      }
    }

v-bind:

v-bind:  是vue中,提供的用于绑定属性的指令【属性绑定机制】,该指令会告诉vue,冒号后面的属性值里的内容是一个变量。

<div id="app">
    <button title="123">点我</button>
    <!-- v-bind:  是vue中,提供的用于绑定属性的指令,该指令会告诉vue,冒号后面的属性值里的内容是一个变量。 -->
    <button v-bind:title="titl">点vue</button>
    <!-- 既然是变量,当然可以使用字符串拼接等操作 -->
    <button v-bind:title="titl.replace('Vue','vUE') + '123'">点vue</button>
    <!-- v-bind:提供了一种简写的方式就是直接在要绑定的元素上写: -->
    <button :title="titl">点vue了吗</button>
</div>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            titl: '欢迎学习Vue'
        }
    })
</script>

v-on

vue像Angular一样,都不提倡使用dom操作,v-on是vue提供的事件绑定机制。在vue中,指令指定的内容为变量(属性)或者method,类似下面的直接调用alert方法,vue会去methods去寻找这个alert方法或属性,找不到就会报错

<div id="app">
    <!-- 在vue的指令中会把其内内容当作属性(变量)或方法来处理,alert作为一个method并没有在vue中定义,所以点击1会报错 -->
    <!-- <input type="button" value="点击1" v-on:click="alert('1bc')"> -->
    <input type="button" value="点击2" v-on:click="click_abc">
    <!-- v-on:的缩写是@ -->
    <input type="button" value="点击3" @click="click_abc">
</div>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            titl: '欢迎学习Vue'
        },
        methods: {
            click_abc: function () {
                alert('abc')
            }
        }
    })
</script>

在这里有个问题,vue并没有那么严格的说方法一定要在methods中定义,它也可以在变量(data内属性)中定义:

<div id="app">
    <!-- 在vue的指令中会把其内内容当作属性(变量)或方法来处理,
    alert作为一个method并没有在vue中定义,所以点击1会报错 -->
    <input type="button" value="点击1" v-on:click="alert('1bc')">
    <input type="button" value="点击2" v-on:click="click_abc">
</div>

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            titl: '欢迎学习Vue',
            alert:function (x) {
                alert(x)
            }
        },
        methods: {
            click_abc: function () {
                alert('abc')
            }
        }
    })
</script>

不过还是不推荐这种写法,毕竟一个好的约定习惯是data内只封装数据。

 

案例

注意:

1、在vm实例中,如果想要获取 data 上的数据,或者 想要调用methods 中的方法,必须通过this.数据属性名 或 this.方法名 来进行访问,这里的this就表示我们 new 出来的 vm实例对象。

2、vm实例,会监听自己身上 data 中所有数据的改变,只要数据一旦发生变化,就会自动把最新的数据从data上同步到页面中去。 [好处:程序员只需要关心数据,不需要考虑怎么渲染数据了

<div id="app">
    <input type="button" value="浪起来" @click="bll">
    <input type="button" value="稳住" @click="wz">
    <h3>{{msg}}</h3>
</div>

<script>
    // 注意:在vm实例中,如果想要获取 data 上的数据,或者 想要调用
    // methods 中的方法,必须通过this.数据属性名 或 this.方法名 来
    // 进行访问,这里的this就表示我们 new 出来的 vm实例对象
    var vm = new Vue({
        el: '#app',
        data: {
            msg: '猥琐发育,别浪!!',
            inter: null
        },
        methods: {
            bl() {
                if (this.inter != null) return;
                let that = this;
                that.inter = setInterval(function () {
                    let start = that.msg.substring(0, 1);
                    let end = that.msg.substring(1);
                    that.msg = end + start;

                    // 注意:vm实例,会监听自己身上 data 中所有数据的改变,只要数据
                    // 一旦发生变化,就会自动把最新的数据从data上同步到页面中去。
                    // [好处:程序员只需要关心数据,不需要考虑怎么渲染数据了。]
                }, 500);
            },
            bll() {
                // 使用箭头函数解决this指向问题。箭头函数内部的this永远和箭头
                // 函数外部的this保持一致。
                if (this.inter != null) return;
                this.inter = setInterval(() => {
                    let start = this.msg.substring(0, 1);
                    let end = this.msg.substring(1);
                    this.msg = end + start;

                    // 注意:vm实例,会监听自己身上 data 中所有数据的改变,只要数据
                    // 一旦发生变化,就会自动把最新的数据从data上同步到页面中去。
                    // [好处:程序员只需要关心数据,不需要考虑怎么渲染数据了。]
                }, 500);
            },
            wz() {
                clearInterval(this.inter);
                this.inter = null;
            }
        }
    })
</script>

v-model

v-model只能运用在表单元素中,用于双向数据绑定。注意v-bind只能用于单向数据绑定。

<div id="app">
    <!-- v-bind只能用于实现数据的单向绑定,从M 自动绑定到 V,无法实现数据的双向绑定 -->
    <input type="text" v-bind:value="msg">

    <!-- 使用 v-model 指令,可以实现 表单元素和Model中数据的双向绑定 -->
    <!-- 注意:v-model 只能运用在 表单元素中 -->
    <input type="text" v-model:value="msg">
</div>

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            msg: 'Hello Vue'
        },
        methods: {}
    })
</script>

v-for

迭代

<div id="app">
    <ul>
        <!--<li v-for="value in common">{{value}}</li>-->
        <li v-for="(value,index) in common">索引:{{index}},值:{{value}}</li>
    </ul>
    <ul>
        <!--<li v-for="(k,v) in obj">键:{{v}},值:{{k}}</li>-->
        <!-- 在遍历对象的时候,还有可以获取索引 -->
        <li v-for="(k,v,i) in obj">键:{{v}},值:{{k}},索引:{{i}}</li>
    </ul>
    <ul>
        <!-- 如果迭代数字的话是从1开始的 -->
        <li v-for="num in 10">{{num}}</li>
    </ul>
    <ul>
        <li v-for="str in 'Hello_World'">{{str}}</li>
    </ul>
</div>

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            // 循环普通数组
            common: [1, 2, 3, 4, 5],
            // 循环对象
            obj: {maomao: '24', keke: 24, jiji: 22, mimi: 22}
        },
        methods: {}
    })
</script>

 

v-for存在的问题

使用v-for可能存在一定的问题,建议在使用v-for时指定:key

<div id="app">
    <div>
        <label>id:
            <input type="text" v-model="id">
        </label>
        <label>name:
            <input type="text" v-model="name">
        </label>
        <input type="button" value="添加" @click="add">
    </div>
    <!-- 如果不使用用:key强制绑定对象与元素唯一关联,可能会导致意想不到的问题:
            例如:如果你勾选了最后一项,然后添加一组数据,会发现原来勾选的
            变为了倒数第二个了!
     -->
    <!--<p v-for="mate in roommates">-->
        <!--<input type="checkbox">{{mate.id}}-&#45;&#45;{{mate.name}}-->
    <!--</p>-->


    <!--
        注意:在v-for遍历的时候,key 属性只能使用number或者string。
        注意:key在使用的时候,必须使用 v-bind 属性绑定的形式,指定key的值。
        在组件中,使用v-for循环的时候,或者在一些特殊情况中,如果 v-for有问题,必须
        在使用v-for的同时,指定唯一的 字符串/数字 类型 :key 值
     -->
    <p v-for="mate in roommates" :key="mate.id">
        <input type="checkbox">{{mate.id}}---{{mate.name}}
    </p>
</div>

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            id: '',
            name: '',
            roommates: [
                {id: 1, name: '毛毛'},
                {id: 2, name: '吉吉'},
                {id: 3, name: '可可'},
                {id: 4, name: '咪咪'},
                {id: 5, name: '德玛'}
            ]
        },
        methods: {
            add() {
                this.roommates.unshift({
                    id: this.id,
                    name: this.name
                });
            }
        }
    })
</script>

v-show 和 v-if

<div id="app">
    <!--<button @click="toggle">toggle</button>-->
    <!-- 如果事件内逻辑就一行代码,可以直接写 -->
    <button @click="flag=!flag">toggle</button>

    <!--
        v-if 的特点:每次都会重新删除或创建元素
        v-show 的特点:每次不会重新进行DOM的删除和创建操作,只是切换了
        元素的 display:none 样式。

        v-if 有较高的切换性能消耗
        v-show 有较高的初始渲染消耗

        如果元素涉及到频繁的切换,最好不要使用v-if,而是推荐使用v-show
        如果元素可能永远也不会被显示出来被用户看到,则推荐使用v-if
     -->
    <p v-if="flag">我是v-if</p>
    <p v-show="flag">我是v-show</p>
</div>

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            flag: true
        },
        methods: {
            toggle() {
                this.flag = !this.flag;
            }
        }
    })
</script>

 

自定义指令

构建自定义指令:

// 注册一个名为 `v-focus` 的全局自定义指令
Vue.directive('focus', {
  // 当绑定的元素插入到 DOM 时调用此函数……
  inserted: function (el) {
    // 元素调用 focus 获取焦点
    el.focus()
  }
})


//如果你想要注册一个局部指令,也可以通过设置组件的 directives 选项:
directives: {
  focus: {
    // 指令定义对象
    inserted: function (el) {
      el.focus()
    }
  }
}

注意

全局自定义指令中参数1:指令的名称,在定义的名称前面,不需要加 v- 前缀。但是在调用的时候,必须 在指令名称前 加上 v- 前缀来进行调用。

全局自定义指令中参数2:是一个对象,这个对象身上,有一些指令相关的函数,这些函数可以在特定的阶段,执行相关操作。

 

<div id="app">
    自定义指令自动获取焦点:<input type="text" v-focus v-color="'red'">

    <!--<p v-fontSize="'40px'">哈哈哈哈,我使用了简写方式</p>-->
    <p v-font-size="'40px'">哈哈哈哈,我使用了简写方式</p>
</div>
<script>
    <!-- 定义全局指令 -->
    Vue.directive('focus', {
        bind: (el, binding) => { // 每当指令绑定到元素上的时候,会立即执行这个bind函数,只
            // 执行一次。
            // 注意在 每个 函数中,第一个参数,永远是el,表示 被绑定了指令的那个元素,
            // 这个el参数,是个原生的js对象。
            // 在元素 刚绑定了指令的时候,还没有 插入到 DOM中去,这时候
            // 调用focus方法没有作用,因为,一个元素,只有插入DOM之后,才能获取焦点
            // el.focus()


            // 和样式相关的操作,一般都可以在bind执行
        },
        inserted: (el, binding) => {
            // 在已绑定的元素插入到父节点时调用(只能保证父
            // 节点存在,不一定存在于 document 中)。
            el.focus();
            //  和JS行为有关的操作,最好在inserted中去执行,放置 JS行为不生效
        },
        update: (el, binding) => { // 当BNode更新的时候,会执行 updated,可能会触发多次

        },
        componentUpdated: (el, binding) => {

        },
        unbind: (el, binding) => {

        }
    });

    Vue.directive('color', {
        bind(el, binding) {
            console.log('指令名称', binding.name);
            console.log('指令值', binding.value);
            console.log('指令值(未计算过的)', binding.expression);
            el.style.color = binding.value;
        }
    });

    // 使用简写
    // 不能在自定义指令中使用驼峰命名法,要么全小写,要么使用font-size的形式
    // Vue.directive('fontSize', function (el, binding) {
    //     el.style.fontSize = parseInt(binding.value) + 'px';
    // })

    Vue.directive('font-size', function (el, binding) {
        el.style.fontSize = parseInt(binding.value) + 'px';
    });

    let vm = new Vue({
        el: '#app',
        data: {},
        methods: {},
        directives: {
            focus: { // 指令名称
                // 指令定义对象
                inserted: function (el) {
                    el.focus()
                }
            },
            // 简写方式:表示给fontSize写两个方法bind和update,且这两个方法公用同样的方法体
            // 不能在自定义指令中使用驼峰命名法,要么全小写,要么使用font-size的形式
            // fontSize: function(el, binding){
            //     el.style.fontSize = parseInt(binding.value) + 'px';
            // }
            'font-size':(el,binding)=>{
                el.style.fontSize = parseInt(binding.value) + 'px';
            }
        }
    })
</script>

 

过滤器

<div id="app">
    <!-- 过滤器可以在两种场景中使用:双花括号插
    值(mustache interpolation)和 v-bind 表达
    式(后者在 2.1.0+ 版本支持) -->

    <!-- 类似django模板过滤 -->
    <p>{{ msg | StrFilter }}</p>
    <!-- 可以连续过滤 -->
    <p>{{ msg | StrFilter | blackFilter }}</p>
    <!-- 可以传递多个参数:1-msg,2-*,3-* -->
    <p>{{ msg | strictFilter({name:'毛毛'},['1',2,3]) }}</p>
    <!-- 使用组件内部过滤器 -->
    <p>{{ msg | doFilter }}</p>
    <!-- 还可以用于属性绑定 -->
    <p :title="msg | doFilter">鼠标悬停一会看看</p>
</div>
<script>
    // vue定义全局过滤器[必须在创建实例之前!!!]
    Vue.filter('StrFilter', (str) => {
        return str.replace(/大/g, '小');
    });
    Vue.filter('blackFilter', (str) => {
        return str.replace(/黑/g, '白');
    });
    Vue.filter('strictFilter', (str, arg1, arg2) => {
        console.log(arg1, arg2);
        return str.replace(/黑/g, '白');
    });

    var vm = new Vue({
        el: '#app',
        data: {
            msg: '安徽省阜阳市是一个大大大的市区,里面有很多大佬和黑帮。'
        },
        methods: {},
        filters: {
            // 组件内部的过滤器
            doFilter(str) {
                return str.replace(/安徽省阜阳市/g, '**省**市');
            }
        }
    });
</script>

 

事件修饰符

在事件处理程序中调用

event.preventDefault() 或 event.stopPropagation()

是非常常见的需求。尽管我们可以在methods中轻松实现这点,但更好的方式是:methods只有存粹的数据逻辑,而不是去处理DOM事件细节。为了解决这个问题,vue为v-on提供了事件修饰符。修饰符是以点(.)开头的指令后缀来表示。

        •  .stop
        •  .prevent
        •  .capture
        •  .self
        •  .once
        •  .passive
<style>
        .inner {
            padding: 50px;
            margin: 2px;
            background-color: darkolivegreen;
        }
    </style>
    <script src="./lib/vue-2.4.0.js"></script>
</head>

<body>
<div id="app">
    <!-- 停止默认事件,提交/跳转等事件不再有效 -->
    <!--<a href="https://www.baidu.com" @click.prevent="doThis">去百度</a>-->

    <!-- 停止事件向上冒泡 -->
    <!--<div class="inner" @click="innerDivHandler">
        <button @click="doThis">去百度1</button>
    </div>
    <div class="inner" @click="innerDivHandler">
        <button @click.stop="doThis">去百度2</button>
    </div>-->

    <!-- 只要event.target是元素自身时,才触发处理函数 -->
    <!-- 也就是说,event.target 是子元素时,不触发处理函数 -->
    <!--<div class="inner" @click="innerDivHandler">
        <button @click="doThis">去百度1</button>
    </div>
    <div class="inner" @click.self="innerDivHandler">
        <button @click="doThis">去百度2</button>
    </div>-->

    <!-- 添加事件监听器,使用事件捕获模式 -->
    <!-- 也就是说,内部元素触发的事件先在此处处理,然后才交给内部元素进行处理 -->
    <!--<div @click.capture="doThis">...</div>-->

    <!-- 事件只会触发一次,修饰符可以链式调用 -->
    <!--<a href="https://www.baidu.com" @click.prevent.once="doThis">去百度</a>-->
    <!--<a href="https://www.baidu.com" @click.once.prevent="doThis">去百度</a>-->

    <!-- 滚动事件的默认行为(滚动)将立即发生, -->
    <!-- 而不是等待 `onScroll` 完成后才发生, -->
    <!-- 以防在滚动事件的处理程序中含有 `event.preventDefault()` 调用 -->
    <!--不要将 .passive 和 .prevent 放在一起使用,因为 -->
    <!--  .prevent 将被忽略,并且浏览器可能会显示一条警告。 -->
    <!-- 记住,.passive 会向浏览器传达的意思是,你_并不_希望阻止事件的默认行为。 -->
    <!--<div v-on:scroll.passive="onScroll">...</div>-->

</div>

<script>
    var vm = new Vue({
        el: '#app',
        data: {},
        methods: {
            doThis() {
                console.log('doThis');
            },
            innerDivHandler() {
                console.log('innerDivHandler');
            }
        }
    })
</script>

按键修饰符

 

常用的按键修饰符别名

 .enter

 .tab

 .delete (捕获“删除”和“退格”按键)

 .esc

 .space

 .up

 .down

 .left

 .right

 

 

基本使用

<div id="app">
    <!-- 监听按键码为13的keyup事件 -->
    按键码:<input type="text" v-model="msg" @keyup.13="add">

    <!-- enter为vue提供的一些常用按键别名 -->
    按键别名:<input type="text" v-model="msg" @keyup.enter="add">

    <!-- 使用自定义的按键别名 -->
    自定义按键别名:<input type="text" v-model="msg" @keyup.f1="add">

    <!-- 可以串联响应多个按键  -->
    串联响应多个按键:<input type="text" v-model="msg" @keyup.up.enter="add">

    <p>回车输出:{{txt}}</p>
</div>
<script>
    <!--自定义按键别名-->
    Vue.config.keyCodes.f1=13

    let vm = new Vue({
        el: '#app',
        data: {
            msg: '',
            txt: ''
        },
        methods: {
            add() {
                this.txt = this.msg;
            }
        }
    })
</script>

系统辅助按键

仅在以下修饰符对应的按键被按下时,才会触发鼠标或键盘事件监听器:

 .ctrl

 .alt

 .shift

 .meta

<div id="app">
    <!-- ctrl+enter触发add方法 -->
    按键码:<input type="text" v-model="msg" @keyup.ctrl.enter="add">

    <p>回车输出:{{txt}}</p>
</div>
<div id="app">
    <!-- ctrl+enter触发add方法 -->
    按键码:<input type="text" v-model="msg" @keyup.ctrl.enter="add">

    <!-- Ctrl + Click -->
    <div @click.ctrl="doSomething">做一些操作</div>

    <p>回车输出:{{txt}}</p>

    <!--.exact 修饰符可以控制触发事件所需的系统辅助按键的准确组合。-->
    <!-- 如果 Alt 键或 Shift 键与  Ctrl 键同时按下,也会触发事件 -->
    <button @click.ctrl="onClick">A</button>

    <!-- 只在 Ctrl 按键按下,其他按键未按下时,触发事件 -->
    <button @click.ctrl.exact="onCtrlClick">A</button>

    <!-- 只在没有系统辅助按键按下时,触发事件 -->
    <button @click.exact="onClick">A</button>
</div>

鼠标按键修饰符

仅仅针对于特定鼠标:

 .left

 .right

 .middle

 

 

class与style绑定

在数据绑定中,一个常见的需求是,将数据与元素的class列表,以及元素的style内联样式的操作绑定在一起。由于它们都是属性(attribute),因此我们可以使用v-bind来处理它们:只需从表达式中计算出最终的字符串。然而,处理字符串拼接,即麻烦又容易出错。为此,在使用 v-bind 指令来处理 class 和 style 时,Vue 对此做了特别的增强。表达式除了可以是字符串,也能够是对象和数组。

<style>
        .red {
            color: red;
        }

        .italic {
            font-style: italic;
        }

        .thin {
            font-weight: 200;
        }

        .active {
            font-size: 50px;
        }
    </style>
    <script src="./lib/vue-2.4.0.js"></script>
</head>

<body>
<div id="app">
    <!--<h1 class="red italic thin active">这是一个大的H1</h1>-->

    <!-- 第一种使用方式,直接传递一个数组,注意:这里的class需要使用 v-bind做数据绑定 -->
    <!--<h1 :class="['thin','italic']">这是一个大的H1</h1>-->

    <!-- 在数组中使用三元表达式 -->
    <!--<h1 :class="['thin','italic',flag?'active':'']">这是一个大的H1</h1>-->

    <!-- 在数组中使用 对象 来替代三元表达式,提高代码可读性 -->
    <!--<h1 :class="['thin','italic',{active:flag}]">这是一个大的H1</h1>-->

    <!-- 在为class使用 v-bind 绑定对象的时候,对象的属性是类名,由于 对象的属性可
       带引号,也可以不带引号,所以这里我没写引号;属性的值 是一个标识符
     -->
    <h1 :class="classObj">这是一个大的H1</h1>
</div>

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            flag: true,
            classObj: {red: true, italic: true, active: false, thin: true}
        },
        methods: {}
    })
</script>

行内样式:

<div id="app">
    <!-- 由于对象中的键不允许直接使用-,所以要用引号引起来 -->
    <!--<h1 :style="{color:'red','font-size':'50px'}">这是一个大的H1</h1>-->

    <!-- 在data上直接定义,然后绑定 -->
    <!--<h1 :style="styleObj">这是一个大的H1</h1>-->

    <!-- 通过数组引用多个data上定义的样式对象 -->
    <h1 :style="[styleObj,style2Obj]">这是一个大的H1</h1>
</div>

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            styleObj: {color: 'red', 'font-size': '50px'},
            style2Obj: {'font-style': 'italic'},
        },
        methods: {}
    })
</script>

组件

 

概念

 

什么是组件

组件的出现,就是为了拆分Vue实例的代码量的,能够让我们以不同的组件,来划分不同的功能模块,将来我们需要什么样的功能,就可以调用对应的组件即可;

 

组件化和模块化的不同

模块化:是从代码逻辑的角度进行划分的;方便代码分层开发,保证每个功能模块的职能单一;

组件化:是从UI界面的角度进行划分的;前端的组件化,方便UI组件的重用;

 

 

创建组件的方式

 

方式1

<body>
<div id="app">
    <!-- 1.3 在页面中引用定义的组件 -->
    <!-- <my-com1></my-com1> -->
    <mycom1></mycom1>
</div>
<script>
    // 1.1 使用Vue.extend 来创建全局的Vue组件模板HTML
    // 通过 template 属性,指定了组件要展示的HTML结构
   // var com1 = Vue.extend({
   //      template:'<h3>这是使用Vue.extend创建的组件</h3>'
   //  });

       // 1.2 使用Vue.component('组件的名称',创建出来的组件模板对象)生成组件
       // Vue.component('myCom1',com1)

       // 如果使用Vue.component 定义全局组件的时候,组件名称使用了 驼峰命名,则在引用的时候,需要把大写的驼峰改为小写的字母,同时,两个单词之间,使用 - 链接
    // Vue.component('myCom1',com1);

    // 如果不使用驼峰,则直接拿名称来使用即可;
    // Vue.component('mycom1',com1);



    // 我们其实没必要把创建组件的过程拆分两部,下面将使用一步的方式
    Vue.component('mycom1',Vue.extend({
        template:'<h3>这是使用Vue.extend创建的组件</h3>'
    }))


    var vm = new Vue({
        el: "#app",
        data: {
            
        },
        methods: {
            
        }
    });
</script>

方式2

<div id="app">
    <mycom2></mycom2>
</div>
<script>
    <!-- 可以直接在定义组件时,直接写组件模板HTML -->
    Vue.component('mycom2',{
        //  注意组件内的模板只能有一个根元素
        // template:'<h2>你好,组件2</h2><span>哈哈啊哈</span>'
        template:'<div><h2>你好,组件2</h2><span>哈哈啊哈</span></div>'
    })


    Vue.filter('method', (args) => {
        return ``;
    })

    // 实例必须定义,因为组件依赖实例中的el元素
    var vm = new Vue({
        el: "#app",
        data: {
            
        },
        methods: {
            
        }
    });
</script>

 

方式3

<template id="mytemp1">
    <!-- 同样的,只能有一个根元素 -->
    <div>
        <h3>模板3的方式很方便,哈哈哈哈</h3>
    </div>
</template>
<script>
    <!-- 使用前两种创建方式,都不能在template里有html代码提示,第三种方式是将template抽离出来,放到被管理的app之外,然后再template中指定对应的模板,最后在app中直接引入即可 -->
    Vue.component('mycom3',{
        template:'#mytemp1'
    })

    var vm = new Vue({
        el: "#app",
        data: {
            
        },
        methods: {
            
        }
    });
</script>

 

私有组件

<div id="app">
            <mycom4>
            </mycom4>
        </div>
        <div id="app2">
            <!-- <mycom4></mycom4> -->
        </div>
        <template id="teml4">
            <h4>
                哈哈我是一个私有组件
            </h4>
        </template>
        <script>
            Vue.filter('method', (args) => {
                return ``;
            })

            var vm1 = new Vue({
                el: "#app",
                data: {
                    
                },
                methods: {
                    
                },
                filters:{},
                directives:{},
                components:{
                    mycom4:{
                        template:'#teml4'
                    }
                },

                beforeCreat() {},
                created(){},
                beforeMount(){},
                mounted(){},
                beforeUpdate(){},
                updated(){},
                beforeDestory(){},
                destoryed(){},
                afterDestory(){}
            });

            var vm2 = new Vue({
                el:"#app2"
            })
        </script>

 

组件中的data和method

<div id="app">
            <mycom1>
            </mycom1>
            <hr>
            <mycom1>
            </mycom1>
            <hr>
            <mycom1>
            </mycom1>
            <hr>
        </div>
        <template id="templ">
            <div>
                <input @click="increament" name="" value="increament" type="button">
                    <h3>
                        {{count}}
                    </h3>
                </input>
            </div>
        </template>
        <script>
            var obj = {count:0};

            // 如果data不是一个methods的话(而是一个对象obj),
            // 那么每次创建一个新的组件,都会像使用全局变量一样,这样导致
            // 的结果就是所有的组件共用变量。
            Vue.component('mycom1',{
                template:"#templ",
                data:function(){
                    // return obj;

                    // 这样写是为每个组件都开辟一块内存区域
                    return {count:0};
                },
                methods:{
                    increament() {
                        this.count++;
                    }
                }
            })
            var vm = new Vue({
                el: "#app",
                data: {
                    
                },
                methods: {
                    
                }
            });
        </script>

 

组件动画

<style type="text/css">
        .v-enter,.v-leave-to {
            opacity: 0;
            transform: translateX(100px);
        }
        .v-enter-active,.v-leave-active {
            transition: all .8s ease;
        }
    </style>
</head>
<body>
<div id="app">
    <a href="" @click.prevent="templ = 'login'">登陆</a>
    <a href="" @click.prevent="templ = 'register'">注册</a>

    <!-- 对组件使用动画,只需要使用transition包裹起来即可 -->
    <!-- 使用mode指定动画执行的顺序模式:先出后进 -->
    <transition mode="out-in">
        <component :is="templ"></component>
    </transition>
</div>
<script>
   
    var vm = new Vue({
        el: "#app",
        data: {
            templ:'login'
        },
        methods: {
            
        },
        components:{
            login:{
                template:"<h3>登陆模块</h3>"
            },
            register:{
                template:"<h3>注册模块</h3>"
            }
        }
    });
</script>

父组件给子组件传值

 

父子组件的概念图

 

父组件给子组件传递值

首先,子组件是不能直接获取父组件里的值的,要想获取值需要在组件标签中使用指令绑定一个变量,传递给子组件中,如下:

<div id="app">
    <shop v-bind:parentmsg="msg"></shop>
</div>

子组件shop要获得父组件里的msg,需要使用属性绑定指令绑定一个变量,将父组件里的某个变量传递给这个变量,然后:

    components:{
            shop:{
                template:'#list',
                props:['parentmsg']
            }
        }

在子组件里,通过props指定的变量引入父组件里绑定的值,注意:props是一个数组,它里面的内容即为要引入的变量名称(通过名称引入)

<body>
        <div id="app">
            <shop v-bind:parentmsg="msg">
            </shop>
        </div>
        <template id="list">
            <div>
                <p>
                    从父组件里传来的数据---{{parentmsg.mm}}
                </p>
            </div>
        </template>
        <script>
            var vm = new Vue({
                el: "#app",
                data: {
                    msg:{mm:'我是父组件里的信息'}
                },
                methods: {
                    
                },
                components:{
                    // 结论:经过演示发现,子组件中,默认无法访问到父组件中的 data 上的数据 和 methods中的方法
                    shop:{
                        template:'#list',
                        data:()=>{ // 注意:子组件中的data数据,并不是通过 父组件传递过来的,而是子组件自身私有的,比如:子组件通过Ajax,请求回来的数据,都可以放到data身上;
                            // data上的数据都是可写的
                            return {
                                title:'abc',
                                name:'123'
                            }
                        },
                        methods:{

                        },
                        // 注意:组件中的所有props中的数据,都是通过父组件传递给子组件的
                        // props上的数据都是只读的
                        props:['parentmsg'] // 把父组件传递过来的 parentmsg属性,先在props数组中,定义一下,这样,才能使用这个数据
                    }
                }
            });
        </script>

思考:是传值还是传引用?

不管你是传递值还是传递引用,注意:在子组件中都不允许修改父组件传递过来的值,也就是说子组件只能使用,而不能修改。

 

注意:子组件想要获取父组件内的数据,必须通过组件传值的方式去获取。但是对于DOM操作,子组件直接可以使用document对象去操作父组件内部的元素【挂载完毕后】,例如子组件的某元素通过click方法,获取父组件内部某个元素,此时dom已经渲染完毕,针对dom操作以及跨越了组件,和组件并无关系了。

 

 

父组件给子组件传递方法

<div id="app">
            <!-- 传递子组件方法,使用v-on绑定事件的形式将父组件中的方法绑定到子组件身上 -->
            <!-- func为getMsg在子组件中的别名,getMsg为父组件的methods -->
            <shop @func="getMsg">
            </shop>
        </div>
        
        <template id="list">
            <div>
                <!-- 调用子组件的info方法 -->
                <button @click="info">点击调用父组件中的方法</button>
            </div>
        </template>
        <script>
            var vm = new Vue({
                el: "#app",
                data: {
                    
                },
                methods: {
                    getMsg(data1,data2){
                        console.log('我是父组件的methods' + data1 + data2);
                    }
                },
                components:{
                    shop:{
                        template:'#list',
                        data:()=>{
                            return {
                                title:'abc',
                                name:'123'
                            }
                        },
                        methods:{
                            info(){
                                // 子组件可以通过通过$emit触发执行绑定到自己身上的func方法
                                // 如果有参数,参数直接写在方法名后
                                this.$emit('getMsg',123,222);
                            }
                        }
                    }
                }
            });
        </script>

子组件给父组件传递值【事件调用机制】

子组件给父组件传递值,只能是被动方式传递,即某个事件触发,才能传递。子组件向父组件传递值采用了父组件给子组件传递方法的方式。

<div id="app">
            <!-- 传递子组件方法,使用v-on绑定事件的形式将父组件中的方法绑定到子组件身上 -->
            <shop @func="getMsg">
            </shop>
        </div>
        <template id="list">
            <div>
                <button @click="info">点击调用父组件中的方法</button>
            </div>
        </template>
        <script>
            var vm = new Vue({
                el: "#app",
                data: {
                    childdata:null
                },
                methods: {
                    getMsg(data){
                        this.childdata = data;
                    }
                },
                components:{
                    shop:{
                        template:'#list',
                        data:()=>{
                            return {
                                title:'abc',
                                name:'123'
                            }
                        },
                        methods:{
                            info(){
                                // 当子组件中的方法被调用时,会执行父组件中的方法,此时,将要传递给父组件的值通过函数的参数传递过去,在父组件中接收。
                                // 子组件向父组件传值只能被动的传递(有事件触发)
                                this.$emit('func',this.title);
                            }
                        }
                    }
                }
            });
        </script>

 

使用ref引用DOM或组件

<div id="app">
        <!-- <p ref="ppp">我能通过ref引用到p元素</p> -->
        <!-- 如果ref指定的名称被多个元素占用,则只使用最后一个 -->
        <p ref="ppp">我能通过ref引用到p元素</p>

        <!-- 使用ref还可以引用组件 -->
        <login ref="logref"></login>
    </div>
    <template id="mytempl">
        <div></div>
    </template>

    <script>

        var vm = new Vue({
            el: '#app',
            data: {

            },
            methods: {

            },
            components:{
                login:{
                    template:"#mytempl",
                    data:()=>{
                        return {
                            title:'哈哈哈'
                        }
                    }
                }
            }
        });

        console.log(vm.$refs.ppp);
        console.log(vm.$refs.logref);
        console.log(vm.$refs.logref.title);

    </script>

 

使用render渲染组件

我们的组件除了使用特殊占位符替换以外,还可以使用render渲染我们的组件,不同的是这两者就类似于v-text和插值表达式,render渲染的组件会直接覆盖容器里的所有内容,而使用占位符的形式组件只会替换占位符位置的内容。

<script src="../lib/vue-2.4.0.js"></script>
</head>

<body>
<div id="app">
</div>

<script>
    var login = {
        template:"<h1>登陆模块</h1>"
    }

    var vm = new Vue({
      el: '#app',
      render:function(createElements) { 
          // createElements是一个方法,调用它,能够把指定的组件模板,渲染为 html 结构
            return createElements(login)
            // 注意:这里 return的结果,会替换页面中的el指定的那个容器
      }
    })
  </script>

 

前进时,请别遗忘了身后的脚印。
原文地址:https://www.cnblogs.com/liudaihuablogs/p/13468948.html