Vue 忽略自定义标签名&插件开发&组件数据传递和共享—>父传子

发布于:2022-12-16 ⋅ 阅读:(467) ⋅ 点赞:(0)
忽略自定义标签名
通过全局配置 app.config.compilerOptions.isCustomElement 设置需要被忽略
的自定义标签
  • 取值:(tag: string) => boolean
  • 用法:
const app = Vue . createApp ({ /* ... */ }). mount ( "#app" );
app . config . compilerOptions . isCustomElement = tag =>
tag . startsWith ( 'ion-' );
须使 Vue 忽略在 Vue 之外的自定义元素 (e.g. 使用了 Web ComponentsAPIs)。否则,它会假设你忘记注册全局组件或者拼错了组件名称,从而抛出一个关于 Unknown custom element 的警告。
  <link rel="stylesheet" href="../../assets/font/iconfont.css">
    <style>
        body{
            padding-bottom: 800px;
        }
        .iconfont{
            font-size: 30px;
        }
        icon-message,icon-set,collection{
            font-family: "iconfont" !important;
            font-size: 30px;
        }
        icon-message::before{
            content: "\e77e";
        }
        icon-set::before{
            content: "\e78e";
        }
        collection::before{
            content: "\e60c";
        }
    </style>
</head>
<body>
    <p class="iconfont icon-email-fill"></p>
    <p class="iconfont">&#xe77e;</p>
    <icon-message></icon-message>
    <hr>
    <div id="app">
        <h4>渲染自定义标签指定的图标</h4>
        <p class="iconfont icon-email-fill"></p>
        <p class="iconfont">&#xe77e;</p>
        <icon-message></icon-message>
        <icon-set></icon-set>
        <collection></collection>
    </div>

    <script type="module">
        import { createApp } from "../../assets/vue/3.0/vue.esm-browser.js";
        const customTags = ["icon-message","icon-set","collection"]

        const app = createApp({
            data(){
                return {
                
                }
            }
        })
        
        // 通过扩展自定义组件标签的判断逻辑,描述那些自定义标签不是组件
        app.config.compilerOptions.isCustomElement = function(tag){
            // tag 参数 为程序运行时所有自定义标签的名称
            console.log(tag);
            // 通过返回 true 表示标签为自定义标签
            // 通过返回 false 表示标签为组件标签
            // return tag=="icon-message"
            // return tag.startsWith("icon-")
            return customTags.includes(tag);
        }
        
        app.mount("#app")
    </script>

插件开发

为统一 Vue扩展和全局配置语法,方便代码管理维护,为项目功能分解为模块化提供操作依据, Vue提供统一的插件配置管理
应用 API app.use(plugin,options)
插件是自包含的代码,通常向 Vue 添加全局级功能。它可以是公开 install() 方法的 object 对象参数,也可以是 公开的 function 方法

 + 参数

                - plugin : Object|Function

                            Object = { install:function(app [,options] ){} }

                            Function = function(app [,options] ){}

                    * 方法对应的第一个参数app为调用时的应用对象(createApp构建对象)

                    * options 在插件加载过程中提供额外的配置参数

  • 插件定义
// plugins 定义
export default {
install : function ( app , options ){
/*
app: 当前安装插件的 Vue 应用程序实例对象,通过该对象可以扩展全局配置
等相关功能
options: 当前安装插件时提供的额外参数数据
*/
console . log ( "app:" , app );
console . log ( "options:" , options );
}
}
// 或者
export default function ( app , options ){
console . log ( "app:" , app );
console . log ( "options:" , options );
}
  • 插件应用
<script type = "module" >
// 插件模式需要依赖 ES6 模块语法
import { createApp } from "../js/vue.esm-browser.js" ;
import plugins from " 插件定义文件 " ;
createApp ({
})
// 先安装插件
. use ( plugins ,{ msg : " 参数 " })
// 再挂载应用
. mount ( "#app" );
</script>

局部组件

<body>
    <div id="app">

    </div>

    <script type="module">
        import { createApp } from "../../assets/vue/3.0/vue.esm-browser.js";
        const app = createApp({
            data(){
                return {
                
                }
            }
        })
        // 插件1
        let plugin1 = {
            install:function(app,opt){
                console.log("插件1:",app,opt);
            }
        }
        app.use(plugin1,"额外参数")
        // 插件2
        let plugin2 = function(app,opt){
            console.log("插件2:",app,opt);
        }
        app.use(plugin2,{
            name:"额外参数"
        })
        app.mount("#app")
    </script>

