Vue小技巧

继承棱镜
• 阅读 130

给 props 属性设置多个类型这个技巧在开发组件的时候用的较多,为了更大的容错性考虑,同时代码也更加人性化:
[JavaScript] 纯文本查看 复制代码
?

export default {
props: {

width: {
  type: [String, Number],
  default: '100px'
}
// 或者这样
// width: [String, Number]

}
}

比如一个 <my-button> 上暴露了一个 width 属性,我们既可以传 100px,也可以传 100 :
[HTML] 纯文本查看 复制代码
?

<!-- my-button.vue -->
<template>
<button :style="computedWidth">{{ computedWidth }}</button>
</template>

<script>
export default {

props: {
  width: [String, Number]
},
computed: {
  computedWidth () {
    let o = {}
    if (typeof this.width === 'string') o.width = this.width
    if (typeof this.width === 'number') o.width = this.width + 'px'
    return o
  }
}

}
</script>
使用:
[HTML] 纯文本查看 复制代码
?

<!-- 在其他组件中使用 -->
<template>
<my-button width="100px"></my-button>
<!-- or -->
<my-button :width="100"></my-button>
</template>
阻止 <el-form> 默认提交行为有时候我们在用饿了么组件 <el-form> 在文本框中键入 enter 快捷键的时候会默认触发页面刷新。我们可以加入如下代码解决其默认行为:
[HTML] 纯文本查看 复制代码
?

<el-form @submit.native.prevent>
...
</el-form>
data 初始化因为 props 要比 data 先完成初始化,所以我们可以利用这一点给 data 初始化一些数据进去,看代码:
[JavaScript] 纯文本查看 复制代码
?

export default {
data () {

return {
  buttonSize: this.size
}

},
props: {
size: String
}
}
除了以上,子组件的 data 函数也可以有参数,且该参数是当前实例对象。所有我们可以利用这一点做一些自己的判断。如,改写上面的代码:
[JavaScript] 纯文本查看 复制代码
?

export default {
data (vm) {

return {
  buttonSize: vm.size
}

},
props: {
size: String
}
}
template我们在做 v-if 判断的时候,可以把判断条件放在 template 组件上,最终的渲染结果将不包含 <template> 元素。
[HTML] 纯文本查看 复制代码
?

<template>
<div class="box">

<template v-if="isVal">
  <h2>...</h2>
</template>
<template v-else>
  <h2>...</h2>
</template>

</div>
</template>
v-for 也同样适用。
Lifecycle hook生命周期钩子可以是一个数组类型,且数组中的函数会依次执行。
[JavaScript] 纯文本查看 复制代码
?

export default {
...
created: [
function one () {

 console.log(1)

},
function two () {

 console.log(2)

}
]
...
}
没什么用,知道就行了。事实上生命周期钩子还可以作用于 DOM 元素上,利用这一点,我们可以用父组件中的方法来初始化子组件的生命周期钩子:
[HTML] 纯文本查看 复制代码
?

<!-- Child.vue -->
<template>
<h3>I'm child!</h3>
</template>

<!-- Parent.vue -->
<template>
<child @hook:created="handleChildCreated"></child>
</template>

<script>
import Child from './child.vue'
export default {

 components: [ Child ],
 methods: {
   handleChildCreated () {
     console.log('handle child created...')
   }
 }

}
</script>
其他钩子雷同,不再赘述。
v-for在用 v-for 遍历数组的时候,我们一般都会错误的这样去做,举个栗子:
v-for 和 v-if 放在同一个元素上使用:
[HTML] 纯文本查看 复制代码
?

<template>
<ul class="items">

<!-- 只有激活的用户才可以显示 -->
<li
  v-for="(user, index) in users"
  v-if="user.isActive"
  :key="user.id">
  {{ user.name }}
</li>

</ul>
</template>
由于 v-for 和 v-if 放在同一个元素上使用会带来一些性能上的影响,官方给出的建议是在计算属性上过滤之后再进行遍历。所以平时开发不推荐一起使用,知道有这回事即可,不至于面试时不知道。 关于为什么不推荐放在一起使用,参见 避免-v-if-和-v-for-用在一起。
混合如果好多组件都共用到一些像 props、data、methods 等,可以单独抽出来放到 mixins 混合器中。比如,在用户管理列表中使用。
分页混合器:
[JavaScript] 纯文本查看 复制代码
?

