当前位置: 首页 > 软件库 > Web应用开发 > Web框架 >

vue-model

Model component for Vue.js
授权协议 MIT License
开发语言 PHP
所属分类 Web应用开发、 Web框架
软件类型 开源软件
地区 不详
投 递 者 尉迟卓
操作系统 跨平台
开源组织
适用人群 未知
 软件概览

About

Vue-model is a Javascript plugin for Vue.js that gives you the ability to transform your plain data into rich models with built-in and customizable HTTP actions, computed properties, and methods.

This project started because I work in Vue relatively often and really wanted to be able to call customer.save(), have it POST the data to the server, show the user feedback that the action was in progress, and then apply the server's results to the model.

So that's what this plugin does.

TOC

Installation

> npm install --save vue-model
Vue.use(require('vue-model'));

Quick Examples

Here are a few very basic examples to show you a little bit of what you can do with vue-model.

Create a Model

POST the model to the backend and show a spinner while it's happening.

<button @click.prevent='customer.http.store()'>
    <template v-if='customer.http.createInProgress'>
        <i class='fa fa-spinner fa-spin'></i>
        Creating...
    </template>
    <template v-if='!customer.http.createInProgress'>
        Create Customer
    </template>
</button>

Update a Model

The same as creating, but instead it issues a PUT.

<button @click.prevent='customer.http.update()'>
    <template v-if='customer.http.updateInProgress'>
        <i class='fa fa-spinner fa-spin'></i>
        Saving...
    </template>
    <template v-if='!customer.http.updateInProgress'>
        Save Customer
    </template>
</button>

Fetch or Delete a Model

Some of the other default actions you can execute, right out of the box.

<div v-for='customer in customers'>
    {{ customer.name }}
    (<a href='#' @click.prevent='customer.http.fetch()'>Refresh</a>)
    (<a href='#' @click.prevent='customer.http.destroy()'>Delete</a>)
</div>

Defining Models

Defining your models is as simple as providing a plain JSON object, but it's often better to keep them in dedicated files.

Here's an example of a customer model that defines a few of the model's attributes, some http options, methods, and computed properties.

var Customer = module.exports = {
    attributes: [
        'id',
        'name',
        'email',
    ],

    http: {
        baseRoute: '/api/customers/',
        actions: {
            // Don't expose the destroy action
            destroy: false
        }
    },

    methods: {
        sayHello() {
            alert('Hello ' + this.name);
        }
    },

    computed: {
        is_aaron: function () {
            return this.email === 'aarondfrancis@gmail.com'
        }
    }
}

