Javascript 创建可以管理外部数据的抽象组件

Javascript 创建可以管理外部数据的抽象组件,javascript,vue.js,vuetify.js,Javascript,Vue.js,Vuetify.js,目前,我将Vuetify用于基本组件,并希望创建可重用的扩展。例如,包含复选框的列表、具有某些功能的datatable列等 对于这个问题,我将以包含复选框的列表为例。我创建了以下名为CheckboxGroup.vue的组件 <template> <v-container> <v-checkbox v-for="(item, index) in items" :key="index" v-model="item.stat

目前,我将Vuetify用于基本组件,并希望创建可重用的扩展。例如,包含复选框的列表、具有某些功能的datatable列等

对于这个问题,我将以包含复选框的列表为例。我创建了以下名为CheckboxGroup.vue的组件

<template>
  <v-container>
    <v-checkbox
      v-for="(item, index) in items"
      :key="index"
      v-model="item.state"
      :label="item.title"
    ></v-checkbox>
  </v-container>
</template>

<script>
export default {
  props: {
    items: Array,
    required: true
  }
};
</script>
  <template>
      <v-container fluid>
        <v-checkbox 
          v-for="(item, index) in items"
          :key="index"
          v-model="item[itemModel]" 
          :label="item[itemValue]"
        ></v-checkbox>
        <hr>
        {{items}}
      </v-container>
    </template>
    <script>

    export default {
      name: "CheckboxGroup",
       props: {

        items: {
          type: Array,
          required:true
        },

        itemValue:{
          type:String,
          default: 'title',

           // validate props if you need
          //validator: function (value) {
          //  return ['title', 'name'].indexOf(value) !== -1
          // }
          // or make required
        },

        itemModel:{
          type:String,
          default: 'state',

           // validate props if you need
           //validator: function (value) {
            // validate props if you need
            // return ['state', 'deleted'].indexOf(value) !== -1
           // }
         // or make required
        }

      }
    };
    </script>
<template>

  <div id="app">
    <checkbox-group :items="documents"
      item-value="name"
      item-model="deleted"
    >

    </checkbox-group>
  </div>
</template>

<script>
import CheckboxGroup from "./CheckboxGroup.vue";

export default {
  name: "App",
  components: {
    // HelloWorld,
    CheckboxGroup
  },
  data: function() {
    return {
      documents: [
        {
          id: 1,
          name: "Doc 1",
          deleted: false
        },
        {
          id: 2,
          name: "Doc 2",
          deleted: false
        },
        {
          id: 3,
          name: "Doc 3",
          deleted: true
        }
      ]
    }
}
};
</script>
这次
标题
被称为
名称
状态
被称为
已删除
。显然,
CheckboxGroup
无法管理文档,因为属性名称错误

你将如何解决这个问题?您会创建一个计算属性并重命名这些属性吗?我想这是个坏主意

顺便问一下,使用
v-model
是个好主意吗?另一种解决方案是侦听复选框的已更改事件,并发出带有项索引的事件。然后,您必须侦听父组件中的更改

我不认为有一种方法可以创造出这样的东西

<CheckboxGroup :items="documents" titleAttribute="name" stateAttribute="deleted"/> 

因为不管怎样,这都是糟糕的设计。我希望这是一个非常小的问题,每个Vue开发人员都遇到过这个问题,因为主要目标应该始终是开发可以多次重用的抽象组件


请记住,这个复选框问题只是一个例子。这个问题的解决方案也可以解决相同或类似的问题:)

如果我理解你想要什么,那就不那么简单了。使用道具是个好主意。您不需要管理文档属性名称,只需将属性名称设置为组件

注意

<template>
  <v-container>
    <v-checkbox
      v-for="(item, index) in items"
      :key="index"
      v-model="item.state"
      :label="item.title"
    ></v-checkbox>
  </v-container>
</template>

<script>
export default {
  props: {
    items: Array,
    required: true
  }
};
</script>
  <template>
      <v-container fluid>
        <v-checkbox 
          v-for="(item, index) in items"
          :key="index"
          v-model="item[itemModel]" 
          :label="item[itemValue]"
        ></v-checkbox>
        <hr>
        {{items}}
      </v-container>
    </template>
    <script>

    export default {
      name: "CheckboxGroup",
       props: {

        items: {
          type: Array,
          required:true
        },

        itemValue:{
          type:String,
          default: 'title',

           // validate props if you need
          //validator: function (value) {
          //  return ['title', 'name'].indexOf(value) !== -1
          // }
          // or make required
        },

        itemModel:{
          type:String,
          default: 'state',

           // validate props if you need
           //validator: function (value) {
            // validate props if you need
            // return ['state', 'deleted'].indexOf(value) !== -1
           // }
         // or make required
        }

      }
    };
    </script>