全局组件

 <link rel="stylesheet" href="../../assets/font/iconfont.css">
    <style>
        body{
            padding-bottom: 800px;
        }
        .iconfont{
            font-size: 30px;
        }
        icon-message,icon-set,collection{
            font-family: "iconfont" !important;
            font-size: 30px;
        }
        icon-message::before{
            content: "\e77e";
        }
        icon-set::before{
            content: "\e78e";
        }
        collection::before{
            content: "\e60c";
        }
    </style>
</head>
<body>
    <div id="app">
        <p>{{ $ajaxBase }}</p>
        <input type="button" value="全局方法" @click="$replaceStar()">
        <br>
        <icon-message></icon-message>
        <br>
        <p v-test>全局指令</p>
        <br>
        <comp-a></comp-a>
    </div>

    <script type="module">
        import { createApp } from "../../assets/vue/3.0/vue.esm-browser.js";
        import pluginA from "./plugins/pluginA.js"
        import directives from "./plugins/directives.js"
        import components from "./plugins/components.js"

        // const app = createApp({
        //     data(){
        //         return {
                
        //         }
        //     }
        // })
        // app.use(pluginA,["icon-message"])
        // app.mount("#app")

        // vue3借鉴了Jquery的链式语法规则
        createApp({
            data(){
                return {
                
                }
            }
        }).use(pluginA,["icon-message"])
          .use(directives)
          .use(components)
          .mount("#app")
    </script>

组件数据传递和共享

页面组件关系结构, 类似于 HTML 的结构树,存在父子关系,因此组件间的数据传递共享存在 => 子、子 => 父和非父子关系组件数据传递
  1. 父组件向子组件数据传递

  • 技术实现:属性绑定,数据拦截
  • 详细描述:==以属性绑定的方式将传递的数据绑定在子组件标签上,在子组件对象中 以属性 props 方式进行 绑定属性的拦截==
 

<!--

            技术实现:属性绑定,数据拦截

                    + 属性绑定:将当前组件范围的数据变量,以自定义标签属性的方式进行 v-bind 操作

                               子组件标签在被解析成组件的时候,会被vue完成组件标签和标签属性的内容加载

                               而组件标签上如果存在定义的属性,被解析时这些属性会被自动存储于标签对应组件的实例属性 $attrs 上

                    + 数据拦截:通过props配置定义,可以将$attrs中接收的绑定属性变量进行提取并删除$attrs的记录,

                              同时构建具有响应式功能的 只读数据仓库 props,该数据仓库变量除只读特性外,其它功能等效于 data

            详细描述:以属性绑定的方式将传递的数据绑定在子组件标签上,在子组件对象中以属性 props 方式进行 绑定属性的拦截

           

            开发习惯:在vue组件化开发时,组件是先完成定义,后进行加载调用的,需要提供的页面变量在定义时就已经确定了,

                      为确保代码阅读是不产生障碍,多数情况下简单数据传递都会以接收变量(拦截定义的名称)为准

           

            组件标签使用的注意事项:对于vue组件标签而言,无论是通过v-bind完成的属性定义,还是直接属性的属性描述都属于组件标签的属性绑定

                    + 动态属性绑定 => 属性取值的数据类型取决于变量本身

                    + 静态属性绑定 => 属性取值只可能是 String 类型

           

        -->

   .box{
            margin: 10px;
            border: 1px solid #999;
            min-height: 100px;
            padding: 10px;
        }
    </style>
</head>
<body>
    <div id="app">
        <h4>父组件</h4>
        <p>msg:{{ msg }}</p>
        <input type="text" v-model="msg">
        <!-- <p v-bind:info="msg"></p> -->
        <comp-a 
            v-bind:info="msg"
            :num="num"
            :arr="arr"
            :user="user"
            text="测试组件属性的静态绑定"
            :flag="false"
        ></comp-a>
        <hr>
        <!-- <comp-a 
            v-bind:info="msg"
            :num="num1"
        ></comp-a> -->
    </div>

    <script type="text/x-template" id="compA">
        <div class="box">
            <h4>子组件-CompA</h4>
            <p>$attrs.info:{{ $attrs.info }}</p>
            <p>info:{{ info }}</p>
            <input type="text" v-model="info">
            <p>flag:{{ flag }}</p>
            <h5 v-show="flag">flag值为true显示</h5>
        </div>
    </script>

    <script type="module">
        import { createApp } from "../../assets/vue/3.0/vue.esm-browser.js";
        const app = createApp({
            data(){
                return {
                    msg:"父组件数据变量-msg",
                    num:10,
                    num1:11,
                    arr:[1,2,3,4],
                    user:{
                        name:"tom"
                    }
                }
            }
        })

        app.component("CompA",{
            template:"#compA",
            props:["info","num","arr","user","text","flag"],
            beforeCreate() {
                console.log("this.$attrs:",this.$attrs)
            },
            created() {
                console.log("this.$attrs:",this.$attrs)
            },
        })

        app.mount("#app")
    </script>