Once you create a model (which we'll talk about in a bit), you now have a super powerful object you can play with in your views.

Here's a simple form that allows a user to update their name and persist it to the backend. (Bonus: it also shows a loading indicator!)

Change your name:
<input v-model='customer.name'>

<button @click='customer.http.update()'>
    <template v-if='customer.http.updateInProgress'>
        <i class='fa fa-spinner fa-spin'></i>
        Saving...
    </template>
    <template v-if='!customer.http.updateInProgress'>
        Save
    </template>
</button>

And here's the same form, with feedback for errors:

Change your name:
<input v-model='customer.name' :class="{'error': customer.http.errors.has('name') }">

<div v-if='customer.http.errors.any()'>
    Uh oh!
    <ul>
        <li v-for='error in customer.http.errors.flat()'>
            {{ error.field }}: {{ error.message }}
        </li>
    </ul>
</div>

<button @click='customer.http.update()'>
    <template v-if='customer.http.updateInProgress'>
        <i class='fa fa-spinner fa-spin'></i>
        Saving...
    </template>
    <template v-if='!customer.http.updateInProgress'>
        Save
    </template>
</button>

The crazy thing about this it's all done right there with our model: putting the data, showing loading indicators, receiving the response, and mapping the validation errors!

Definition Options

Your model definitions are merged with the values in Defaults.js to create a fully fleshed out model. Let's take a look at some of the options you can define.

Attributes

The top level attributes key defines your model's... attributes. When a model is created, we'll default all these keys to null so that Vue tracks them. Just like plain objects in Vue, if you set a previously undefined key on an object, Vue may not track it and you'll run into unexpected (and frustrating) results.

The attributes array also forms the basis for what data is sent to the server for HTTP requests. You can of course modify what data is sent, but the starting point is the keys in the attributes array.

Methods & Computed

This will be familiar to you if you're familiar with Vue. They work the same way.

HTTP

Now we're getting to the really good stuff. The top level http key holds all of our configuration for making requests. Let's look at some of the keys in the http object.

baseRoute: This may be something like /customers/, or /api/customers/, resulting in final urls like /customers/{id}

eventPrefix: The namespace for events sent from this model. If you don't define a value for this, then it is automatically set to the name that you register your model with. (See the Events section for more on this.)

takeAtLeast: If you want your actions to take at least a certain amount of time, you can set this value to something greater than 0. Sometimes if an action takes < 100ms, it can seem like it didn't work. I learned this from watching an Adam Wathan live-stream, and then later saw it on his twitter. By default it's set to 0ms.

axios: a function that lets you customize the axios request configuration option, if you want.

getDataFromResponse: this is the function that takes the axios response from the server and turns it into a key-value map of data. This just depends on how your backend returns the data. You may return it in a nested data key, or you may return it with no nesting at all.

getErrorsFromResponse: same idea as getDataFromResponse, but for validation errors. This function takes the response and returns a map where keys are field names, and values are arrays of errors. By default this is set up for Laravel 5.5 by returning response.data.errors.

isValidationError: there are lots of things that can go wrong with a request, but we only want to try to map validation errors when the thing that went wrong was validation. This function receives an error and returns a bool if it was a validation error. By default, this is set up to return true if the response code is 422, which is what Laravel sends when validation fails.

errorKey: by default, we nest the errors on the http key, making access from your model look something like customer.http.errors.{method}. If you don't like that, you can change it! You can set this value to e.g. errors, and it will live at the top of your model, making access a little easier: customer.errors.{method}. (Make sure your model doesn't have an errors attribute, method, or computed property though!)

Action Definitions

actionDefaults the defaults that are applied to every action:

{
    // Apply the response data to the model
    apply: false,

    // The server validates this request and could
    // return a validation error in response
    validation: true,

    // Modify what data we should send to the server
    data: {
        // only: [],
        // with: [],
        // without: [],
        // custom: function(data, definition) {
        //     return data;
        // }
    }
}

The actions live in the actions key. This defines the http actions available on your model. You can simply use the defaults, or make up your own! By default, we have index, store, fetch, update, and destroy.

If you wanted to make your own, you could do so like this:

{
    actions: {
        favorite: {
            method: 'PUT',
            route: '{id}/favorite',
            apply: true,
            data: false
        },
        unfavorite: {
            method: 'DELETE',
            route: '{id}/favorite',
            apply: true,
            data: false
        }
    }
}

Now you have two new methods on your model, favorite and unfavorite, which you'd call by e.g.: customer.http.favorite(). (Why you would favorite a customer is beyond me, but you get the idea.)

Assuming your baseRoute is /customers/ and its id is 1, the favorite action will PUT to /customers/1/favorite with no data (data: false), and apply whatever response comes back from the server. (The server could respond with {favorited: true} for example.)

If you want to disable one of the default actions, just set the value to false

{
    actions: {
        destroy: false
    }
}

customer.http.destroy will be undefined now.

Data

