浅谈Vue下的components模板

组件

创建方式一:

HTML: <div id="app"><c1></c1></div>

/*要注意,局部模板的作用范围 只在 相对的vue对象 范围内, 比如此例子 <haha></haha>的作用范围 只在 <div id="app"></div>内*/

let vm = new Vue({ ...

    components:{"c1":{ template:"<div>i am c1<div>" }}

});

 

创建方式二:Vue.component 全局组件 --- 全局模板 顾名思义 肯定是 放在哪里都能用

HTML: <div id="app"><c2></c22></div>

 

//这里使用Vue.component原型方法来创造。注意,全局组件注册位置必须在父实例的模块上面(即在初始化组件根实例之前,注册好组件)

Vue.component(

      "c2",

      template:"<div>i am c2<div>"

);

let vm = new Vue({...,components:{  这里则不需要添加 } });

 

创建方式三:局部注册

不必在全局注册每个组件。通过使用组件实例选项注册,可以使组件仅在另一个实例/组件的作用域中可用:

HTML: <div id="app"><c3></c3></div>

 

let c3={ template:"<div>嘻嘻嘻<div>" }

let vm = new Vue({ ...,components: { c3});

 

防止有些浏览器不认识标签报错,用 is 属性判断

is 属性判断

 

组件中的data必须返回object类型

 

父、子组件

在 Vue.js 中,父子组件的关系可以总结为 props down, events up 。父组件通过 props 向下传递数据给子组件,子组件通过 events 给父组件发送消息。看看它们是怎么工作的。

 

使用Props传递数据

组件实例(父实例)的作用域是孤立的。这意味着不能并且不应该在子组件的模板内直接引用父组件的数据。可以使用 props 把数据传给子组件。

注:把父实例的引用类型的数据传给子组件,子组件也能反向修改这个引用类型的数据。这种操作方式有两面性,看个人怎么用了,官方是不推荐这么操作,如上是建议用props把数据传给子组件,通过event或emit返给父实例/父组件

例如:

 

prop 是父组件用来传递数据的一个自定义属性。子组件需要显式地用 props 选项 声明 “prop”:

 

Vue.component('child', {

// 声明 props

props: ['message'], //prop 是父组件用来传递数据的一个自定义属性, props: ['属性名']

// 就像data 一样,prop可用在模板内. 同样也可在 vm实例中像"this.message"这样使用

template: '<span>{{ message }}</span>'

})

然后向它传入一个普通字符串:

 

<child message="hello!"></child> //子组件需要显式地用 props选项声明

动态 Props

v-bind

类似于用 v-bind 绑定 HTML 特性到一个表达式,组件也可以使用 v-bind 动态绑定 props 的值 到 父组件的数据中

每当父组件的数据变化时,该变化也会传给子组件:

 

<div>

//[父组件的数据中,每当父组件的数据变化时,该变化也会传导给子组件]

<input v-model="parentMsg"> //双向绑定

<br>

<child v-bind:my-message="parentMsg"></child> //子组件

</div>

使用 v-bind 的缩写语法通常更简单:<child :my-message="parentMsg"></child>

 

 

字面量语法 vs 动态语法

初学者常犯的一个错误是使用字面量语法传递数值:

<!-- 传递了一个字符串"1" -->

<comp some-prop="1"></comp>

因为它是一个字面 prop ,它的值以字符串 "1" 而不是以实际的数字传下去。

如果想传递一个实际的 JS数字,需要使用 v-bind ,从而让它的值被当作JS表达式计算:

<!-- 传递实际的数字 -->

<comp v-bind:some-prop="1"></comp>

 

 

注: 测试发现,在组件的prop中, prop-name="..." 和 v-bind:prop-name="..." 有区别

 

单向数据流

prop 是单向绑定的当父组件的属性变化时,将传导给子组件,但是不会反过来。这是为了防止子组件无意修改了父组件的状态。

另外,每次父组件更新时,子组件的所有 prop 都会更新为最新值。这意味着你不应该在子组件内部改变 prop 。如果你这么做了,Vue 会在控制台给出警告。(个人测试没有警告!!!)

通常有两种改变 prop 的情况:(父影响子,子不影响父)

1. prop 作为初始值传入子组件之后只是将它的初始值作为本地数据的初始值使用. 在这种情况下,最好定义一个本地的 data 属性并将这个 prop 用作其初始值

 

例如,定义一个局部 data 属性,并将 prop 的初始值作为局部数据的初始值:

props: ['initialCounter'], //子组件
  data: function () { //子组件
  return { counter: this.initialCounter }//counter子组件的局部数据
}

父控件的变量值作为子组件的属性值,如:

2. 这个 prop 以一种原始的值传入且需要进行转换。在这种情况下,最好使用这个 prop 的值来定义一个计算属性

    例如,在 computed 定义一个属性,此属性从 prop 的值计算得出。

    <div id="div8">

        <input type='text' v-model="msg">

        <child v-bind:message='msg'></child>

    </div>

    <script type="text/javascript">

        Vue.component('child', {

            props: ['message'],

            template: '<p>message:{{ normalizedSize}} </p>',

            computed: {

                normalizedSize: function() {

                    return this.message += "_str"

                }

            }

        })

        new Vue({

            el: '#div8',

            data: {

                msg: '我是msg'

            }

        })

    </script>

 

执行结果:

 

再如:从父控件向子组件传值

   

 

 

Prop 验证

组件可以为 props 指定验证要求。如果未指定验证要求,Vue 会发出警告。当组件给其他人使用时这很有用。

prop 是一个对象而不是字符串数组时,它包含验证要求:

type 可以是下面原生构造器:

  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array

type 也可以是一个自定义构造器,使用 instanceof 检测。

当 prop 验证失败了, Vue 将拒绝在子组件上设置此值,如果使用的是开发版本会抛出一条警告

 

#自定义事件

我们知道,父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,应该怎样做?那就是自定义事件!

 

使用 v-on 绑定自定义事件

每个 Vue 实例都实现了事件接口(Events interface),即:

  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件

另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。

下面是一个例子,在本例中,子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件:

 

给组件绑定原生事件

有时候,你可能想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:

<my-component v-on:click.native="doTheThing"></my-component>

使用自定义事件的表单输入组件

自定义事件也可以用来创建自定义的表单输入组件,使用 v-model 来进行数据双向绑定。牢记:

<input v-model="something">

仅仅是一个语法糖,他也相当于:<input v-bind:value="something" v-on:input="something = $event.target.value">

所以在组件中使用时,它相当于下面的简写<input v-bind:value="something" v-on:input="something = arguments[0]">

所以要让组件的 v-model 生效,它必须:

  • 接受一个 value 属性
  • 在有新的 value 时触发 input 事件

例如,货币过滤器:

 

 

 

 

(模板的继承)全局模板 顾名思义 肯定是 放在哪里都能用

/*

  我们来讲个最简单的 父亲,儿子 ,孙子的 例子

  要注意以下几点:

        1.先实例化对象vm

        2.造出parent模板,并挂载在 vm的 conponents 下

        3.造出 son 模板 并 挂载 在 父级 parent 的conponents下,并在 父级template属性中 包裹住自己的 模板名标签 ;同理 造出孙子标签

        4.在HTML节点中添加 目标 根节点

              (节点的顺序一定要书写正确)

*/

<div id="app">

    <parent></parent>

</div>

 

//创建 孙子 模板

let grendson = { 

    template:"<div>孙子</div>"

}

 

//创建 儿子 模板

let son= { 

    template: "<son>儿子<grendson >孙子</grendson ></son>"

    components:{

        grendson 

    }

}

 

//创建 父亲 模板

let parent = { 

    template:"<div>父亲<son></son></div>"

    components:{

        son

    }

}

//实例化vm对象

let vm = new Vue({

    el: "#app",

    data:{

    },

    components:{

        parent

    }

});

 

 

 

实例一

 

css:

<style type="text/css">

        .tab-button {

          padding: 6px 10px;

          border-top-left-radius: 3px;

          border-top-right-radius: 3px;

          border: 1px solid #ccc;

          cursor: pointer;

          background: #f0f0f0;

          margin-bottom: -1px;

          margin-right: -1px;

        }

        .tab-button:hover {

          background: #e0e0e0;

        }

        .tab-button-active {

          background: #e0e0e0;

        }

        .tab {

          border: 1px solid #ccc;

          padding: 10px;

        }

</style>

 

html:

<div id="app">

        <div v-for="(item, index) in buttons">

            <button @click="change($event)" :id="item.id" class="tab-button" 

                 :class="{'tab-button-active': item.isActive}">{{item.name}}</button>

            <div class="tab">

                <component v-bind:is="currentTabComponent"></component>

            </div>

        </div>

</div>

 

script:

var vm = new Vue({

    el: '#app',

    data:{

        currentTab: 'Home',

        tabs:['Home','Posts','Archive'],

        buttons: [

            {id: 0, name: 'Home', isActive:true},

            {id: 1, name: 'Posts', isActive:false},

            {id: 2, name: 'Archive', isActive:false}

        ],

        isActive: false,

        prevBtn: 0

    },

    computed: {

        // 计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。

        // 这里当 this.index 有改变时,currentView()会重新求值

        currentTabComponent(){

            return 'tab-' + this.currentTab.toLowerCase()

        }

    },

    methods: {

        change( $event ){

            var index = $event.target.id;

            

            Vue.set(vm.buttons[vm.prevBtn], 'isActive', false);

            Vue.set(vm.buttons[index], 'isActive', true);

            this.currentTab = this.tabs[index%3];

            

            vm.prevBtn = index;

        }

    }

})

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值