<template>

  <div id="app">
    <checkbox-group :items="documents"
      item-value="name"
      item-model="deleted"
    >

    </checkbox-group>
  </div>
</template>

<script>
import CheckboxGroup from "./CheckboxGroup.vue";

export default {
  name: "App",
  components: {
    // HelloWorld,
    CheckboxGroup
  },
  data: function() {
    return {
      documents: [
        {
          id: 1,
          name: "Doc 1",
          deleted: false
        },
        {
          id: 2,
          name: "Doc 2",
          deleted: false
        },
        {
          id: 3,
          name: "Doc 3",
          deleted: true
        }
      ]
    }
}
};
</script>
与此解决方案类似,重命名属性或使用代理更占用资源,因为您需要运行循环来重命名属性名称或将别名应用于数据数组对象

示例

<template>
  <v-container>
    <v-checkbox
      v-for="(item, index) in items"
      :key="index"
      v-model="item.state"
      :label="item.title"
    ></v-checkbox>
  </v-container>
</template>

<script>
export default {
  props: {
    items: Array,
    required: true
  }
};
</script>
  <template>
      <v-container fluid>
        <v-checkbox 
          v-for="(item, index) in items"
          :key="index"
          v-model="item[itemModel]" 
          :label="item[itemValue]"
        ></v-checkbox>
        <hr>
        {{items}}
      </v-container>
    </template>
    <script>

    export default {
      name: "CheckboxGroup",
       props: {

        items: {
          type: Array,
          required:true
        },

        itemValue:{
          type:String,
          default: 'title',

           // validate props if you need
          //validator: function (value) {
          //  return ['title', 'name'].indexOf(value) !== -1
          // }
          // or make required
        },

        itemModel:{
          type:String,
          default: 'state',

           // validate props if you need
           //validator: function (value) {
            // validate props if you need
            // return ['state', 'deleted'].indexOf(value) !== -1
           // }
         // or make required
        }

      }
    };
    </script>
<template>

  <div id="app">
    <checkbox-group :items="documents"
      item-value="name"
      item-model="deleted"
    >

    </checkbox-group>
  </div>
</template>

<script>
import CheckboxGroup from "./CheckboxGroup.vue";

export default {
  name: "App",
  components: {
    // HelloWorld,
    CheckboxGroup
  },
  data: function() {
    return {
      documents: [
        {
          id: 1,
          name: "Doc 1",
          deleted: false
        },
        {
          id: 2,
          name: "Doc 2",
          deleted: false
        },
        {
          id: 3,
          name: "Doc 3",
          deleted: true
        }
      ]
    }
}
};
</script>
CheckboxGroup.vue

<template>
  <v-container>
    <v-checkbox
      v-for="(item, index) in items"
      :key="index"
      v-model="item.state"
      :label="item.title"
    ></v-checkbox>
  </v-container>
</template>

<script>
export default {
  props: {
    items: Array,
    required: true
  }
};
</script>
  <template>
      <v-container fluid>
        <v-checkbox 
          v-for="(item, index) in items"
          :key="index"
          v-model="item[itemModel]" 
          :label="item[itemValue]"
        ></v-checkbox>
        <hr>
        {{items}}
      </v-container>
    </template>
    <script>

    export default {
      name: "CheckboxGroup",
       props: {

        items: {
          type: Array,
          required:true
        },

        itemValue:{
          type:String,
          default: 'title',

           // validate props if you need
          //validator: function (value) {
          //  return ['title', 'name'].indexOf(value) !== -1
          // }
          // or make required
        },

        itemModel:{
          type:String,
          default: 'state',

           // validate props if you need
           //validator: function (value) {
            // validate props if you need
            // return ['state', 'deleted'].indexOf(value) !== -1
           // }
         // or make required
        }

      }
    };
    </script>
<template>

  <div id="app">
    <checkbox-group :items="documents"
      item-value="name"
      item-model="deleted"
    >

    </checkbox-group>
  </div>
</template>

<script>
import CheckboxGroup from "./CheckboxGroup.vue";

export default {
  name: "App",
  components: {
    // HelloWorld,
    CheckboxGroup
  },
  data: function() {
    return {
      documents: [
        {
          id: 1,
          name: "Doc 1",
          deleted: false
        },
        {
          id: 2,
          name: "Doc 2",
          deleted: false
        },
        {
          id: 3,
          name: "Doc 3",
          deleted: true
        }
      ]
    }
}
};
</script>