By default, we'll send all the keys + values from your model's attributes array. This may not be ideal in many cases though, so you can modify what data gets sent for each action. (Some of these examples may be contrived, but bear with me...)

  • false means no data will be sent at all

    {
        favorite: {
            data: false
        }
    }
  • only: [] defines the only keys from the attributes you want sent.

    {
        setName: {
            data: {
                only: ['name']
            }
        }
    }
  • without: [] defines which keys you want to exclude

    {
        update: {
            data: {
                // Maybe this a separate resource?
                without: ['favorited']
            }
        }
    }
  • with: [] keys present on this but not in attributes that you want to include, perhaps a computed property or method

    {
        update: {
            data: {
                with: ['computed_property', 'method']
            }
        }
    }
  • custom: function after all of the above are computed, as the very last step we'll check for a custom function. The function receives the payload we're about send as well as the action's definition. You must return a payload, otherwise nothing will be sent.

    {
        recent: {
            data: {
                custom: function(payload, definition) {
                    payload.lastFetched = localStorage.get('last_fetched');
                    return payload;
                }
            }
        }
    }

only, with, and without can be arrays, or functions that return arrays.

The arrays themselves can be full of strings, which are accessible from the model (attributes, methods, computed properties) or they can be plain objects.

For example:

{
    favorited: {
        route: '',
        method: 'GET',
        data: {
            only: [],
            with: [{
                active: 1,
                favorited: 1
            }]
        }
    }
}

That action would send a GET to /customers/?active=1&favorited=1. We dropped every key via the only:[], and then added some static data via with.

Registering Models

Now that we know alllll about model definition, let's talk about registration. The registration process is simple using the Vue.models.register method, eg:

var VueModel = require('vue-model');
Vue.use(VueModel);

Vue.models.register('customer', {
    // model definition
});

Vue.models.register('foo', {
    // model definition
});

The first argument is the name argument, the second argument is a plain object that lets you define some options that are specific to your model.

Here's an example of registering a customer model that has a base route of /customers:

Vue.models.register('customer', {
    http: {
        baseRoute: '/customers'
    }
});

You can also register many at once during the plugin install:

var VueModel = require('vue-model');
Vue.use(VueModel, {
    customer: require('./models/customer'),
    foo: require('./models/foo'),
    bar: require('./models/bar'),
});

In this case, they key is the name and the value is the model's definition object.

Now you're ready to start creating and using your models.

Creating Models

There are two different ways to create models in vue-model: You can create them manually whenever you please, or you can have vue-model create them automatically.

Manually

A Single Model

To manually create a model, use the $model() Vue Instance method.

Within a Vue Instance:

this.$model(name, data, options);

The $model() method accepts 3 parameters:

  • name: (string) The type of model. This is the same key you used to register the model
  • data: (object) The model data
  • options: (object) Any instance specific model definitions

You can create the model wherever you please. For example, you can call the method inside the data function:

new Vue({
    el: '#app',
    
    data: function() {
        return {
            customer: this.$model('customer', {
                name: 'Aaron'
            })
        };
    }
});

Or you can call it anywhere else! Here's an example where we instantiate a model within Vue's created lifecycle hook.

new Vue({
    el: '#app',
    
    data: {
        customer: {
            name: 'Aaron'
        }
    },
    
    created: function() {
        this.customer = this.$model('customer', this.customer);
    }
});

Multiple Models

Do you have a whole set of models that need to be created? Great! Just use the this.$models method. It's the same as this.$model except the data parameter is an array of objects.

  • name: (string) The type of model. This is the same key you used to register the model
  • data: (array) A collection model data
  • options: (object) Any instance specific model definitions

This will return an array of models.

You can definitely do this yourself using a for loop and the this.$model method, this.$models is just a little more convenient.

Automatically

Manually creating models gives you ultimate flexibility, but sometimes you just want it to work right away. That's where automatic model creation comes into play.

To automatically create models, you simply need to add a models array to your Vue Instance. A models array element can take two forms. The first form is just a string:

new Vue({
    el: '#app',
    
    models: ['customer'],
    
    data: {
        customer: {
            name: 'Aaron'
        }
    }
});

When you pass a string in, the model type the data key must be the same. In the example above, the model type must be customer, and the data key must also be customer.

If you need more flexibility in naming, you can pass in a proper object.

new Vue({
    el: 'body',

    models: [{
        type: 'customer'
        key: 'newCustomer'
    }],

    data: {
        newCustomer: {
            name: 'Aaron'
        }
    }
});