// paging-mixin.vue
export default {
props: {

pageSize: 1,
pageLength: 10,
currentPage: 1
total: 20

},
methods: {

/**
 * 上一页
 */
prevPage (page) {
  ...
},
/**
 * 下一页
 */
nextPage (page) {
  ...
}
/**
 * 跳转到当前页
 */
currentPage (page) {
  ...
}

}
}

Users.vue:
[HTML] 纯文本查看 复制代码
?

<template>
<div class="user-model">

<my-table :data="users"></my-table>
<my-paging
  :page-length="pageLength"
  :page-size="pageSize"
  :current-page="currentPage"
  :total="total">
</my-paging>

</div>
</template>

<script>
import PagingMixin from '../mixins/paging-mixin.vue'
export default {

mixins: [PagingMixin],
data () {
  return {
    users: [],
    pageLength: 10,
    pageSize: 1,
    currentPage: 1,
    total: 20
  }
}

}
</script>

不用每个页面都写一遍 props 和 methods 了。
render 函数下面是一段简单的 template 模板代码:
[HTML] 纯文本查看 复制代码
?

<template>
<div class="box">

<h2>title</h2>
this is content

</div>
</template>

我们用渲染函数来重写上面的代码:
[JavaScript] 纯文本查看 复制代码
?

export default {
render (h) {

let _c = h
return _c('div', 
  { class: 'box'}, 
  [_c('h2', {}, 'title'), 'this is content'])

}
}

事实上,Vue 会把模板(template)编译成渲染函数(render)。上面的 template 模板会被编译成如下渲染函数:
[JavaScript] 纯文本查看 复制代码
?

let render = function () {
return _c('div',

{staticClass:"box"},
[_c('h2', [_v("title")]), _v("this is content")])

}

是不是很像? 正如官方说的,渲染函数比 template 更接近编译器。如果用一个流程图来解释的话,大概是这个样子:
template ↓预编译工具(vue-loader + vue-template-compile) ↓ render ↓resolve vnode复制代码具体参见 Vue声明周期图示。
渲染函数用处:
开发组件库,Element 源码用的都是 render
封装一些高阶组件。组件里面嵌套组件就是高阶组件,前提是要满足组件三要素:props、event、slot
用于处理一些复杂的逻辑判断。如果我们一个组件里面有很多 v-if 判断的话,用模板就显得不合适了,这个时候可以用渲染函数来轻松处理
errorCaptured捕获一个来自子孙组件的错误时被调用。有时候当我们想收集错误日志,却不想把错误暴露到浏览器控制台的时候,这很有用。下面是个例子:
Child.vue
[HTML] 纯文本查看 复制代码
?

<template>
<!-- 省略一些无关代码 -->
</template>
<script>
export default {

mounted () {
  // 故意把 console 写错
  consol.log('这里会报错!')
}

}
</script>

Parent.vue
[HTML] 纯文本查看 复制代码
?

<template>
<child></child>
</template>
<script>
import Child from './Child.vue'
export default {

components: [ Child ],
/**
 * 收到三个参数:
 * 错误对象、发生错误的组件实例
 * 以及一个包含错误来源信息的字符串。
 * 此钩子可以返回 false 以阻止该错误继续向上传播。
 */
errorCaptured (err, vm, info) {
  console.log(err)
  // -> ReferenceError: consle is not defined ...
  console.log(vm)
  // -> {_uid: 1, _isVue: true, $options: {…}, _renderProxy: o, _self: o,…}
  console.log(info)
  // -> `mounted hook`
  // 告诉我们这个错误是在 vm 组件中的 mounted 钩子中发生的
   
  // 阻止该错误继续向上传播
  return false
}

}
</script>

关于 errorCaptured 更多说明,请移步官网-> 。
v-once通过 v-once 创建低开销的静态组件。渲染普通的 HTML 元素在 Vue 中是非常快速的,但有的时候你可能有一个组件,这个组件包含了大量静态内容。在这种情况下,你可以在根元素上添加 v-once 特性以确保这些内容只计算一次然后缓存起来,就像这样:
[HTML] 纯文本查看 复制代码
?

<template>
<div class="box" v-once>

<h2> 用户协议 </h2>
... a lot of static content ...

