其他章节请看:

vue 快速入门 系列

vue 的基础应用(下)

上篇聚焦于基础知识的介绍;本篇聚焦于基础知识的应用

递归组件

组件是可以在它们自己的模板中调用自身的。不过它们只能通过 name 选项来做这件事。我们实现一个自定义树的组件。请看示例:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src='vue.js'></script>
</head>
<body>
<div id='app'>
<custom-tree :list='treeData'></custom-tree>
</div> <script>
// 递归组件 - 自定义树
Vue.component('custom-tree', {
// 给组件命名
name: 'custom-tree', // {1}
props: ['list'],
template: `
<ul>
<li v-for='item in list'>
{{item.name}}
<!-- v-if 指定退出的条件,防止无线递归 -->
<custom-tree
:list='item.children'
v-if='item.children'
></custom-tree>
</li>
</ul>
`
})
const app = new Vue({
el: '#app',
// 数据也需要符合递归的条件
data: {
treeData: [ // {2}
{
name: 'a',
children: [
{
name: 'b'
},
{
name: 'c'
}
]
},
{
name: 'd',
children: [
{
name: 'e',
children: [
{
name: 'f'
},
{
name: 'g'
}
]
}
]
}
]
}
})
</script>
</body>
</html>
// 页面输出:
a
b
c
d
e
f
g

有3点需要注意:

  • 给组件设置 name (行{1})
  • 使用一个条件来结束无限递归。这里使用了 v-if
  • 数据得满足递归(行{2})

Tip: 后续不在提供完整的代码,省略 head、body 等。

动态组件

vue 提供了 <component> 来动态的挂载组件。请看示例:

<div id='app'>
<!-- vue 提供了 <component> 来动态的挂载组件 -->
<component v-bind:is="currentComponent"></component>
<button @click='switchHandle'>切换组件</button>
</div> <script>
var comC = {
template: `<p>我是组件 C</p>`
}; var app = new Vue({
el: '#app',
data: {
currentComponent: 'comB'
},
// 局部注册。components 选项中定义你想要使用的组件
components: {
comA: {
template: `<p>我是组件 A</p>`
},
comB: {
template: `<p>我是组件 B</p>`
},
comC: comC
},
methods: {
switchHandle: function(){
let map = {
'comA': 'comB',
'comB': 'comC',
'comC': 'comA'
};
// 动态切换组件
this.currentComponent = map[this.currentComponent]
}
}
})
</script>
// 页面输出:
我是组件 A 切换组件 // 点击按钮(‘切换组件’),依次显示'我是组件 B'、'我是组件 C'...

内置的组件 component 根据属性 is 的值来决定哪个组件被渲染。

nextTick

Vue.nextTick( [callback, context] )

用法

在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。—— 不明白的化,请看示例:

  <div id="example">{{message}}</div>

  <script>
var vm = new Vue({
el: '#example',
data: {
message: '123'
}
})
vm.message = 'new message' // 更改数据 // {20}
console.log(vm.$el.textContent === 'new message') // false {21}
Vue.nextTick(function () {
console.log(vm.$el.textContent === 'new message') // true {22}
})
</script>