In this example, the model type is still customer, but the actual data lives on the data key newCustomer.

Under the hood, vue-model adds a mixin that latches on to the created lifecycle event to create models automatically. Read more about the Vue Instance lifecycle

Depending on what the data is will depend on whether one or many models are automatically created. If the data is an array, many model will be created. For example:

new Vue({
    el: '#app',

    models: [{
        type: 'customer'
        key: 'customers'
    }],

    data: {
        customers: [{
            name: 'Aaron'
        },{
            name: 'Evan'
        }]
    }
});

We told vue-model to automatically create the customer model for the data that lives at the customers key. Because the data at customers is an array, vue-model will loop through and make each item a model.

Performing HTTP Actions

Performing HTTP Actions is the heart of vue-model. The whole purpose of this plugin is to make it painless for your models to interact with your application's backend.

All the actions are available on the http key. To perform an action, you just need to call the corresponding method.

Examples:

// Create a new customer
customer.http.store();

// Fetch this customer from the server
customer.http.fetch();

// Save this customer
customer.http.update();

// Delete this customer
customer.http.destroy();

// Retrieve a list of customers
customer.http.index()

These are the 5 actions that vue-model ships with, but you are welcome to disable those and/or set up your own.

Route Interpolation

All of your action's routes will be interpolated with your model's data. So if your model has an id of 10, a route of

/videos/{id}

becomes

/videos/10

You can do this with any attribute from your model. If your model's type has a value of watched, a route defined as

/videos/{type}/increment

would become

/videos/watched/increment

Applying Response Data (or Not)

Another great thing about vue-model is that you can automatically update your models with the response that comes back from the server.

If you define your action with apply = true, vue-model will take the response from the server, loop through all the data and set the values.

{
    favorite: {
        method: 'PUT',
        route: '{id}/favorite',
        apply: true,
        data: false
    }
}

If the server returns

{
    favorited: 1
}

as its payload from the complete action, then the completed attribute on our model will automatically be updated.

customer.http.favorite();
// Once it finishes...
console.log(customer.favorited);
// > 1

That lets us create toggle buttons very easily, all in HTML.

<button v-if="customer.favorited" @click.prevent="video.$.unfavorite()">
    Favorited
</button>

<button v-if="!customer.favorited" @click.prevent="video.$.favorite()">
    Mark as Favorite
</button>

Busy Indicators

You'll often want to know when the model is busy, so that you can show loading indicators or prevent other actions. Vue-model provides two types of busy indicators: Global, and Action Specific.

Global

The global busy indicator lives in the http object under the inProgress key.

For example, if you have a model named customer, you can observe the customer.http.inProgress attribute. This is helpful for showing/hiding elements or disabling buttons.

Here's one way you can disable a button, should the model be busy performing an HTTP action:

<button @click='customer.http.complete()' :disabled='customer.http.inProgress'>
    Mark as Favorite
</button>

Action-Specific

If you have loading indicators scattered across the page and only want to show the correct indicator based on the specific action, then you should use an action-specific busy indicator.

For every action, there is a corresponding property that indicates whether or not that action is currently in process. For example, if the action is named update, then the property would be named updateInProgress.

Consider a case where you have a complete action for a video model and would like to show a loading indicator on the button.

<button @click='video.http.complete()' :disabled='video.http.completeInProgress'>
    <i v-if='video.http.completeInProgress' class='fa fa-spinner fa-spin'></i>
    Mark as Complete
</button>

This button will disable itself and show the lovely Font Awesome loading indicator while the model finishes the complete action. This provides feedback and a good experience for your users. However, in this example if a different action is being performed, say a favorite action, the button will not show the loading indicator because it is bound to completeInProgress and not inProgress or favoriteInProgress.

When any of the action-specific loading indicators ({action}InProgress) are true, the global inProgress indicator will also be true.

Events

Vue-model emits several events that you can listen for and respond to, giving you many different ways to seamlessly tie your app into vue-model.

Naming