</div>
</template>
只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。关于 v-once 更多介绍,请移步官网->。
slot-scope作用域插槽。vue@2.5.0 版本以前叫 scope,之后的版本用 slot-scope 将其代替。除了 scope 只可以用于 <template> 元素,其它和 slot-scope 都相同。
用过 Element 组件的同学都知道,当我们在使用<el-table> 的时候会看到如下代码:
Element@1.4.x 的版本:
[HTML] 纯文本查看 复制代码
?

<el-table-column label="操作">
<template scope="scope">
<el-button

size="small"
@click="handleEdit(scope.$index, scope.row)">编辑</el-button>

<el-button

size="small"
type="danger"
@click="handleDelete(scope.$index, scope.row)">删除</el-button>

</template>
</el-table-column>

但在 2.0 之后的版本替换成了 slot-scope。
Element@2.0.11:
[HTML] 纯文本查看 复制代码
?

<el-table-column label="操作">
<template slot-scope="scope">

<el-button
  size="mini"
  @click="handleEdit(scope.$index, scope.row)">编辑</el-button>
<el-button
  size="mini"
  type="danger"
  @click="handleDelete(scope.$index, scope.row)">删除</el-button>

</template>
</el-table-column>
复制代码说白了,slot-scope 相当于函数的回调,我把结果给你,你想怎么处理就怎么处理,一切随你:
[JavaScript] 纯文本查看 复制代码
?

function getUserById (url, data, callback) {
$.ajax({

url,
data,
success: function (result) {
  callback(result)
}

})
}

// 使用
getUserById('/users', { id: 1 }, function (response) {
// 拿到数据并开始处理自己的页面逻辑
})
下面我们来简单模拟下 <el-table> 组件内部是怎么使用 slot-scope 的,看代码:
模拟的 <el-table> 组件:
[JavaScript] 纯文本查看 复制代码
?

// 定义模板
let template = `
<ul class="table">
<li v-for="(item, index) in data" :key="index">

<!-- 我希望数据由调用者自己处理 -->
<!-- 'row' 相当于变量名,随便定义,比如 aaa,bbb 啥的 -->
<slot :row="item">
  <!-- 当使用者什么都没写的时候,默认值才会显示-->
  {{ item.name }}
</slot>

</li>
</ul>
`
Vue.component('el-table', {
template,
props: {

data: Array,
default: []

}
})
在你需要的地方使用 <el-table> 组件:
HTML:
[HTML] 纯文本查看 复制代码
?

<div id="app">
<el-table :data="userData">

<!-- 使用的时候可以用 template -->
<!-- `scope` 也是个变量名,随便命名不是固定的,比如 foo, bar -->
<template slot-scope="scope">
  <!-- 其中 `scope.row` 中的 row 就是我们上边定义的变量啦-->
  <!-- `scope.row`返回的是 `item` 对象 -->
  <template v-if="scope.row.isActived">
    <span class="red">{{ scope.row.name }}</span>
  </template>
  <template v-else>
    {{ scope.row.name }}
  </template>
</template>

</el-table>
</div>
JavaScript:
[JavaScript] 纯文本查看 复制代码
?

new Vue({
el: '#app',
data: {

userData: [
  {id: 1, name: '张三', isActived: false},
  {id: 2, name: '李四', isActived: false},
  {id: 1, name: '王五', isActived: true},
  {id: 1, name: '赵六', isActived: false},
]

}
})
CSS:
[CSS] 纯文本查看 复制代码
?
1
2
3
.red {
color: red
}

JavaScript:
[JavaScript] 纯文本查看 复制代码
?

// <el-table> 组件
Vue.component('el-table', {
name: 'ElTable',
render: function (h) {

return h('div', { 
  class: 'el-table'
}, this.$slots.default)

},
props: {

data: Array

}
})

// <el-table-column>
Vue.component('el-table-column', {
name: 'ElTableColumn',
render: function (h) {

// 定义一个存放 li 元素的数组
let lis = [], 
   // 获取父组件中的 data 数组
   data = this.$parent.data
// 遍历数组,也就是上面的 `v-for`,生成 `<li>` 标签
// `this.$scopedSlots.default` 获取的就是上面 slot-scope 作用于插槽的部分,
// 并把 `{ row: item }` 传给上面的 `scope` 变量
data.forEach((item, index) => {
  let liEl = h('li', {
    key: item.id
  }, [ this.$scopedSlots.default({ row: item }) ])
  // 把生成的 li 标签存到数组
  lis.push(liEl)
})
return h('ul', {
  class: 'el-table-column'
}, lis)

}
})

