支持 vuejs 中的可选链接
Support optional chaining in vuejs
我使用@vue/cli-service 4.2 创建了 vue 和 electron 应用程序,因为我面临可选链接的问题。
我不能使用?用于验证条件,例如 (@babel/plugin-proposal-optional-chaining)
例如。 a?.b?.c 这意味着它检查天气 a 存在然后检查 b 否则
return false 与 angular.
中的模板表达式相同
任何人都知道如何在 vuejs 中配置可选链接。
根据这个问题的评论here
您可以创建一个全局混合并使用 eval
函数计算表达式。
示例:
Vue.mixin({
methods: {
$evaluate: param => eval('this.'+param)
}
});
在模板中:
<template>
<p>{{ $evaluate('user?.name') }}</p>
</template>
他们还补充说它可能并不完美:
Although it's still no substitute for the real operator, especially if you have many occurrences of it
编辑
如上所述,使用eval
可能会带来一些意想不到的问题,我建议您改用计算属性。
证监会中:
<template>
<p>{{ userName }}</p>
</template>
<script>
export default {
data(){
return {
user: {
firstName: 'Bran'
}
}
},
computed: {
userName(){
return this.user?.firstName
}
}
}
</script>
一个快速更新是 Vue 3 捆绑了对可选链接的支持。
要进行测试,您可以尝试编译以下 Vue 组件代码。
<template>
<div id="app" v-if="user?.username">
@{{ user?.username }} - {{ fullName }} <strong>Followers: </strong>
{{ followers }}
<button style="align-self: center" @click="followUser">Follow</button>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
name: 'App',
props: {
test: Object
},
data() {
return {
followers: 0,
user: {
id: 1,
test: {},
username: '_sethAkash',
firstName: undefined,
lastName: 'Seth',
email: 'sethakash007@gmail.com',
isAdmin: true
}
}
},
computed: {
fullName(): string {
//
return `${this?.test?.firstName} ${this?.user?.lastName}`
}
},
methods: {
followUser: function () {
this.followers += 1
}
},
watch: {
followers(newFollowerCount, oldFollowerCount) {
if (oldFollowerCount < newFollowerCount) {
console.log(`${this?.user?.username} has gained a follower!`)
}
}
},
mounted() {
this.followUser()
}
})
</script>
在搜索了很多可能性之后,我做了一个函数来帮助我。
制作一个js文件保存辅助函数并导出
const propCheck = function (obj = {}, properties = ""){
const levels = properties.split(".");
let objProperty = Object.assign({}, obj);
for ( let level of levels){
objProperty = objProperty[level];
if(!objProperty)
return false;
}
return true;
}
export default propCheck;
并在 Vue 实例中全局安装此函数
Vue.prototype.$propCheck = propCheck;
在您的模板中使用后
<span>{{$propCheck(person, "name")}}</span>
或
<span>{{$propCheck(person, "contatcs.0.address")}}</span>
或
<span>{{$propCheck(person, "addres.street")}}</span>
这并不完全相同,但我认为,在这种情况下,对于大多数情况来说,它可能会更好。
法术效果我用了Proxy
。您只需要调用对象的 nullsafe
方法,然后从那里开始,只需使用普通链接即可。
在某些版本的 VueJs 中,您无法指定默认值。它将我们的 null 安全值视为一个对象(有充分的理由)并且 JSON.stringify
它绕过了 toString
方法。我可以覆盖 toJSON
方法,但你不能 return 字符串输出。它仍然会将您的 return 值编码为 JSON。所以你最终用引号引起来了你的字符串。
const isProxy = Symbol("isProxy");
Object.defineProperty(Object.prototype, 'nullsafe', {
enumarable: false,
writable: false,
value: function(defaultValue, maxDepth = 100) {
let treat = function(unsafe, depth = 0) {
if (depth > maxDepth || (unsafe && unsafe.isProxy)) {
return unsafe;
}
let isNullish = unsafe === null || unsafe === undefined;
let isObject = typeof unsafe === "object";
let handler = {
get: function(target, prop) {
if (prop === "valueOf") {
return target[prop];
} else if (typeof prop === "symbol") {
return prop === isProxy ? true : target[prop];
} else {
return treat(target[prop], depth + 1);
}
}
};
let stringify = function() {
return defaultValue || '';
};
let dummy = {
toString: stringify,
includes: function() {
return false;
},
indexOf: function() {
return -1;
},
valueOf: function() {
return unsafe;
}
};
return (isNullish || isObject) ? (new Proxy(unsafe || dummy, handler)) : unsafe;
};
return treat(this);
}
});
new Vue({
el: '#app',
data: {
yoMama: {
a: 1
}.nullsafe('xx'),
yoyoMa: {
b: 1
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
{{ yoMama.yoyoMa.yoMama.yoyoMa.yoMama }}
<hr> {{ yoyoMa.nullsafe('yy').yoMama.yoyoMa.yoMama.yoyoMa }}
</div>
/*
* Where to use: Use in vue templates to determine deeply nested undefined/null values
* How to use: Instead of writing parent?.child?.child2 you can write
* isAvailable(parent, 'child.child2')
* @author Smit Patel
* @params {Object} parent
* {String} child
* @return {Boolean} True if all the nested properties exist
*/
export default function isAvailable(parent, child) {
try {
const childArray = String(child).split('.');
let evaluted = parent;
childArray.forEach((x) => {
evaluted = evaluted[x];
});
return !!evaluted;
} catch {
return false;
}
}
使用:
<template>
<div>
<span :v-if="isAvailable(data, 'user.group.name')">
{{ data.user.group.name }}
<span/>
</div>
</template>
<script>
import isAvailable from 'file/path';
export default {
methods: { isAvailable }
}
</script>
它使用 Babel
启用 Optional Chaining(?.)
、Nullish Coalescing(??)
和 Vue.js SFC
的许多新 ES 语法。
Github Repo: vue-template-babel-compiler
演示
用法
1。安装
npm install vue-template-babel-compiler --save-dev
2。配置
1。 Vue-CLI
// vue.config.js
module.exports = {
chainWebpack: config => {
config.module
.rule('vue')
.use('vue-loader')
.tap(options => {
options.compiler = require('vue-template-babel-compiler')
return options
})
}
}
2。 Nuxt.js
// nuxt.config.js
export default {
// Build Configuration: https://go.nuxtjs.dev/config-build
build: {
loaders: {
vue: {
compiler: require('vue-template-babel-compiler')
}
},
},
// ...
}
Please refer to REAMDE for detail usage
支持 Vue-CLI, Nuxt.js, Webpack
,任何环境使用 vue-loader v15+
.
对模板和 js 文件使用 getSafe() 方法:)
<template><div>
{{getSafe(() => obj.foo.bar)}} <!-- returns 'baz' -->
{{getSafe(() => obj.foo.doesNotExist)}} <!-- returns undefined -->
</div></template>
<script>
export default {
data() {
return {obj: {foo: {bar: 'baz'}}};
},
methods: {getSafe},
};
function getSafe(fn) {
try { return fn(); }
catch (e) {}
}
</script>
我使用@vue/cli-service 4.2 创建了 vue 和 electron 应用程序,因为我面临可选链接的问题。
我不能使用?用于验证条件,例如 (@babel/plugin-proposal-optional-chaining)
例如。 a?.b?.c 这意味着它检查天气 a 存在然后检查 b 否则 return false 与 angular.
中的模板表达式相同任何人都知道如何在 vuejs 中配置可选链接。
根据这个问题的评论here
您可以创建一个全局混合并使用 eval
函数计算表达式。
示例:
Vue.mixin({
methods: {
$evaluate: param => eval('this.'+param)
}
});
在模板中:
<template>
<p>{{ $evaluate('user?.name') }}</p>
</template>
他们还补充说它可能并不完美:
Although it's still no substitute for the real operator, especially if you have many occurrences of it
编辑
如上所述,使用eval
可能会带来一些意想不到的问题,我建议您改用计算属性。
证监会中:
<template>
<p>{{ userName }}</p>
</template>
<script>
export default {
data(){
return {
user: {
firstName: 'Bran'
}
}
},
computed: {
userName(){
return this.user?.firstName
}
}
}
</script>
一个快速更新是 Vue 3 捆绑了对可选链接的支持。
要进行测试,您可以尝试编译以下 Vue 组件代码。
<template>
<div id="app" v-if="user?.username">
@{{ user?.username }} - {{ fullName }} <strong>Followers: </strong>
{{ followers }}
<button style="align-self: center" @click="followUser">Follow</button>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
name: 'App',
props: {
test: Object
},
data() {
return {
followers: 0,
user: {
id: 1,
test: {},
username: '_sethAkash',
firstName: undefined,
lastName: 'Seth',
email: 'sethakash007@gmail.com',
isAdmin: true
}
}
},
computed: {
fullName(): string {
//
return `${this?.test?.firstName} ${this?.user?.lastName}`
}
},
methods: {
followUser: function () {
this.followers += 1
}
},
watch: {
followers(newFollowerCount, oldFollowerCount) {
if (oldFollowerCount < newFollowerCount) {
console.log(`${this?.user?.username} has gained a follower!`)
}
}
},
mounted() {
this.followUser()
}
})
</script>
在搜索了很多可能性之后,我做了一个函数来帮助我。
制作一个js文件保存辅助函数并导出
const propCheck = function (obj = {}, properties = ""){
const levels = properties.split(".");
let objProperty = Object.assign({}, obj);
for ( let level of levels){
objProperty = objProperty[level];
if(!objProperty)
return false;
}
return true;
}
export default propCheck;
并在 Vue 实例中全局安装此函数
Vue.prototype.$propCheck = propCheck;
在您的模板中使用后
<span>{{$propCheck(person, "name")}}</span>
或
<span>{{$propCheck(person, "contatcs.0.address")}}</span>
或
<span>{{$propCheck(person, "addres.street")}}</span>
这并不完全相同,但我认为,在这种情况下,对于大多数情况来说,它可能会更好。
法术效果我用了Proxy
。您只需要调用对象的 nullsafe
方法,然后从那里开始,只需使用普通链接即可。
在某些版本的 VueJs 中,您无法指定默认值。它将我们的 null 安全值视为一个对象(有充分的理由)并且 JSON.stringify
它绕过了 toString
方法。我可以覆盖 toJSON
方法,但你不能 return 字符串输出。它仍然会将您的 return 值编码为 JSON。所以你最终用引号引起来了你的字符串。
const isProxy = Symbol("isProxy");
Object.defineProperty(Object.prototype, 'nullsafe', {
enumarable: false,
writable: false,
value: function(defaultValue, maxDepth = 100) {
let treat = function(unsafe, depth = 0) {
if (depth > maxDepth || (unsafe && unsafe.isProxy)) {
return unsafe;
}
let isNullish = unsafe === null || unsafe === undefined;
let isObject = typeof unsafe === "object";
let handler = {
get: function(target, prop) {
if (prop === "valueOf") {
return target[prop];
} else if (typeof prop === "symbol") {
return prop === isProxy ? true : target[prop];
} else {
return treat(target[prop], depth + 1);
}
}
};
let stringify = function() {
return defaultValue || '';
};
let dummy = {
toString: stringify,
includes: function() {
return false;
},
indexOf: function() {
return -1;
},
valueOf: function() {
return unsafe;
}
};
return (isNullish || isObject) ? (new Proxy(unsafe || dummy, handler)) : unsafe;
};
return treat(this);
}
});
new Vue({
el: '#app',
data: {
yoMama: {
a: 1
}.nullsafe('xx'),
yoyoMa: {
b: 1
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
{{ yoMama.yoyoMa.yoMama.yoyoMa.yoMama }}
<hr> {{ yoyoMa.nullsafe('yy').yoMama.yoyoMa.yoMama.yoyoMa }}
</div>
/*
* Where to use: Use in vue templates to determine deeply nested undefined/null values
* How to use: Instead of writing parent?.child?.child2 you can write
* isAvailable(parent, 'child.child2')
* @author Smit Patel
* @params {Object} parent
* {String} child
* @return {Boolean} True if all the nested properties exist
*/
export default function isAvailable(parent, child) {
try {
const childArray = String(child).split('.');
let evaluted = parent;
childArray.forEach((x) => {
evaluted = evaluted[x];
});
return !!evaluted;
} catch {
return false;
}
}
使用:
<template>
<div>
<span :v-if="isAvailable(data, 'user.group.name')">
{{ data.user.group.name }}
<span/>
</div>
</template>
<script>
import isAvailable from 'file/path';
export default {
methods: { isAvailable }
}
</script>
它使用 Babel
启用 Optional Chaining(?.)
、Nullish Coalescing(??)
和 Vue.js SFC
的许多新 ES 语法。
Github Repo: vue-template-babel-compiler
演示
用法
1。安装
npm install vue-template-babel-compiler --save-dev
2。配置
1。 Vue-CLI
// vue.config.js
module.exports = {
chainWebpack: config => {
config.module
.rule('vue')
.use('vue-loader')
.tap(options => {
options.compiler = require('vue-template-babel-compiler')
return options
})
}
}
2。 Nuxt.js
// nuxt.config.js
export default {
// Build Configuration: https://go.nuxtjs.dev/config-build
build: {
loaders: {
vue: {
compiler: require('vue-template-babel-compiler')
}
},
},
// ...
}
Please refer to REAMDE for detail usage
支持 Vue-CLI, Nuxt.js, Webpack
,任何环境使用 vue-loader v15+
.
对模板和 js 文件使用 getSafe() 方法:)
<template><div>
{{getSafe(() => obj.foo.bar)}} <!-- returns 'baz' -->
{{getSafe(() => obj.foo.doesNotExist)}} <!-- returns undefined -->
</div></template>
<script>
export default {
data() {
return {obj: {foo: {bar: 'baz'}}};
},
methods: {getSafe},
};
function getSafe(fn) {
try { return fn(); }
catch (e) {}
}
</script>