Vue-model events follow a naming scheme of {eventPrefix}.{action}.{result}. The eventPrefix can be set in your model definition.

By default, if you don't pass in an eventPrefix while registering your model, vue-model will set it to the name of model you register.

// No eventPrefix, model type is 'customer'
Vue.models.register('customer', {});

// --> eventPrefix is equal to 'customer'


// Explicit eventPrefix passed in
Vue.models.register('customer', {
    http: {
        eventPrefix: 'cst'
    }
});

// --> eventPrefix is equal to 'cst'

{action} is always equal to the name of the action on your API. If you call customer.http.update(), action will be equal to update.

{result} is one of the following:

  • before - Before the action takes place
  • success - Successful completion of the action
  • complete - Action finished, regardless of outcome
  • error - Action failed

Putting it all together, the event name will look similar to the following examples:

  • customer.update.before
  • customer.destroy.success
  • customer.list.complete
  • customer.fetch.error

Data

Each event comes with data payload:

  • {eventPrefix}.{action}.before - Before the action takes place. Receives a plain object with a function you can call to prevent the action from happening.

    {
        cancel: fn
    }
  • {eventPrefix}.{action}.success - Successful completion of the action. Receives the response from the server.

  • {eventPrefix}.{action}.error - Action failed. Receives the axios error object.

  • {eventPrefix}.{action}.complete - Action finished, regardless of outcome. No data. (Not fired if the action was cancelled manually by calling the cancel function in the before event.)

Listeners

Automatically Adding Listeners

Events aren't much good without event listeners. To add event listeners, define a listeners key in your models option. Any model registration then moves to a register key. E.g:

new Vue({
    el: '#app',

    models: {
        register: ['customer']
        listeners: [
            'customer.update.success'
        ]
    },
});

When you add listeners automatically like this, they are bound during the Vue instance's mounted hook and automatically destroyed in the beforeDestroy lifecycle hook.

There are a couple different ways to register listeners within the listeners array. The first is a simple string, e.g. customer.update.success. This serves as both the event and the handler. Vue-model will try to call a method named customer.update.success.

In that case, you'd set your Vue instance up like this:

new Vue({
    el: '#app',

    models: {
        register: ['customer']
        listeners: [
            'customer.update.success'
        ]
    },

    methods: {
        'customer.update.success': function() {
            console.log('great success!')
        }
    }
});

If you don't like that, then you can add listeners as a map, with the key being the event and the value being the method to call, either a string or a function.

new Vue({
    el: '#app',

    models: {
        register: ['customer']
        listeners: [{
            'customer.update.success': 'customerUpdated',
            'customer.update.error': function() {
                console.log('oh no!');
            }
        }]
    },

    methods: {
        customerUpdated: function() {
            console.log('great success!')
        }
    }
});

You can mix and match however you please. If you want to map multiple handlers to a single event, you're free to just keep adding elements to the array.

new Vue({
    el: '#app',

    models: {
        register: ['customer']
        listeners: [
            'customer.update.success',
        {
            'customer.update.error': function() {
                console.log('oh no!');
            }
        }, {
            'customer.update.error': function() {
                console.log('two handlers for the same event, why not');
            }
        }]
    },

    methods: {
        'customer.update.success': function() {
            console.log('great success!')
        }
    }
});

Manually Adding Listeners

There may be times when you don't want to add listeners when your instance is mounted, which is when the automatic listeners are bound. If that's the case, you're in luck because you can use the $addModelListeners and $removeModelListeners methods.

new Vue({
    el: '#app',

    // No automatic listeners
    models: {
        register: ['customer']
    },

    watch: {
        // Some property that determines if this
        // component is "active"
        componentIsActive: function(val) {
            var method = val ? '$add' : '$remove';

            // Add or remove our listeners
            this[method + 'ModelListeners']([
                'customer.update.success'
            ]);
        }
    }

    methods: {
        'customer.update.success': function() {
            console.log('great success!')
        }
    }
});

Remember: When you don't use automatic event listeners, you are responsible for cleaning up your event listeners.

