1

我有一个简单的登录表单,正确登录后会滑动到下一个视图。我发现的两个例子的组合。我想使用 MVC 模式将此登录划分为多个文件。在我在网上看到的许多示例中,这在 Sencha Touch 2 中是小菜一碟。无论我尝试什么,我都无法让它工作。我习惯用 Flex、Java、ActionScript、Php 进行编程,但 Sencha json 完全是另一回事。任何人都可以帮助我吗?我想在推荐的文件夹结构中有一个模型、存储、视图和控制器包:

-app
  -controller
    -Controller.js
  -model
    -Model.js
  -store
    -Store.js
  -view
    -Main.js
    -Login.js
    -SecondView.js
-app.js
-app.css
-index.html

这是在一个文件中包含所有逻辑的当前 app.js。

Ext.require([
'Ext.form.Panel',
'Ext.form.FieldSet',
'Ext.field.Text',
'Ext.field.Password',

'Ext.data.Store'
]);

Ext.define('User', {
extend: 'Ext.data.Model',

config: {
    fields: [
        {name: 'name', type: 'string'},
        {name: 'password', type: 'string'}
    ]
}
});

Ext.setup({
icon: 'icon.png',
tabletStartupScreen: 'tablet_startup.png',
phoneStartupScreen: 'phone_startup.png',
glossOnIcon: false,
onReady: function() {
    var form;

    var formBase = {
        url: 'login.php',
        standardSubmit: false,
        title:"Login",
        items: [
            {
                xtype: 'fieldset',
                title: 'MyCompony',
                instructions: 'Log in with username and password.',
                defaults: {
                    required: true,
                    labelAlign: 'left',
                    labelWidth: '40%'
                },
                items: [
                    {
                        xtype: 'textfield',
                        name: 'name',
                        label: 'Name',
                        value: 'user',
                        autoCapitalize: false
                    },
                    {
                        xtype: 'passwordfield',
                        name: 'password',
                        label: 'Password',
                        value: 'test'
                    }
                ]
            },
            {
                xtype: 'toolbar',
                docked: 'bottom',
                items: [
                    {xtype: 'spacer'},
                    {
                        text: 'Reset',
                        handler: function() {
                            form.reset();
                        }
                    },
                    {
                        text: 'Login',
                        ui: 'confirm',
                        handler: function() {
                            if (formBase.user) {
                                form.updateRecord(formBase.user, true);
                            }
                            form.submit({
                                waitMsg: {message: 'Submitting'}
                            });
                        }
                    }
                ]
            }
        ],

        listeners: {
            submit: function(form, result) {
                console.log('success', Ext.toArray(arguments));
                view.push({
                    title: 'Second View',
                    padding: 10,
                    items: [
                        {
                            html: 'Second view'
                        },
                        {
                            xtype: 'button',
                            text: 'Pop this view!',
                            width: 200,
                            handler: function() {
                                view.pop();
                            }
                        }
                    ]
                });
            },
            exception: function(form, result) {
                console.log('failure', Ext.toArray(arguments));
            }
        }
    };

    if (Ext.os.deviceType == 'Phone') {
        Ext.apply(formBase, {
            xtype: 'formpanel',
            autoRender: true
        });
    } else {
        Ext.apply(formBase, {
            xtype: 'formpanel',
            autoRender: true,
            padding: 100
        });
    }
    form = Ext.create('Ext.form.Panel', formBase);
    var view = Ext.create('Ext.navigation.View', {
        fullscreen: true,
        items: [
            form
        ]
    });

}
});

这是一个简单的 php 脚本 (login.php) 来回答登录请求。

<?php
$pw = $_REQUEST['password'];
header('Content-Type: application/json');
if($pw == 'asdf'){
    echo '{"success":true, "msg":'.json_encode('This User is authorized').'}';
}else{
    echo '{"success":false, "msg":'.
        json_encode('This User is NOT authorized').
        ', "errors" : { "password" :'.json_encode('Password is required').
        '}'.
        ', "pwd" :'.json_encode($pw).'}';
}

