Vue.js,学习心得(十二)组件二

学习心得,
组件(二),

直接上代码了

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Prop</title>
    <script src="../js/vue.js"></script>
</head>
<body>
<div id="app-1">
    <div is="child1" message="HI~~Vue.js"></div>
</div>
<hr>

<div id="app-2">
    <!-- 在 HTML 中使用 kebab-case -->
    <div is="child2" my-message="Hello~~2"></div>
</div>
<hr>

<div id="app-3">
    <input v-model="parentMsg">
    <br>
    <div is="child3" v-bind:my-message="parentMsg" v-bind="todo"></div>

</div>
<hr>

<!--字面量语法 vs 动态语法-->

<!--初学者常犯的一个错误是使用字面量语法传递数值:-->
<!--&lt;!&ndash; 传递了一个字符串 "1" &ndash;&gt;-->
<!--<comp some-prop="1"></comp>-->
<!--因为它是一个字面量 prop,它的值是字符串 "1" 而不是一个数值。如果想传递一个真正的 JavaScript 数值,则需要使用 v-bind,从而让它的值被当作 JavaScript 表达式计算:-->
<!--&lt;!&ndash; 传递真正的数值 &ndash;&gt;-->
<!--<comp v-bind:some-prop="1"></comp>-->



<!--非 Prop 特性-->

<!--所谓非 prop 特性,就是指它可以直接传入组件,而不需要定义相应的 prop。-->
<!--尽管为组件定义明确的 prop 是推荐的传参方式,组件的作者却并不总能预见到组件被使用的场景。-->
<!--所以,组件可以接收任意传入的特性,这些特性都会被添加到组件的根元素上。-->
<!--例如,假设我们使用了第三方组件 bs-date-input,它包含一个 Bootstrap 插件,该插件需要在 input 上添加 data-3d-date-picker 这个特性。-->
<!--这时可以把特性直接添加到组件上 (不需要事先定义 prop):-->
<!--<bs-date-input data-3d-date-picker="true"></bs-date-input>-->
<!--添加属性 data-3d-date-picker="true" 之后,它会被自动添加到 bs-date-input 的根元素上。-->

<div id="app-4">
    <span is="bs-date-input" data-3d-date-picker="true" class="date-picker-theme-dark"></span>
</div>
<hr>

<div id="app-5">
    <p>{{totals}}</p>
    <button-counter v-on:increments="incrementTotals"></button-counter>
    <button-counter v-on:increments="incrementTotals"></button-counter>
</div>
<hr>


    <!--.sync 修饰符-->
    <!--<comp :foo.sync="bar"></comp>-->





<!--使用自定义事件的表单输入组件-->

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

<!--<input v-model="something">-->

<!--这不过是以下示例的语法糖:-->
<!--<input-->
        <!--v-bind:value="something"-->
        <!--v-on:input="something = $event.target.value">-->
<!--所以在组件中使用时,它相当于下面的简写:-->
<!--<custom-input-->
        <!--v-bind:value="something"-->
        <!--v-on:input="something = arguments[0]">-->
<!--</custom-input>-->



<div id="app-6">
    <currency-input v-model="price"></currency-input>
</div>
<hr>





<div id="app-7">
    <my-checkbox v-model="foo" value="some value"></my-checkbox>
</div>
<hr>