Testing

  • Run npm t or npm test to run all tests once.
  • Run npm run test:watch to watch and rerun tests.
  • vue显示3d模型使用vue-3d-model https://www.npmjs.com/package/vue-3d-model 1. 下载 npm install vue-3d-model --save 引入组件,可支持7种模型文件类型 类型 对应组件 obj <model-obj> json <model-three> stl <model-st> dae <model-collada>

  • vue-3d-model是一个可以解析3d模型的组件,基于threeJS和webGL; 这篇文章就不介绍具体怎么引入了,可以到官网查阅一下,这里主要是记录一下这个组件的属性,方便我自己和大家查阅使用,具体支持哪些文件,我放在文章最后: 配置属性: width - 宽度,和高度一起才生效 height - 高度,和宽度一起才生效 src

 相关资料
  • 构造器 每个 Vue.js 应用都是通过构造函数 Vue 创建一个 Vue 的根实例 启动的: var vm = new Vue({ // 选项 }) 虽然没有完全遵循 MVVM 模式, Vue 的设计无疑受到了它的启发。因此在文档中经常会使用 vm 这个变量名表示 Vue 实例。 在实例化 Vue 时,需要传入一个选项对象,它可以包含数据、模板、挂载元素、方法、生命周期钩子等选项。全部的选

  • vue

    教程简介 本教程要实现一个简单的后台管理系统,包含登陆、数据列表、数据查询、列表分页、添加数据、修改数据和删除数据等功能,教程会从 Vue 入门开始讲解,包含 es6、Sass、Webpack、Bootstrap、jQuery 等技术,再到后台管理系统的一些常规功能,用 Vue 如何去实现。 也许会有人质疑 Vue 和 jQuery 的搭配,在我本人看来,jQuery 本身已很成熟,而且包含了很多

  • FAQ 哇,非常长的一页!是否意味着 Vue 2.0 已经完全不同了呢,是否需要从头学起呢,Vue 1.0 的项目是不是没法迁移了? 非常开心地告诉你,并不是!几乎 90% 的 API 和核心概念都没有变。因为本节包含了很多详尽的阐述以及许多迁移的例子,所以显得有点长。不用担心,你不必从头到尾把本节读一遍! 我该从哪里开始项目迁移呢? 首先,在当前项目下运行迁移工具。我们非常谨慎地把高级 Vue

  • Integration with Vue is easily done with the @tinymce/tinymce-vue package. To use it, install it with npm like this: npm install @tinymce/tinymce-vue For information on how to use the package, check

  • 本规范提供了一种统一的编码规范来编写 Vue.js 代码。这使得代码具有如下的特性: 其它开发者或是团队成员更容易阅读和理解。 IDEs 更容易理解代码,从而提供高亮、格式化等辅助功能 更容易使用现有的工具 更容易实现缓存以及代码包的分拆 要点 尽量使用ES2015,遵循CommonJs规范 切勿直接操作DOM,所以也应该避免使用jQuery库 data属性一定要是一个函数并且返回一个json对象

  • 全局配置 Vue.config 是一个对象,包含 Vue 的全局配置。可以在启动应用之前修改下列属性: silent 类型: boolean 默认值: false 用法: Vue.config.silent = true 取消 Vue 所有的日志与警告。 optionMergeStrategies 类型: { [key: string]: Function } 默认值: {} 用法: Vue.c

  • MVVM MVVM双向数据绑定是通过数据劫持+发布订阅模式Object.defineProperty let obj={}; let theValue; Object.defineProperty(obj,'theKeyName',{ //value:'theValue', configurable:true, //可以配置对象,删除属性 //writable:true

  • Highcharts Vue 是我们基于 Vue 框架封装的 Highcharts,可以很方便的在 Vue 开发环境中使用 Highcharts 创建交互性图表。 开发环境 已经全局安装 Node.js, NPM Vue, Highcharts 库已经安装在项目中 通过 npm 安装 Highcharts 下载安装 安装 highcharts-vue npm install highcharts-