任何人?

4

3 回答 3

5

好的,经过一些研究(几天),这是答案:

索引.html:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Map</title>
    <link rel="stylesheet" href="../../resources/css/sencha-touch.css" type="text/css">
    <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true"></script>
    <script type="text/javascript" src="../../builds/sencha-touch-all-debug.js"></script>
    <script type="text/javascript" src="app.js"></script>
</head>
<body>
</body>
</html>

登录.php:

<?php
$pw = $_REQUEST['password'];
header('Content-Type: application/json');
if($pw == 'test'){
    echo '{"success":true, "msg":'.json_encode('This User is authorized').'}';
}else{
    echo '{"success":false, "msg":'.
        json_encode('This User is NOT authorized').
        ', "errors" : { "password" :'.json_encode('Password is required').
        '}'.
        ', "pwd" :'.json_encode($pw).'}';
}
?>

应用程序.js:

Ext.Loader.setConfig({ enabled: true });
Ext.application({
    name: 'AddressBook',

    icon: 'resources/images/icon.png',
    tabletStartupScreen: 'resources/images/tablet_startup.png',
    phoneStartupScreen: 'resources/images/phone_startup.png',
    glossOnIcon: true,

    models: ['WorkOrder'],
    stores: ['WorkOrders'],
    views: ['Main','workorder.Map'],
    controllers: ['AppController'],

    launch: function() {
        Ext.Viewport.add({
            xclass: 'AddressBook.view.Main'
        });
    }
});

werkorders.json

[
    {
        "id": "14",
        "lastName": "Franklin",
        "latitude": "52.370216",
        "longitude": "4.895168"
    },
    {
        "id": "2",
        "lastName": "Johnson",
        "latitude": "52.370316",
        "longitude": "4.895868"
    },
    {
        "id": "8",
        "lastName": "Vanderburg",
        "latitude": "52.370516",
        "longitude": "4.895968"
    }
]

应用程序/视图/Main.js:

Ext.define('AddressBook.view.Main', {
    extend: 'Ext.navigation.View',
    xtype: 'mainview',

    requires: [
        'AddressBook.view.Login',
        'AddressBook.view.workorder.Map',
        'AddressBook.view.workorder.Edit'
    ],

    config: {
        autoDestroy: false,

        navigationBar: {
            ui: 'sencha',
            items: [
                {
                    xtype: 'button',
                    id: 'editButton',
                    text: 'Edit',
                    align: 'right',
                    hidden: true,
                    hideAnimation: Ext.os.is.Android ? false : {
                        type: 'fadeOut',
                        duration: 200
                    },
                    showAnimation: Ext.os.is.Android ? false : {
                        type: 'fadeIn',
                        duration: 200
                    }
                },
                {
                    xtype: 'button',
                    id: 'saveButton',
                    text: 'Save',
                    ui: 'sencha',
                    align: 'right',
                    hidden: true,
                    hideAnimation: Ext.os.is.Android ? false : {
                        type: 'fadeOut',
                        duration: 200
                    },
                    showAnimation: Ext.os.is.Android ? false : {
                        type: 'fadeIn',
                        duration: 200
                    }
                }
            ]
        },

        items: [
            { xtype: 'loginForm' }
        ]
    }
});

应用程序/视图/Login.js:

Ext.define('AddressBook.view.Login', {
    title: "Luminizer Login",
    extend: 'Ext.form.Panel',
    xtype: 'loginForm',

    config: {
        url: 'login.php',
        standardSubmit: false,
        title: 'Login Luminizer',
        layout: 'vbox',
        items: [
            {
                xtype: 'fieldset',
                title: 'MyCompony',
                instructions: 'Log in with username and password.',
                defaults: {
                    required: true,
                    labelAlign: 'left',
                    labelWidth: '40%'
                },
                items: [
                    {
                        xtype: 'textfield',
                        name: 'username',
                        id: 'username',
                        label: 'Name',
                        value: 'user',
                        autoCapitalize: false
                    },
                    {
                        xtype: 'passwordfield',
                        name: 'password',
                        id: 'password',
                        label: 'Password',
                        value: 'test'
                    }
                ]
            },
            {
                xtype: 'toolbar',
                docked: 'bottom',
                items: [
                    {xtype: 'spacer'},
                    {
                        text: 'Reset',
                        handler: function() {
                            var form = this.parent.parent;
                            form.reset();
                        }
                    },
                    {
                        text: 'Login',
                        ui: 'confirm',
                        handler: function() {
                            var form = this.parent.parent;

                            var username = form.getValues().username;//form.down('#username').getValue();
                            var password = form.getValues().password;//down('#password').getValue();
                            form.fireEvent('login', username, password);
                        }
                    }
                ]
            }
        ]
    },

    resetForm: function() {
        var view = this.parent;
        view.down("#username").setValue("");
        view.down("#password").setValue("");
    }
});

应用程序/视图/workorder/map.js:

Ext.define('AddressBook.view.workorder.Map', {
    extend: 'Ext.Panel',
    xtype: 'map-show',
    requires: [
        'Ext.Map'
    ],
    config: {
        title: 'Information',
        layout: 'card',
        items: [
            {
                xtype: 'map',
                mapOptions : {
                    zoom : 15,
                    mapTypeId : google.maps.MapTypeId.ROADMAP,
                    navigationControl: true,
                    navigationControlOptions: {
                        style: google.maps.NavigationControlStyle.DEFAULT
                    }
                }
            }
        ]
    },

    centerMap: function(newRecord) {
        if (newRecord) {
            this.down('map').setMapCenter({
                latitude: newRecord.data.latitude,
                longitude: newRecord.data.longitude
            });
        }
    },

    setMarkers: function(markers) {
        var mapPanel = this;
        var map = this.down("map")._map;
        mapPanel.markerDataDict = {};
        mapPanel.markerDict = {};


        if(!mapPanel.infowindow) {
            mapPanel.infowindow = new google.maps.InfoWindow({
                content: 'Sencha HQ'
            });
        }
        for(var i = 0 ;i < markers.length; i++) {
            var markerData = markers[i];
            map.setZoom(15);
            var latitude = Number(markerData.data.latitude);
            var longitude = Number(markerData.data.longitude);
            var position = new google.maps.LatLng(latitude, longitude);
            mapPanel.markerDataDict[position] = markerData;
            var marker = new google.maps.Marker({
                position: position,
                title : markerData.data.id,
                map: map
            });
            mapPanel.markerDict[position] = marker;

            google.maps.event.addListener(marker, 'click', function(mouseEvent) {
                var lat = Math.round(mouseEvent.latLng.lat() * 1000000)/1000000;
                var lng = Math.round(mouseEvent.latLng.lng() * 1000000)/1000000;
                var id = mapPanel.markerDataDict[mouseEvent.latLng].data.id;
                mapPanel.infowindow = new google.maps.InfoWindow();
                mapPanel.infowindow.setContent(['Werkorder: '+ id +'<br/>',
                                                'lat.:' + lat + '<br/>',
                                                'long.:' + lng ].join(""));
                if(mapPanel.oldInfowindow)
                    mapPanel.oldInfowindow.close();
                mapPanel.oldInfowindow = mapPanel.infowindow;
                mapPanel.infowindow.open(map, mapPanel.markerDict[mouseEvent.latLng]);
                mapPanel.infowindow.setPosition(mouseEvent.latLng);
                mapPanel.fireEvent('markerClicked', mapPanel.markerDataDict[mouseEvent.latLng])
            });
        }
    }
});

应用程序/视图/工作订单/Edit.js:

Ext.define('AddressBook.view.workorder.Edit', {
    extend: 'Ext.Container',
    xtype: 'contact-edit',

    config: {
        title: 'Edit',
        layout: 'fit',

        items: [
            {
                xtype: 'formpanel',
                items: [
                    {
                        xtype: 'fieldset',
                        defaults: {
                            labelWidth: '35%'
                        },
                        title: 'Information',
                        items: [
                            {
                                xtype: 'textfield',
                                label: 'First Name',
                                name: 'firstName'
                            },
                            {
                                xtype: 'textfield',
                                label: 'Last Name',
                                name: 'lastName'
                            },
                            {
                                xtype: 'textfield',
                                label: 'Title',
                                name: 'title'
                            }
                        ]
                    },
                    {
                        xtype: 'fieldset',
                        defaults: {
                            labelWidth: '35%'
                        },
                        title: 'Contact Information',
                        items: [
                            {
                                xtype: 'textfield',
                                label: 'Telephone',
                                name: 'telephone'
                            }
                        ]
                    },
                    {
                        xtype: 'fieldset',
                        title: 'Address',
                        defaults: {
                            labelWidth: '35%'
                        },
                        items: [
                            {
                                xtype: 'textfield',
                                label: 'City',
                                name: 'city'
                            },
                            {
                                xtype: 'textfield',
                                label: 'State',
                                name: 'state'
                            },
                            {
                                xtype: 'textfield',
                                label: 'Country',
                                name: 'country'
                            }
                        ]
                    }
                ]
            }
        ],

        listeners: {
            delegate: 'textfield',
            keyup: 'onKeyUp'
        },

        record: null
    },

    updateRecord: function(newRecord) {
        this.down('formpanel').setRecord(newRecord);
    },

    saveRecord: function() {
        var formPanel = this.down('formpanel'),
            record = formPanel.getRecord();

        formPanel.updateRecord(record);

        return record;
    },

    onKeyUp: function() {
        this.fireEvent('change', this);
    }
});

应用程序/控制器/AppController.js:

Ext.define('AddressBook.controller.AppController', {
    extend: 'Ext.app.Controller',

    config: {
        refs: {
            main: 'mainview',
            editButton: '#editButton',
            contacts: 'contacts',
            loginForm: 'loginForm',
            showMap: 'map-show',
            editContact: 'contact-edit',
            saveButton: '#saveButton'
        },

        control: {
            main: {
                push: 'onMainPush',
                pop: 'onMainPop'
            },
            editButton: {
                tap: 'onContactEdit'
            },
            contacts: {
                itemtap: 'onMarkerSelect'
            },
            loginForm: {
                login: 'onLogin'
            },
            showMap: {
                markerClicked: 'onMarkerSelect'
            },
            saveButton: {
                tap: 'onContactSave'
            },
            editContact: {
                change: 'onContactChange'
            }
        }
    },

    onMainPush: function(view, item) {
        var editButton = this.getEditButton();

        if (item.xtype == "map-show") {
            this.getLoginForm().reset();

            this.showEditButton();
        } else {
            this.hideEditButton();
        }
    },

    onMainPop: function(view, item) {
        if (item.xtype == "contact-edit") {
            this.showEditButton();
        } else {
            this.hideEditButton();
        }
    },

    onMarkerSelect: function(record) {
        var editButton = this.getEditButton();

        if (!this.showEdit) {
            this.showEdit = Ext.create('AddressBook.view.workorder.Edit');
        }

        // Bind the record onto the show contact view
        this.showEdit.setRecord(record);

        // Push the show contact view into the navigation view
        this.getMain().push(this.showEdit);
    },

    onLogin: function(username, password) {
        var controller = this;
        Ext.Ajax.request({
            url: 'login.php',
            method: 'POST',
            disableCaching: true,

            params: {
                username: username,
                password: password
            },

            success: function(response) {
                console.log("Login successful for {username}");
                var editButton = controller.getEditButton();
                if (!controller.showContact) {
                    controller.showContact = Ext.create('AddressBook.view.workorder.Map');
                }

                var store = Ext.getStore("WorkOrders");
                store.load({callback: function(records, operation, success) {
                                if(success) {
                                    console.log(records);
                                    controller.showContact.centerMap(store.data.items[0]);
                                    controller.showContact.setMarkers(store.data.items);
                                    // Push the show contact view into the navigation view
                                    controller.getMain().push(controller.showContact);
                                    controller.getLoginForm().resetForm();
                                }
                            },
                            scope: this
                });

            },

            failure: function(response) {
                console.log("Login failure for {username}");
            }
        });

    },

    onMarkerClicked: function(markerData) {

    },

    onContactEdit: function() {
        if (!this.editContact) {
            this.editContact = Ext.create('AddressBook.view.workorder.Edit');
        }

        // Bind the record onto the edit contact view
        this.editContact.setRecord(this.getShowContact().getRecord());

        this.getMain().push(this.editContact);
    },

    onContactChange: function() {
        this.showSaveButton();
    },

    onContactSave: function() {
        var record = this.getEditContact().saveRecord();

        this.getShowContact().updateRecord(record);

        this.getMain().pop();
    },

    showEditButton: function() {
        var editButton = this.getEditButton();

        if (!editButton.isHidden()) {
            return;
        }

        this.hideSaveButton();

        editButton.show();
    },

    hideEditButton: function() {
        var editButton = this.getEditButton();

        if (editButton.isHidden()) {
            return;
        }

        editButton.hide();
    },

    showSaveButton: function() {
        var saveButton = this.getSaveButton();

        if (!saveButton.isHidden()) {
            return;
        }

        saveButton.show();
    },

    hideSaveButton: function() {
        var saveButton = this.getSaveButton();

        if (saveButton.isHidden()) {
            return;
        }

        saveButton.hide();
    }
});

