梅州建站规划,微站和网站数据同步,线上卖护肤品营销方法,怎么做购物网站系统文本自定义组件
组件是可复用的 Vue 实例#xff0c;在开发过程中#xff0c;我们可以把重复用到的功能封装成自定义组件#xff0c;达到便捷开发的目的。
组件的组织
通常一个应用会以一棵嵌套的组件树的形式来组织#xff1a; 你可能会有头部导航、内容区、侧边栏等组件在开发过程中我们可以把重复用到的功能封装成自定义组件达到便捷开发的目的。
组件的组织
通常一个应用会以一棵嵌套的组件树的形式来组织 你可能会有头部导航、内容区、侧边栏等组件每个组件内部又包含了导航链接、博文之类的组件。
为了能在模板 template 中使用这些组件必须先注册以便 Vue 能够识别。
组件的注册
在 Vue 中组件的注册分全局注册和局部注册两种
全局注册用 Vue.component 来创建组件注册之后可以在任何新创建的 Vue 根实例中使用局部注册在单个 Vue 格式的文件中创建组件在需要用到的地方进行注册
但通常我们都是基于 Vue 工程进行开发的会用到 webpack 这样的构建系统而通过全局注册的组件在构建系统中即使没被使用依然会存在于构建结果中所以我们通常选择局部注册。
组件的创建
每个 Vue 格式的文件都可以作为一个组件来使用。
组件的局部注册
首先我们需要有一个 Vue 格式的文件
在通过 vue-cli 创建的 vue 工程中默认存在一个组件 HelloWorld.vue 这个文件中有些基础内容由于内容过多我们进行了删减留下了一个标题和一个段落我们可以在文件中指定组件名称 注意 template 里的根元素只有一个。 将其作为组件在 App.vue 中使用组件可以重复使用 小结一下
组件的局部注册需要
一个组件文件 HelloWorld在需要使用组件 HelloWorld 的 vue 文件 App 中引入组件 HelloWorld在 App 的 components 中注册组件 HelloWorld在 App 的 template 中使用组件
当组件树形成时组件间就有了层级关系像上面这样的组件使用中App.vue 就是父组件而在它内部使用的 HelloWorld 就是子组件。
组件中的数据
自定义组件内的数据 data 必须是一个函数
data: function () {return {count: 0}
}重复使用的组件间的 data 是相互独立的。这一点是很重要的现在不理解没关系我们在之后会再次遇到这种情况的。
组件单向数据流
在上一节中的作业里由于组件 HelloVue 中 data 里的数据 str 是固定的所以页面上显示的时候内容就是一样的 而实际开发中复用的组件里显示的内容往往是不同的比如下面的图片中显示的每个文章介绍其实用的是一个组件但是每个介绍的内容却是不同的这就需要从父组件中传递不同的内容给子组件。 那么如何从父组件中把内容传给子组件呢
prop 的使用方法
基础使用
当父组件给子组件的 prop 传递一个值的时候这个值就变成了子组件实例的一个属性。
现在我们给 HelloVue 组件传递一个标题
父组件中传一个 title 给子组件
templatediv idapp!-- 注意title1 和 title2 是父组件的 data 中定义的数据title 则是子组件中接收数据时的变量名 --HelloVue :titletitle1/HelloVueHelloVue :titletitle2/HelloVue/div
/template有两点需要大家注意一下
title1 和 title2 是父组件的 data 中定义的数据而 title 则是子组件中接收数据时的变量名因为 title1 和 title2 是变量所以 title 前需要加 :
如果不加 :那么在子组件中收到的 title 值就是 “title1” 和 “title2”。
子组件中用 prop 接收 title
templatediv classhello!-- 第二步在页面上显示 title 的值写法和显示 data 里定义的数据一样 --h1{{ title }}/h1/div
/templatescriptexport default {name: HelloVue,// 第一步在 prop 属性中接收 titleprops: [title]};
/script注意在子组件中 prop 属性的写法因为传过来的值可能不止一个因此这里是个数组其中的每一项均为传过来的值的名称。
上面这种写法没有声明所传值的类型如果要声明类型可以参看进阶使用方法。
进阶使用附带类型声明
我们可以用下面的写法给值声明类型类型首字母要大写哦
scriptexport default {name: HelloVue,// 在 prop 属性中接收 title其类型为 Stringprops: {title: String}};
/script这里 prop 是一个对象当传入的值有多个的时候可以用逗号隔开我们还可以用下面的写法给值设置一些要求
props: {title: String,// 多类型likes: [String, Number],// 带有默认值isPublished: {type: Boolean,default: true},// 必填commentIds: {type: Array,required: true},author: Object,callback: Function,contactsPromise: Promise
}从上面的示例中我们知道了怎么通过 prop 实现父到子的数据传递那么能不能用 prop 实现子到父的数据传递呢
答案是不能。现在我们就来解释一下什么叫“单向数据流”。
单向数据流
单向数据流指的是父子 prop 之间形成了一个单向下行绑定父级 prop 的更新会向下流动到子组件中但是反过来则不行。
这样可以防止从子组件意外改变父级组件的状态从而导致你的应用的数据流向难以理解。
简单来说
prop 可以实现父到子的数据传递父组件中的数据变化会通过 prop 传递到子组件子组件不能直接修改父组件通过 prop 传递过来的数据
但实际开发中常会遇到传到子组件中的数据需要处理后才能使用的情况比如排序、格式化等这时候怎么办呢
1. prop 传入的数据需要处理
这时我们就可以用前面提到的计算属性对数据进行处理
props: [initialTitle],
computed: {normalizedTitle: function () {// 对传入的 initialTitle 进行去空格、字母小写化处理return this.initialTitle.trim().toLowerCase()}
}2. prop 传入的数据作为本地数据使用
如果想将 prop 传递的初始值作为一个本地数据使用可以定义一个本地的 data 属性并将这个 prop 用作其初始值
props: [initialTitle],
data: function () {return {// 要读取 prop 里的 initialTitle要在前面加 “this.”// 将传入的 initialTitle 作为本地属性 title 的初始值title: this.initialTitle}
}接下来可以直接修改 title而不必改变父组件的 initialTitle。 在某些情况下我们还可以通过自定义事件调用父组件中定义的方法在父组件中修改数据然后让数据的更新自动向下流动到子组件中。“自定义事件”这个概念我们会在后面的章节进行讲解。 文章列表的实现
现在我们来尝试做上面的文章列表完成后是这样的 注意这里我们从父组件 App.vue 传到子组件 Article.vue 里的是一个对象 article
Articlev-forarticle in articleList:keyarticle.title:articlearticle
/Articlearticle 是 App.vue 中的 data 数据 articleList 中的一项。
在子组件 Article.vue 中使用 article 数据时通过计算属性对时间和文章内容做了处理注意这种做法并不是直接改变 article 的内容
computed: {formatTime: function() {if (this.article) {const dt new Date(this.article.time)const month dt.getMonth()const date dt.getDate()return ${month}月${date}日}return ;},brief: function() {return this.article (this.article.content.substr(0, 35) ...) || }
}自定义组件绑定原生事件
事件修饰符
在自定义组件Article.vue的根元素上监听一个原生事件和在 html 原生标签上监听一个原生事件是有区别的请看下面的例子
App.vue 中
!-- 给自定义组件添加点击事件 print --
Articlev-forarticle in articleList:keyarticle.title:articlearticleclickprint(article)
/ArticleArticle.vue 中
div classarticle-title clickprintTitle{{ article article.title }}/div
// 在 methods 对象中定义方法
methods: {printTitle() {alert(cilcked a title);}
}现在试着点击一下文章列表的标题部分从控制台中的打印结果可以看出只有子组件中的点击事件被执行了。
即使点击的是标题以外的部分父组件中的点击事件 print 也不会被执行。
那么如何让父组件里的 print 也能被执行呢这时候我们就需要用到 Vue 中的修饰符了。
修饰符是由点开头的指令后缀来表示的在前面的课程中我们已经接触过了 .prevent、.capture 等常用修饰符。
现在要让父组件里的 print 也能被执行我们可以这样添加 .native 修饰符
Articlev-forarticle in articleList:keyarticle.title:articlearticleclick.nativeprint(article)
/Article大家手动给 App.vue 中的 clickprint(article) 添加 .native 修饰符后再试着点击标题部分。
观察一下控制台中的输出可以看到这时候print 和 printTitle 都执行了。
除了事件修饰符Vue 还提供了按键修饰符用来监听键盘事件。
按键修饰符
这里我们主要讲一下回车键监听。
现在我们把 App.vue 中的 print 事件改成发生回车事件时执行
button keyup.enterprint(article)按回车键执行 print/button代码播放完毕后先点击按钮让它聚焦然后按回车键查看控制台的输出。可以看到 print 方法执行了。
因为回车键enter 键的 ASCII 码是 13所以也可以这样写
button keyup.13print(article)按回车键执行 print/button其他按键的监听大同小异这里就不赘述了。
自定义事件
上节课的作业中我们通过 App.vue 中的 handleLikes 方法来处理文章的点赞行为。
这个方法定义在 App.vue 中改变的也是 App.vue 中定义的 articleList 数据这样是没有问题的。
但是通常我们会在子组件 Article.vue 里写点赞按钮像这样 但是之前我们提到过我们不能在子组件中直接修改父组件传来的 prop 数据。
如果想要修改父组件中的原数据要怎么办呢
这里我们可以通过自定义事件来完成这个任务。
自定义事件
现在我们用自定义事件 “upVote” 来实现点赞功能。
给子组件 Article.vue 绑定自定义事件
在 App.vue 中用 v-on:upVotehandleLikes 给 Article.vue 绑定自定义事件
!-- 自定义事件 upVote调用该事件时会执行 handleLikes 方法 --
articlev-forarticle in articleList:keyarticle.title:articlearticlev-on:upVotehandleLikes
/article“upVote” 是我们给自定义事件取的事件名就像点击事件叫 “click” 一样。比较一下点击事件 v-on:click; 自定义事件 v-on:upVote; 在 Article.vue 中调用自定义事件 “upVote”
!-- 在 template 中直接调用自定义事件 upVote --
button click$emit(upVote)点赞/button如果在点赞的同时还有其他要执行的代码可以这样写
button clickchildEvent点赞/button
methods: {childEvent: function() {// 调用自定义事件 upVotethis.$emit(upVote);// do other things}
}特别注意这里出现了三个名称
handleLikes父组件中修改点赞数的方法upVote自定义事件名childEvent子组件中的按钮点击时调用的方法。
自定义事件的参数
prop 可以完成父组件到子组件的数据传递自定义事件则可以帮我们完成子组件到父组件的数据传递。
下面我们就通过自定义事件的参数把数据从子组件传到父组件
父组件 App.vue 中
!-- 自定义事件 upVote调用该事件时会执行 handleLikes 方法 --
!-- 注意我们接下来会在子组件里给 handleLikes 传参数 --
articlev-forarticle in articleList:keyarticle.title:articlearticlev-on:upVotehandleLikes
/article
// 在 methods 对象中定义方法
methods: {handleLikes(article) {article.likes}
}注意虽然这里 handleLikes 方法需要传入参数 article但v-on:upVotehandleLikes 没有传入参数 article。
在子组件 Article.vue 中调用自定义事件 “upVote” 时会把参数传入
button clickchildEvent点赞/button
methods: {childEvent: function() {// 调用自定义事件 upVote这里的第二个参数最后会传到父组件中的 handleLikes 方法里this.$emit(upVote, this.article);// do other things}
}$emit 的第一个参数是自定义事件的名称它还可以有第二个、第三个参数甚至更多的参数这些参数最终会成为自定义事件对应的那个方法的参数。
小结一下自定义事件可以
在子组件中调用父组件的方法把子组件的数据通过自定义事件参数的形式传给父组件
自定义事件中的双向绑定
之前讲过 v-model 可以实现双向绑定如果是自定义组件如何实现双向绑定呢
这里我们要用到修饰符 .sync。
父组件 App.vue 中用修饰符 .sync 完成 count 的双向绑定
MyCount classcount :count.synccount/MyCount
// 在 methods 对象中定义方法
data: function() {return {count: 0}
}子组件 MyCount.vue 中用 update:count 的模式触发事件把 count1 赋值给 count
div classmy-countbutton click$emit(update:count, count1)加一/button{{ count }}
/div
props: [count],虽然 count 是定义在 App.vue 里的但是通过双向绑定我们在子组件中改变 count 值App.vue 里的 count 值也会有相同的变化。
组件函数调用
除了用自定义组件双向绑定的方法完成弹框的显示和隐藏外我们还可以把 visible 直接写在子组件中通过在父组件里调用子组件方法的形式修改子组件中的 visible 的值完成弹框的显示和隐藏。
想要调用子组件中的方法其实就是访问子组件实例调用实例中的方法。
下面我们利用 Vue 提供的 ref 属性来访问子组件实例并调用子组件中的方法。
改写子组件 Modal.vue
首先我们需要修改一下子组件 Modal.vue 的写法 这个代码演示我们不运行请忽略运行报错大家看一下改写后的 Modal.vue 的写法即可。 调用子组件中的方法
接下来我们使用 ref 属性来访问子组件实例并调用子组件中的方法
1. 给要访问的子组件添加 ref 属性
templateModal refmodal/Modal
/template现在我们可以通过 this.$refs.modal 来访问自定义组件 Modal.vue。
2. 调用子组件中的方法
现在我们调用子组件中的 show 方法来改变子组件中的 visible 的值使弹框出现
script
export default {methods: {showModal() {// 调用子组件中的 show 方法this.$refs.modal.show();}}
};
/scriptref 访问子元素
ref 除了可以访问组件实例还可以访问子元素
templatediv idappinput refinput typetext /button clickfocusInput点击使输入框获取焦点/button/div
/template
script
export default {name: app,methods: {focusInput() {// this.$refs.input 访问输入框元素并调用 focus() 方法使其获取焦点this.$refs.input.focus();}}
}
/script实现效果
组件 slot 入门
slot 即插槽相当于在子组件的 DOM 中留一个位置父组件如果有需要就可以在插槽里添加内容。
插槽的基础使用
这节里我们会讲解插槽的简单用法。
在子组件 Modal.vue 中用 slot 标签预留一个位置slot 标签中的内容是后备内容也可以为空
div classmodal-contentslot这是个弹框/slotdiv classfooterbutton clickcloseclose/buttonbutton clickconfirmconfirm/button/div
/div后备内容当父组件不在插槽里添加内容时插槽显示的内容。 在父组件中使用子组件 在父组件中使用子组件但不向自定义组件的插槽 slot 中添加内容 Modal :visible.syncvisible/Modal此时如果打开弹框弹框中显示的是后备内容“这是个弹框” 在父组件中使用子组件并给插槽加入个性化内容 Modal :visible.syncvisible个性化内容/Modal组件 slot 进阶
有时我们需要多个插槽。例如对于一个带有如下模板的组件
div classmodal v-ifvisiblediv classmodal-contentheader!-- 我们希望把页头放这里 --/headermain!-- 我们希望把主要内容放这里 --/mainfooter!-- 我们希望把页脚放这里 --/footer/div
/div对于这样的情况slot 元素有一个特殊的属性name。这个属性可以用来定义额外的插槽
div classmodal v-ifvisiblediv classmodal-contentheaderslot nameheader/slot/headermainslot/slot/mainfooterslot namefooter/slot/footer/div
/div上节课中的插槽 slot 我们没有写 name 属性但其实它会自动带隐含的名字“default”也就是我们所说的“匿名插槽”。
而带有 name 属性的插槽我们称为“具名插槽”。
在向具名插槽提供内容的时候我们可以在一个 template 元素上使用 v-slot 指令并以 v-slot 的参数的形式提供其名称
Modal :visible.syncvisibletemplate v-slot:headerh1Modal title/h1/templatedivmain content/divdivmain content/divtemplate v-slot:footerpModal footer/p/template
/Modal