<script>
    //使用Prop传递数据
    //组件实例的作用域是孤立的。
    //这意味着不能 (也不应该) 在子组件的模板内直接引用父组件的数据。
    //父组件的数据需要通过 prop 才能下发到子组件中。
    //子组件要显式的用props选项声明它预期的数据:
    Vue.component('child1',{
        //声明 props
        props:['message'],
        //就像data一样,prop也可以用在模板中使用
        //同样也可以在 vm 实例中通过 this.message 来使用
        template:'<span>{{message}}</span>'
    });
    var app1 = new Vue({
        el:"#app-1"
    });

    //    camelCase vs. kebab-case
    //
    //    HTML 特性是不区分大小写的。
    //    所以,当使用的不是字符串模板时,camelCase (驼峰式命名) 的 prop 需要转换为相对应的 kebab-case (短横线分隔式命名):
    Vue.component('child2',{
        // 在 JavaScript 中使用 camelCase
        props:['myMessage'],
        template:'<span>{{myMessage}}</span>'
    });
    var app2 = new Vue({
        el:"#app-2"
    });

    //动态Prop
    //与绑定到任何普通的 HTML 特性相类似,
    // 我们可以用 v-bind 来动态地将 prop 绑定到父组件的数据。
    // 每当父组件的数据变化时,该变化也会传导给子组件:

    //    如果你想把一个对象的所有属性作为 prop 进行传递,
    //    可以使用不带任何参数的 v-bind (即用 v-bind 而不是 v-bind:prop-name)。
    //    例如,已知一个 todo 对象:

    var app3 = new Vue({
        el:"#app-3",
        data:{
            parentMsg:'',
            todo:{
                text:'Learn Vue',
                isComplete:false
            }
        },
        components:{
            child3:{
                props:['myMessage','text'],
                template:'<span>{{myMessage}},{{text}}</span>'
            }
        }
    });

    //单项数据流
    //    Prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是反过来不会。
    //    这是为了防止子组件无意间修改了父组件的状态,来避免应用的数据流变得难以理解。
    //另外,每次父组件更新时,子组件的所有 prop 都会更新为最新值。
    //    这意味着你不应该在子组件内部改变 prop。如果你这么做了,Vue 会在控制台给出警告。
    //在两种情况下,我们很容易忍不住想去修改 prop 中数据:
    //Prop 作为初始值传入后,子组件想把它当作局部数据来用;
    //Prop 作为原始数据传入,由子组件处理成其它数据输出。
    //对这两种情况,正确的应对方式是:
    //1.定义一个局部变量,并用 prop 的值初始化它:
    //    props: ['initialCounter'],
    //        data: function () {
    //        return { counter: this.initialCounter }
    //    }

    //    2.定义一个计算属性,处理 prop 的值并返回:
    //props: ['size'],
    //    computed: {
    //        normalizedSize: function () {
    //            return this.size.trim().toLowerCase()
    //        }
    //    }
    //    注意在 JavaScript 中对象和数组是引用类型,指向同一个内存空间,
    // 如果 prop 是一个对象或数组,在子组件内部改变它会影响父组件的状态。

    //Prop验证
    //我们可以为组件的 prop 指定验证规则。
    //如果传入的数据不符合要求,Vue 会发出警告。
    //这对于开发给他人使用的组件非常有用。
    //要指定验证规则,需要用对象的形式来定义 prop,而不能用字符串数组:


    Vue.component('child3',{
        props:{
            //基础类型检测('null',指允许任何类型)
            propA: Number,
            //可能是多种类型
            propB: [String, Number],
            //必传且是字符串
            propC:{
                type:String,
                required:true
            },
            //数值且有默认值
            propD:{
                type:'Number',
                default:100
            },
            //数组/对象的默认值应当由一个工厂函数返回
            propE:{
                type:'Object',
                defalut:function(){
                    return {message:'hello'}
                }
            },
            //自定义验证函数
            propF:{
                validator:function(value){
                    return value > 10
                }
            }

        }
    });
    //    type 可以是下面原生构造器:
    //    String
    //    Number
    //    Boolean
    //    Function
    //    Object
    //    Array
    //    Symbol
    //    type 也可以是一个自定义构造器函数,使用 instanceof 检测。
    //    当 prop 验证失败,Vue 会抛出警告 (如果使用的是开发版本)。
    //    注意 prop 会在组件实例创建之前进行校验,
    //    所以在 default 或 validator 函数里,诸如 data、computed 或 methods 等实例属性还无法使用。

    //非Prop特性

    //替换/合并现有的特性
    Vue.component('bs-date-input',{
        template:'<input type="date" class="form-control">'
    });
    var app4 = new Vue({
        el:"#app-4"
    });

    //自定义事件
    //    我们知道,父组件使用 prop 传递数据给子组件。但子组件怎么跟父组件通信呢?这个时候 Vue 的自定义事件系统就派得上用场了。
    //    使用 v-on 绑定自定义事件
    //
    //    每个 Vue 实例都实现了事件接口,即:
    //    使用 $on(eventName) 监听事件
    //    使用 $emit(eventName) 触发事件
    //    Vue 的事件系统与浏览器的 EventTarget API 有所不同。
    //    尽管它们的运行起来类似,但是 $on 和 $emit 并不是addEventListener 和 dispatchEvent 的别名。
    //
    //    另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
    //    不能用 $on 侦听子组件释放的事件,而必须在模板里直接用 v-on 绑定,参见下面的例子。

    //声明是子组件,调用是父组件

    Vue.component('button-counter',{
        template:'<button v-on:click="incrementTotals">{{counter}}</button>',
        data:function(){
            return {
                counter:0
            }
        },
        methods:{
            incrementTotals:function () {
                this.counter += 1;
                this.$emit("increments");
            }
        }
    });

    var app5 = new Vue({
        el:"#app-5",
        data:{
            totals:0
        },
        methods:{
            incrementTotals:function () {
                this.totals +=1 ;
            }
        }
    });
    //    给组件绑定原生事件
    //
    //    有时候,你可能想在某个组件的根元素上监听一个原生事件。
    // 可以使用 v-on 的修饰符 .native。例如:



    //所以要让组件的 v-model 生效,它应该 (从 2.2.0 起是可配置的):
    //接受一个 value prop
    //    在有新的值时触发 input 事件并将新值作为参数
    //    我们来看一个非常简单的货币输入的自定义控件:

    Vue.component('currency-input',{
        template:'<span>$' +
        '<input ref="inputr" v-bind:value="value" v-on:input="updateValue($event.target.value)">' +
        '</span>',
        props:['value'],
        methods:{
            //不是直接更新,而是使用此方法来对输入值进行改格式化和位数限制
            updateValue:function(value){
                var formattedValue = value
                //删除两侧的空格符
                    .trim()
                //保留2位小数
                    .slice(
                        0,
                        value.indexOf('.') === -1
                        ? value.length
                            :value.indexOf('.') + 3
                    )
                //如果值上不合规,则手动覆盖为合规的值
                if(formattedValue !== value){
                    this.$refs.inputr.value = formattedValue;
                }
                //通过input 事件带出数值
                this.$emit('input', Number(formattedValue));

            }
        }
    });

    var app6 = new Vue({
        el:'#app-6',
        data:{
            price:''
        }
        //为什么price写在这里,哪里用到了v-model="price" ??
    });



//    自定义组件的 v-model
//    默认情况下,一个组件的 v-model 会使用 value prop 和 input 事件。
//    但是诸如单选框、复选框之类的输入类型可能把 value 用作了别的目的。
//    model 选项可以避免这样的冲突:


    Vue.component('my-checkbox',{
        template:'<input type="checkbox">',
        model:{
            prop:'checked',
            event:'checked'
        },
        props:{
            checked:Boolean,
            value:String
        }
    });


    var app7 = new Vue({
        el:'#app-7',
        data:{
            foo:''
        }
        //    没调通,看不明白
    });


//    非父子组件的通信
//
//    有时候,非父子关系的两个组件之间也需要通信。
    // 在简单的场景下,可以使用一个空的 Vue 实例作为事件总线:

    var bus = new Vue();

    //触发组件A中的事件
    bus.$emit('id-selected',1);

    //在组件B创建的钩子中监听事件
    bus.$on('id-selected',function(id){
        //...
    })


//    使用插槽分发内容




</script>
</body>
</html>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容