- 取值:(tag: string) => boolean
-
用法:
const app = Vue . createApp ({ /* ... */ }). mount ( "#app" );app . config . compilerOptions . isCustomElement = tag =>tag . startsWith ( 'ion-' );
<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"></p>
<icon-message></icon-message>
<hr>
<div id="app">
<h4>渲染自定义标签指定的图标</h4>
<p class="iconfont icon-email-fill"></p>
<p class="iconfont"></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>
插件开发
+ 参数
- 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>
组件数据传递和共享
父组件向子组件数据传递
- 技术实现:属性绑定,数据拦截
- 详细描述:==以属性绑定的方式将传递的数据绑定在子组件标签上,在子组件对象中 以属性 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>