在你的页面这样来使用:
HTMl:
[HTML] 纯文本查看 复制代码
?

<div id="app">
<el-table :data="list">

<el-table-column>
  <template slot-scope="scope">
    <span class="red" v-if="scope.row.actived">{{ scope.row.name }}</span>
    <span v-else>{{ scope.row.name }}</span>
  </template>
</el-table-column>

</el-table>
</div>

JavaScript:
[JavaScript] 纯文本查看 复制代码
?

new Vue({
el: '#app',
data: {

list: [
  { id: 1, name: '张三', actived: false },
  { id: 1, name: '李四', actived: false },
  { id: 1, name: '王五', actived: true },
  { id: 1, name: '赵六', actived: false },
]

}
})

点赞
收藏
评论区
推荐文章
晴空闲云 晴空闲云
3年前
vue3中基于script setup语法糖的$refs使用
在用vue3开发项目的时候,需要调用子组件的方法,于是想着用$refs来实现,但是我是使用scriptsetup语法糖,原先vue2的语法已经不适用了。于是一番折腾和查阅资料,终于搞定。vue2语法vue2语法在组件上设置ref属性后,在代码里可以通过this.$refs.ref值访问到对应的子组件。一个设置ref值的组件:html在js代码中可以通
美凌格栋栋酱 美凌格栋栋酱
7个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
九路 九路
4年前
Vue经典面试题: Vue.use和Vue.prototype.$xx有血缘关系吗?
有关系吗?没关系,面试的时候总会问如何在Vue的实例上挂载一个方法/属性,也就是Vue.prototype的小技巧,但是突然有人问他俩有啥关系还真是新鲜.(https://imghelloworld.osscnbeijing.aliyuncs.com/8accd67b8a68646ac4d99fd7297e0fbc
Jacquelyn38 Jacquelyn38
4年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Souleigh ✨ Souleigh ✨
4年前
Vue3.0--Vue Composition API使用体验
本文将之前采用Vue2.6开发的todoList小项目改造成为Vue3.0编写,并介绍一下2.x和3.x之间写法的不同之处。Vue3.x适配大部分Vue2.x的组件配置,也就是说以前我们在Vue2.x针对组件的一些配置项,例如:exportdefault{name:'test',components:{},props:{},
Dax Dax
4年前
Vue父子组件
几种常见的通信方式:1、prop属性父组件通过绑定属性的方式,给子组件传值,同时子组件通过设置props来接收letChildVue.extend(template:'content',props:content:type:String,default:()r
马丁路德 马丁路德
4年前
vue3 - 组件通信
vue3组件通信和vue2的通信方式基本一致,只是存在写法上的差异props/emitsetup函数接收两个参数,props和context(上下文,其中有一个emit)用法展示//父组件<template<ibutton:type'type'@onClick
Stella981 Stella981
3年前
Intellij IDEA神器居然还有这些小技巧
概述IntellijIDEA真是越用越觉得它强大,它总是在我们写代码的时候,不时给我们来个小惊喜。出于对IntellijIDEA的喜爱,我决定写一个与其相关的专栏或者系列,把一些好用的IntellijIDEA技巧分享给大家。本文是这个系列的第一篇,主要介绍一些你可能不知道的但是又实用的小技巧。我最爱
Stella981 Stella981
3年前
FLutter父子组件通信
本文介绍flutter父子组件数据传递和回调.还是以之前的代码为例Flutter\_DayByDay(https://gitee.com/Royce_he/Flutter_DayByDay)由于之前用ReactNative写项目,顺便对比一下RN父组件直接在xml标签中写属性{值/方法},子组件通过props去取属性和方法
Stella981 Stella981
3年前
React对state的初级理解
props是参数,个个Class之间传值用的。state则为某个Class的内部状态,Class需要根据这个state是否改变而做出改变;<div id"content"</div    <script type"text/babel"      var CommentForm  React.createC
可莉 可莉
3年前
20个常用的JavaScript简写技巧
任何编程语言的简写技巧都能够帮助你编写更简练的代码,让你用更少的代码实现你的目标。让我们一个个来看看JavaScript的简写技巧吧。1\.声明变量//Longhandlet x;let y20;//Shorthandlet x,y20;2\.给多个变量赋值我们可以使用数组解构来在一行中给
继承棱镜
继承棱镜
Lv1
我一直在你身后从未离开,只要你能回头
文章
3
粉丝
0
获赞
0