{{items}} 导出默认值{ 名称:“CheckboxGroup”, 道具:{ 项目:{ 类型:数组, 必填项:true }, itemValue:{ 类型:字符串, 默认值:“标题”, //如果需要,验证道具 //验证器:函数(值){ //返回['title','name'].indexOf(value)!=-1 // } //或要求 }, 项目模型:{ 类型:字符串, 默认值:“state”, //如果需要,验证道具 //验证器:函数(值){ //如果需要,验证道具 //返回['state','deleted'].indexOf(值)!=-1 // } //或要求 } } };
Home.vue

<template>
  <v-container>
    <v-checkbox
      v-for="(item, index) in items"
      :key="index"
      v-model="item.state"
      :label="item.title"
    ></v-checkbox>
  </v-container>
</template>

<script>
export default {
  props: {
    items: Array,
    required: true
  }
};
</script>
  <template>
      <v-container fluid>
        <v-checkbox 
          v-for="(item, index) in items"
          :key="index"
          v-model="item[itemModel]" 
          :label="item[itemValue]"
        ></v-checkbox>
        <hr>
        {{items}}
      </v-container>
    </template>
    <script>

    export default {
      name: "CheckboxGroup",
       props: {

        items: {
          type: Array,
          required:true
        },

        itemValue:{
          type:String,
          default: 'title',

           // validate props if you need
          //validator: function (value) {
          //  return ['title', 'name'].indexOf(value) !== -1
          // }
          // or make required
        },

        itemModel:{
          type:String,
          default: 'state',

           // validate props if you need
           //validator: function (value) {
            // validate props if you need
            // return ['state', 'deleted'].indexOf(value) !== -1
           // }
         // or make required
        }

      }
    };
    </script>
<template>

  <div id="app">
    <checkbox-group :items="documents"
      item-value="name"
      item-model="deleted"
    >

    </checkbox-group>
  </div>
</template>

<script>
import CheckboxGroup from "./CheckboxGroup.vue";

export default {
  name: "App",
  components: {
    // HelloWorld,
    CheckboxGroup
  },
  data: function() {
    return {
      documents: [
        {
          id: 1,
          name: "Doc 1",
          deleted: false
        },
        {
          id: 2,
          name: "Doc 2",
          deleted: false
        },
        {
          id: 3,
          name: "Doc 3",
          deleted: true
        }
      ]
    }
}
};
</script>

从“/CheckboxGroup.vue”导入CheckboxGroup;
导出默认值{
名称:“应用程序”,
组成部分:{
//HelloWorld,
复选框组
},
数据:函数(){
返回{
文件:[
{
id:1,
名称:“文件1”,
已删除:false
},
{
id:2,
名称:“文件2”,
已删除:false
},
{
id:3,
名称:“文件3”,
删除:真
}
]
}
}
};
基于您的示例,我尝试演示如何创建组件以管理子组件中的对象属性。如果您需要更多信息,请告诉我。

您可以在访问过程中使用映射文档属性名称

注意
在我最初的回答中,我对
get
set
使用了Proxy处理程序,这对于普通的javascript对象来说已经足够了,但是在与Vue
数据
属性一起使用时失败,因为Vue应用了观察者包装器

通过在代理中捕获
has
,可以克服这一问题。我把原始答案留给了对这个问题感兴趣的人

下面是一个演示如何使用代理将“别名”Vue反应性属性指定给不同的名称

  • 在不影响原始数据结构的情况下
  • 无需复制数据
console.clear()
Vue.config.productionTip=false
Vue.config.devtools=false
Vue.component('checkboxgroup'{
模板:“#checkboxGroup”,
道具:{items:Array,必需:true},
});
常量别名属性=(对象,别名映射)=>{
常量处理程序={
has(目标、关键){
如果(输入别名映射){
返回true;//防止Vue添加别名道具
}
返回目标中的键;
},
获取(目标、道具、接受者){
const propToGet=别名映射[prop]| | prop;
返回Reflect.get(target,propToGet);
},
设定(目标、道具、价值、接受者){
常量propToSet=别名映射[prop]| | prop;
返回Reflect.set(目标、propToSet、值)
}
};
返回新代理(obj,handler);
}
新Vue({
el:“#应用程序”,
数据:{
文件:[
{id:1,名称:“Doc 1”,删除:false},
{id:2,名称:“Doc 2”,删除:false},
{id:3,名称:“Doc 3”,删除:true},
]
},
计算:{
checkBoxItems(){
常量别名={
标题:“姓名”,
声明:“已删除”
}
返回这个.documents.map(doc=>aliasProps(doc,别名));
}
},
方法:{
保存设置:函数(){
console.log(this.documents);
}
},
});

拯救

这里有一些很好的答案,肯定能解决您的问题-您本质上是想将数据传递给孩子(这是一个不错的设计-您走的方向是正确的!)

我有点震惊,或者还没有被提及。。。所以我想我会加入

作用域插槽允许您利用传递给子级(但在父级内)的数据。子对象本质上是“反映”数据