应用程序/模型/WorkOrder.js:

Ext.define('AddressBook.model.WorkOrder', {
    extend: 'Ext.data.Model',

    config: {
        fields: [
            'id',
            'lastName',
            'latitude',
            'longitude'
        ]
    }
});

应用/商店/WorkOrders.js:

Ext.define('AddressBook.store.WorkOrders', {
    extend: 'Ext.data.Store',

    config: {
        model: 'AddressBook.model.WorkOrder',
        autoLoad: false,
        sorters: 'id',
        proxy: {
            type: 'ajax',
            url: 'werkorders.json',
            reader: {
                type: 'json'
            }
        }
    }
});
于 2012-09-26T03:39:13.750 回答
1

我强烈建议您观看此视频以了解 Sencha Touch 2 中的 MVC 应用程序

链接在这里

该视频有一个处理表格的示例,您可以根据自己的情况申请。

于 2012-09-22T04:19:47.987 回答
-1

MVC 的全部意义在于分解逻辑。我不能说在问题中保留 app.js 中的所有逻辑有什么问题。但是看了各种例子后,我了解到 app.js 是一个小文件,而不是一个大文件。将逻辑部分移动到各种其他文件(控制器逻辑到 controller.js 和所有文件),然后重试。
我可以快速指出的一个示例是以下代码

var formBase = {
    url: 'login.php',
    standardSubmit: false,
    title:"Login",
    items: [
        {
            xtype: 'fieldset',
            title: 'MyCompony',
            instructions: 'Log in with username and password.',
            defaults: {
                ...
            },
            items: [
                {
                    xtype: 'textfield',
                    ...
                },
                {
                    xtype: 'passwordfield',
                    ...
                }
            ]
        },
        {
            xtype: 'toolbar',
            ...
            items: [
                {xtype: 'spacer'},
                {
                    ...
                },
                {
                    text: 'Login',
                    ...
                    handler: function() {
                        ...
                    }
                }
            ]
        }
    ],

应该在 view.js 中。这就是 MVC 的意思。希望它能回答你的问题。

于 2012-09-22T06:44:11.527 回答