特殊属性处理和属性穿透

  <!--

        vue@2.7和vue@3 版本中,class、style可以被子组件props进行拦截,但这两个属性一旦被拦截,

                              定义的相关样式将无法为子组件提供样式服务和支持了

                              所有vue开发中如非特殊需要不建议对class和style进行props拦截

        在vue2.0 版本中,class和style默认是直接传递到组件根元素标签上进行绑定,因为vue2不允许组件出现多个根元素节点

        vue@2.7和vue@3 版本中 组件的模板结构中是允许出现多个根元素节点,在这种环境下class和style的属性穿透需要根据实际场景进行调整

            场景1:组件模板只有一个根节点,没有被props拦截的属性默认会直接将$attrs中记录的属性绑定于组件根元素节点上

            场景2:组件模板存在多个根元素节点,需要开发者通过 v-bind="$attrs" 方式,显示描述绑定规则,否则程序提出警告

        -->

 <style>
        body {
            padding-bottom: 800px;
        }

        .fc {
            color: red;
        }

        .box {
            margin: 10px;
            border: 1px solid #999;
            min-height: 100px;
            padding: 10px;
        }
    </style>
</head>

<body>
    <div id="app">
        <h4>父组件</h4>
        <comp-a :class=" classStr " a="aaaa"></comp-a>
        <br>
        <comp-a style="color:blue;"></comp-a>
    </div>

    <script type="text/x-template" id="compA">
        <!-- 
            vue2 组件模板定义时必须严格保证有且仅有一个根元素 
            vue3 没有这项要求
        -->
        <!-- <div class="box">
            <h4>子组件-CompA</h4>
        </div> -->
        <div class="box">
            <h4>子组件-CompA-1</h4>
        </div>
        <div class="box" v-bind="$attrs">
            <h4>子组件-CompA-2</h4>
        </div>
    </script>

    <script type="module">
        import { createApp } from "../../assets/vue/3.0/vue.esm-browser.js";
        const app = createApp({
            data(){
                return {
                   classStr:"fc"
                }
            }
        })

        app.component("CompA",{
            template:"#compA",
            // props:["class","style"]
            props:["a"]
        })

        app.mount("#app")

props的数据校验

 /*

            props 的数据校验不是给用户提供错误提示的

            props 的数据校验是为开发者提供 合理数据 判断

            所以通过props的对象取值方案,就可以实现数据传入组件时,完成必要数据校验,以提供调用提示

                props:{

                    key:value,

                    ……

                }

                    + key 被拦截的属性名

                    + value 构造函数|Object对象配置

                        -> 构造函数 = 描述当前拦截的属性只能接收某种数据类型的值或者某几种数据类型的值

                        -> Object对象配置 =

            */

 <style>
        body {
            padding-bottom: 800px;
        }

        .box {
            margin: 10px;
            border: 1px solid #999;
            min-height: 100px;
            padding: 10px;
        }
    </style>
</head>

<body>
    <div id="app">
        <h4>父组件</h4>
        <p>num:{{ num}} - {{ typeof(num) }}</p>
        <comp-a :source="num" :msg=" info "></comp-a>
    </div>

    <script type="text/x-template" id="compA">
        <div class="box">
            <h4>子组件-CompA</h4>
            <p>评分:{{ source.toFixed(1) }}</p>
            <p>msg:{{ msg }}</p>
        </div>
    </script>

    <script type="module">
        import { createApp } from "../../assets/vue/3.0/vue.esm-browser.js";
        const app = createApp({
            data(){
                return {
                    num:8,
                    // num:"7",

                    // info:"测试类型"
                    // info:100
                    // info:false
                    info:[1,2,3]
                }
            }
        })

        app.component("CompA",{
            template:"#compA",
            //    props:["source"]
            props:{
                source:Number,
                msg:[String,Number,Boolean]
            }
        })

        app.mount("#app")

    </script>

本文含有隐藏内容,请 开通VIP 后查看