zoukankan      html  css  js  c++  java
  • 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和SSH---Gitee码云
    详解elementUI表单的验证规则---vue(基本用法)
    vscode 设置缩进 4
    vue的图片懒加载
    A complete log of this run can be found in问题解决
    简单直观的搞懂Vue3的ref、reactive、toRef、toRefs
    vue-cli3.0 引入外部字体并使用
    迅为与龙芯强强联合匠心之作iTOP-2K1000开发板正式发布
    迅为RK3399开发板外接固态硬盘测试
    迅为i.MX6Q开发板Ubuntu20.04 Can通信
  • 原文地址:https://www.cnblogs.com/liudaihuablogs/p/13468948.html
Copyright © 2011-2022 走看看