更改数据后(行{20},dom 元素中的内容其实没有得到更新,输出 false(行{21});在 Vue.nextTick() 方法中才被更新,输出 true(行{22})。

这里涉及到 vue 中一个概念:异步更新

假如在更改状态(行{20})后,dom 元素立马得到更新(行{21}),也就是输入出 true,那么用户使用 for 循环改变某个状态 100 次,dom 元素就得更新 100 次,是否觉得浪费!所以 vue 的策略是:使用异步更新,也就是不会马上更新 dom。

手动挂载

vm.$mount( [elementOrSelector] )

用法

如果 Vue 实例在实例化时没有收到 el 选项,则它处于“未挂载”状态。我们可以使用 vm.$mount() 方法手动。

我们创建一个组件,三秒后再挂载它。请看示例:

<div id="app"></div>

<script>
// Vue.extend() 使用基础 Vue 构造器,创建一个“子类”
var MyComponent = Vue.extend({
template: '<div>Hello!</div>'
}) // 创建并挂载到 #app (会替换 #app)
setTimeout(function(){
// 3 秒后页面上才会看见 Hello!
new MyComponent().$mount('#app')
}, 3000)
</script>

3 秒后,页面上才会看见 Hello!

数字输入框组件

需求:数字输入框只能输入数字,有两个按钮,分别是减1和加1。此外还可以设置初始值、最大值、最小值,数字改变时通知父组件。

请看完整代码:

<div id='app'>
父组件 value = {{value}}
<!-- v-model 实现双向绑定 -->
<custom-number
v-model='value'
:max-value='maxValue'
:min-value='minValue'
:step='10'
></custom-number>
</div> <script>
Vue.component('custom-number', {
props:{
// 必须是一个数字
value: {
type: Number,
default: 0
},
maxValue: {
type: Number,
// 正无穷大
default: Number.POSITIVE_INFINITY
},
minValue: {
type: Number,
// 负无穷大
default: Number.NEGATIVE_INFINITY
},
// 默认加减 1
step: {
type: Number,
default: 1
}
},
data: function(){
return {
inputValue: this.value
}
},
created: function(){
// 处理:初始值不在最大值和最小值的范围内
this.update(this.value)
},
computed: {
// 减(-)不可点
minIsDisabled: function(){
return this.inputValue <= this.minValue
},
maxIsDisabled: function(){
return this.inputValue >= this.maxValue
}
},
watch: {
// 监听 inputValue,通知父组件
inputValue: function(val, oldVal){
this.$emit('input', val)
},
// 父组件改变值,子组件的值也跟着改变
value: function(val){
this.update(val);
}
},
template: `
<div>
<button :disabled="minIsDisabled" @click='minus'> - </button>
<input :value='inputValue' @change='changeHandle' >
<button :disabled="maxIsDisabled" @click='add'> + </button>
<p>
子组件 inputValue = {{inputValue}}
</p>
</div>
`,
methods: {
// 如果输入值不是数字,则不会更改值
changeHandle: function(e){
var val = e.target.value;
this.update(val, e.target)
},
// obj 是否是数字。摘自 jquery
isNumeric: function(obj) {
return !isNaN( parseFloat(obj) ) && isFinite( obj );
},
minus: function(){
this.update(this.inputValue - this.step);
},
add: function(){
this.update(this.inputValue + this.step);
},
// 是数字才更新
update: function(val, target={}){
if(!this.isNumeric(val)){
// 将 input 值置为上次的值
target.value = this.inputValue;
return;
}
val = Number(val);
// 大于最大值,则重置为最大值
if (val > this.maxValue){
val = this.maxValue
}else if(val < this.minValue){
val = this.minValue
}
this.inputValue = val;
}
}
}); var app = new Vue({
el: '#app',
data: {
value: 10,
maxValue: 100,
minValue: 1
}
})
</script>
// 页面输出:
父组件 value = 10
- 10 +
子组件 inputValue = 10 // 点击 +(每次加减10)
父组件 value = 20
- 20 +
子组件 inputValue = 20 // 继续点击2次
// 减号(-)变为不可点
父组件 value = 1
- 1 +
子组件 inputValue = 1

Tabs 标签页

需求:实现一个常用的组件 —— tabs 标签页。

:不明白需求的可以看element-ui-tabs

思路:

  • 定义组件 el-tabs
  • 定义 el-tabs 的子组件 tab-pane
  • 父子组件通信使用 vm.$parent 和 vm.$children

请看完整代码:

<style>
ul{margin:0;padding: 0;border-bottom: 1px solid;margin-bottom: 10px;}
li{display:inline-block;margin-right:10px;cursor:pointer;}
.active{color:#409eff;}
</style> <div id='app'>
<el-tabs v-model="activeKey">
<el-tab-pane label="用户管理">
用户管理内容
<p>我是 A</p>
</el-tab-pane>
<el-tab-pane label="配置管理" name="second">配置管理内容</el-tab-pane>
<el-tab-pane label="角色管理">
角色管理内容
<p>我是 C</p>
</el-tab-pane>
<el-tab-pane label="定时任务补偿" name="fourth">定时任务补偿内容</el-tab-pane>
</el-tabs>
</div> <script>
// 父组件
Vue.component('el-tabs', {
props:{
value:{
type: [String, Number]
}
},
data: function(){
return {
currentTab: this.value,
// 存放 tab
tabLists: []
}
},
watch: {
currentTab: function(){
this.updateStatus();
},
// 处理:父组件更改 value
value: function(val, oldVal){
this.currentTab = val
}
},
template: `
<div>
<ul>
<li
v-for='(item, index) in tabLists'
:class='{active: item.name === currentTab}'
@click='handleClick(index)'
>{{item.label}}</li>
</ul>
<slot></slot>
</div>
`,
methods: {
// 取得 tab-pane
getTabPanes: function(){
return this.$children.filter(item => {
return item.$options.name === 'tab-pane'
})
},
// 更新 tabLists
updateTabLists: function(){
let tabLists = [];
this.getTabPanes().forEach((item, index) => {
if(!item.id){
item.id = index
}
tabLists.push({
label: item.label,
name: item.id
}) // 默认展示第一个
if(index === 0){
if(!this.currentTab){
this.currentTab = item.id;
}
}
})
this.tabLists = tabLists;
this.updateStatus()
},
handleClick: function(index){
this.currentTab = this.tabLists[index].name;
console.log(`name = ${this.currentTab}`)
this.updateStatus()
},
// 让子组件显示或隐藏
updateStatus: function(){
this.getTabPanes().forEach(item => {
item.updateShow(this.currentTab === item.id)
})
}
}
}); // 子组件
Vue.component('el-tab-pane', {
name: 'tab-pane',
props: {
// 标签标题
label:{
type: String,
default: ''
},
// pane 的名字,不必填
name: [String, Number]
},
data: function(){
return {
// 显示与否,由父组件决定
show: false,
// 不允许通过父组件更改 props 中的属性 name
// 用 id 来替代 name 属性
id: this.name
}
},
created: function(){
this.$parent.updateTabLists();
},
template: `
<div v-if='show'>
<slot></slot>
</div>
`,
methods: {
updateShow: function(v){
this.show = v;
}
}
}); const app = new Vue({
el: '#app',
data: {
// 当前选中的 tab
activeKey: 2
}
})
</script>
// 页面输出:
// 第一行是 4 个 tab,现在是`角色管理`被选中
用户管理 配置管理 角色管理 定时任务补偿 角色管理内容 我是 C

其他章节请看:

vue 快速入门 系列

vue 快速入门 系列 —— vue 的基础应用(下)的更多相关文章

  1. vue 快速入门 系列 —— vue 的基础应用(上)

    其他章节请看: vue 快速入门 系列 vue 的基础应用(上) Tip: vue 的基础应用分上下两篇,上篇是基础,下篇是应用. 在初步认识 vue一文中,我们已经写了一个 vue 的 hello- ...

  2. vue 快速入门 系列 —— vue loader 扩展

    其他章节请看: vue 快速入门 系列 vue loader 扩展 在vue loader一文中,我们学会了从零搭建一个简单的,用于单文件组件开发的脚手架.本篇将在此基础上继续引入一些常用的库:vue ...

  3. vue 快速入门 系列 —— vue loader 上

    其他章节请看: vue 快速入门 系列 vue loader 上 通过前面"webpack 系列"的学习,我们知道如何用 webpack 实现一个不成熟的脚手架,比如提供开发环境和 ...

  4. vue 快速入门 系列 —— vue loader 下

    其他章节请看: vue 快速入门 系列 vue loader 下 CSS Modules CSS Modules 是一个流行的,用于模块化和组合 CSS 的系统.vue-loader 提供了与 CSS ...

  5. vue 快速入门 系列 —— Vue(自身) 项目结构

    其他章节请看: vue 快速入门 系列 Vue(自身) 项目结构 前面我们已经陆续研究了 vue 的核心原理:数据侦测.模板和虚拟 DOM,都是偏底层的.本篇将和大家一起来看一下 vue 自身这个项目 ...

  6. vue 快速入门 系列 —— Vue 实例的初始化过程

    其他章节请看: vue 快速入门 系列 Vue 实例的初始化过程 书接上文,每次调用 new Vue() 都会执行 Vue.prototype._init() 方法.倘若你看过 jQuery 的源码, ...

  7. vue 快速入门 系列 —— vue-cli 上

    其他章节请看: vue 快速入门 系列 Vue CLI 4.x 上 在 vue loader 一文中我们已经学会从零搭建一个简单的,用于单文件组件开发的脚手架:本篇,我们将全面学习 vue-cli 这 ...

  8. vue 快速入门 系列 —— vue-cli 下

    其他章节请看: vue 快速入门 系列 Vue CLI 4.x 下 在 vue loader 一文中我们已经学会从零搭建一个简单的,用于单文件组件开发的脚手架:本篇,我们将全面学习 vue-cli 这 ...

  9. vue 快速入门 系列 —— vue-router

    其他章节请看: vue 快速入门 系列 Vue Router Vue Router 是 Vue.js 官方的路由管理器.它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌. 什么是路由 ...

随机推荐

  1. CNN专访灵石CTO:Baccarat流动性挖矿能否持续?

    近日,CNN记者Robert独家专访Baccarat的项目团队CTO STEPHEN LITAN,跟他特别聊了聊DeFi的近况. 以下是专访全文: Robert:推出Baccarat的契机是什么? S ...

  2. WPF权限控制——【3】数据库、自定义弹窗、表单验证

    你相信"物竞天择,适者生存"这样的学说吗?但是我们今天却在提倡"尊老爱幼,救死扶伤",帮助并救护弱势群体:第二次世界大战期间,希特勒认为自己是优等民族,劣势民族 ...

  3. django学习-17.如何提供一个规范的接口返回值

    目录结构 1.前言 2.进行实际的一个完整流程操作 2.1.第一步:编写一个用于查询用户数据的视图函数 2.2.第二步:编写对应的一个url匹配规则 2.3.第三步:启动django项目[hellow ...

  4. ATP - UI 自动化测试用例管理平台搭建

    用到的工具:python3 + django2 + mysql + RabbitMQ + celery + selenium python3和selenium这个网上很多教程,我不在这一一说明:   ...

  5. POJ-3159(差分约束+Dijikstra算法+Vector优化+向前星优化+java快速输入输出)

    Candies POJ-3159 这里是图论的一个应用,也就是差分约束.通过差分约束变换出一个图,再使用Dijikstra算法的链表优化形式而不是vector形式(否则超时). #include< ...

  6. golang-Zap和Go Logger日志库

    目录 在Go语言项目中使用Zap日志库 介绍 默认的Go Logger日志库 实现Go Logger 设置Logger 使用Logger Logger的运行 Go Logger的优势和劣势 优势 劣势 ...

  7. Tomcat8弱口令+后台getshell

    漏洞原因 用户权限在conf/tomcat-users.xml文件中配置: <?xml version="1.0" encoding="UTF-8"?&g ...

  8. &#128681;数分工作了三年,我干了件很酷的事情

    从17年毕业来,一直都在干数据分析的工作.和很多转行的小伙伴一样,没有对口的科班学习,摸不清数据分析具体情况,起初充满着很多迷茫. 在刚开始的1年半中,都是自己从淘宝买些课程,最多时,网盘放了4-5T ...

  9. .Net Core 2.1 升级3.1 问题整理

    随着技术的不断拓展更新,我们所使用的技术也在不断地升级优化,项目的框架也在不断地升级,本次讲解 .net core 2.1  升级到3.1所需要注意的事项: 当项目框架升级后,所有的Nuget引用也会 ...

  10. 用实战玩转pandas数据分析(一)——用户消费行为分析(python)

      CD商品订单数据的分析总结.根据订单数据(用户的消费记录),从时间维度和用户维度,分析该网站用户的消费行为.通过此案例,总结订单数据的一些共性,能通过用户的消费记录挖掘出对业务有用的信息.对其他产 ...