Este artigo apresenta minhas idéias recentes de implementação para funções cascatas semelhantes em cascatas provinciais e municipais. Para separar as responsabilidades, o desempenho e o comportamento, tanto quanto possível, essa função é dividida em 2 componentes e uma única lista vinculada é usada para implementar a lógica de cascata -chave. A próxima seção tem um efeito de demonstração. Embora essa seja uma função muito comum, a lógica de implementação deste artigo é clara e o código é fácil de entender. É separado da semântica das cascatas provinciais e municipais e leva em consideração a separação de desempenho e comportamento. Espero que o conteúdo deste artigo possa trazer algum valor de referência ao seu trabalho. Bem -vindo a ler e corrigir.
Operação em cascata em cascata
CascadeType. Persistência persistente em cascata (salvar) operação
CascadeType. Operação de Merge Cascade Update (Mergy)
CascadeType. Atualizar a operação de atualização em cascata, apenas consultar e obter operações
CascadeType. Remova a operação de exclusão em cascata
CascadeType. Todas as operações em cascata acima
Seja para atrasar o carregamento de rastreamento de busca, o padrão é que o primeiro lado está carregando imediatamente e mais o lado é o carregamento de atraso
Manutenção de relacionamento Mappedby
MAPPEDBY = "ParentId" significa que o atributo parentid na classe infantil é usado para manter o relacionamento. Esse nome deve ser exatamente o mesmo que o nome do atributo parentid na classe infantil.
Além disso, deve -se notar que o tipo de coleção na classe pai deve ser listado ou definido e não pode ser definido como Arraylist, caso contrário, um erro será relatado
Efeito de demonstração (Download de código, Nota: Este efeito exige que o HTTP seja executado. Além disso, os dados no efeito são dados simulados e não são realmente retornados pelo plano de fundo; portanto, os dados de províncias, cidades e municípios que você vê são os mesmos):
Nota: Este artigo usa a implementação técnica dos vários blogs relacionados anteriores. Se você precisar, clique no link abaixo para saber sobre isso:
1) Explicação detalhada da implementação da herança do JavaScript: Forneça um Class.js para definir a relação de herança entre a classe JavaScript e a classe de construção;
2) Habilidades JQuery para fazer qualquer componente suportar gerenciamento de eventos do tipo DOM: Forneça um EventBase.js para fornecer a qualquer instância do componente com funções de gerenciamento de eventos semelhantes a DOM;
3) O encapsulamento secundário dos componentes proxy de cache Ajax e Ajax da JQuery: Ajaxcache: fornece ajax.js e ajaxcache.js, simplifica as chamadas de jQuery e cache para solicitações do cliente.
Vamos primeiro aprender mais sobre os requisitos desta função.
1. Análise funcional
Esta função é ilustrada por um componente em cascata contendo três itens em cascata:
1) Cada item em cascata pode exigir uma opção para ser usada como um prompt de entrada:
Nesse caso, uma opção vazia pode ser selecionada na lista de dados de cada item em cascata (ou seja, a solicitada pela entrada):
Também pode não ser necessário usar como prompts de entrada:
Nesse caso, apenas a opção de dados pode ser selecionada na lista de dados de cada item em cascata, e nenhuma opção vazia pode ser selecionada:
2) Se a página atual estiver consultando do banco de dados e os campos correspondentes ao componente em cascata têm valores, o valor consultado será ecoado no componente em cascata:
Se o campo correspondente encontrado na consulta não tiver valor, as duas situações descritas nos requisitos do ponto 1) serão exibidas.
3) Cada item em cascata forma um único relacionamento de lista vinculada na estrutura de dados. A lista de dados deste último item em cascata está relacionada aos dados selecionados pelo item anterior em cascata.
4) Considerando problemas de desempenho, a lista de dados de cada item em cascata é exibida de forma assíncrona pelo Ajax.
5) Após a inicialização do componente em cascata ser concluído, a lista do primeiro item em cascata é carregada automaticamente.
6) Quando o item de cascata atual mudar, limpe a lista de dados de todos os itens em cascata que estão direta ou indiretamente associados. Ao mesmo tempo, se o valor após o item anterior em cascata não estiver vazio, a lista de dados do próximo item em cascata que estiver diretamente associado a ele será carregada automaticamente. Ao limpar a lista de dados dos itens em cascata, tenha cuidado: se os itens em cascata precisarem exibir a opção Prompt de entrada, a opção deverá ser retida ao limpar.
7) Devemos considerar completamente os problemas de desempenho e evitar o carregamento duplicado.
8) Considerando a emissão de envio de formulário, quando qualquer item em cascata do componente em cascata muda, o valor selecionado pelo componente em cascata deve ser refletido em um campo de texto oculto, de modo a facilitar o envio do valor do componente em cascata ao fundo através do campo de texto.
A função é aproximadamente como acima.
2. Idéias de implementação
1) Estrutura de dados
O que é diferente de outros componentes é que ele possui algumas dependências com os dados em segundo plano. A estrutura de dados que considero é melhor implementada:
{"Id": 1, "Text": "Pequim", "Code": 110000, "ParentId": 0}, {"Id": 2, "Text": "Hebei Província", "Code": 220000, "ParentId": 0}, {"Id": 3, "Text": "Henan Province" ": 0}, {" Id ": 3," "": "Henan Province" ": 0}, {" Id ": 3," "": "Henan Province" ": Code": 0}, {"Id": 3, "" ":" "Henan Province" ":O ID é o identificador exclusivo dos dados, e a relação de associação entre os dados é construída através do pai. Texto e código são todos os campos de negócios comuns. Se seguirmos essa estrutura de dados, será muito simples consultar a interface da lista de dados em cascata:
// Verifique a lista do primeiro item de cascata/API/Cascade? Parentid = 0 // Verifique a lista do segundo item em cascata com base no valor selecionado pelo primeiro item de cascata/api/cascade? Parentid = 1 // Verifique a lista do terceiro item de cascata com base no valor selecionado pelo segundo item cascata/api/cascade?
Essa estrutura também é fácil de manusear para o plano de fundo. Embora sejam estruturalmente uma estrutura de tabela em forma de árvore, as consultas são todas de camada única, por isso são fáceis de implementar.
Também pode ser visto na demonstração anterior de consulta de que essa estrutura pode nos ajudar a unificar a interface e os parâmetros da consulta de dados em um, o que é uma coisa muito conveniente para o desenvolvimento de componentes. Depois de obter essa estrutura de dados em segundo plano, analisamos cada dados em uma opção, como <option value = "beijing" param-value = "1"> beijing </pption>. Isso pode não apenas preencher a exibição suspensa da lista de dados, mas também coletar o valor selecionado do item de cascata atual através da função do elemento de formulário de seleção. Finalmente, quando o item em cascata mudar, também podemos obter a opção selecionada e usar o valor do valor de dados de dados armazenado nela como o parâmetro parentid para carregar a lista do próximo item de cascata. Essa também é a idéia de consulta e análise de dados de componentes em cascata.
No entanto, o que precisa ser considerado aqui é a questão da flexibilidade. Em projetos reais, as estruturas de dados dos componentes em cascata podem ser definidas de acordo com um relacionamento de associação semelhante, como o ID Parentid, mas seus campos não são necessariamente chamados de código de texto ID Parentid e provavelmente serão outros campos. Em outras palavras: Ao analisar os dados em uma opção, o campo usado para o texto e o valor da opção e o valor do campo usado para o atributo de valor de dados-param são incertos; O nome do parâmetro parentid usado ao consultar dados não pode estar morto. Às vezes, se a equipe de back -end gravar primeiro a interface de consulta e usar outro nome, não poderá pedir a alguém que altere o nome do parâmetro, porque ele precisa ser compilado e implantado, o que é mais problemático que o front -end; O valor de ParentID = 0 não pode ser corrigido, porque o pai da primeira camada de dados no projeto real pode estar vazio ou -1. Essas coisas devem ser projetadas como opções. Por um lado, o valor padrão é fornecido e a configuração externa também é reservada de acordo com a situação real. Por exemplo, na implementação final deste artigo, esta opção é definida assim:
TextField: 'Text', // o nome do campo nos dados retornados a serem exibidos no elemento <tution>
Valuefield: 'text', // o nome do campo nos dados retornados a serem definidos no valor do elemento <tution>
Paramfield: 'id', // Ao chamar a interface de consulta de dados, o nome do campo correspondente aos dados a serem passados para o fundo
ParamName: 'ParentId', // Ao chamar a interface de consulta de dados, o nome do parâmetro dos dados é passado após o URL
DefaultParam: '', // Ao consultar o primeiro item em cascata, o valor passado para o fundo é geralmente 0 '', ou -1, etc., indicando que os dados na camada superior devem ser consultados
2) Estrutura HTML
De acordo com o artigo 1 da análise funcional anterior, existem dois tipos de estruturas iniciais de HTML dos componentes em cascata:
<l ul id = "licensElocation-view"> <li> <select> <opção value = ""> Selecione uma província </pption> </leclect> </li> <li> <leclect> <opção value = ""> selecione uma cidade </pption> </clection> </li> <li> <select> <opção/"> selecione </option> </county> </li>
ou
<ul id = "CompanyLocation-View"> <li> <leclect> </leclect> </li> <li> <select> </leclect> </li> <li> <li> <li> <leclect> </leclect> </li> </ul>
A única diferença entre essas duas estruturas é se a opção usada como prompts de entrada está configurada. Deve -se notar também que, se essa opção vazia for necessária, o atributo de valor deverá ser definido como esvaziado; caso contrário, esta opção vazia enviará as informações de prompt de opção para o plano de fundo ao enviar o formulário.
A coisa mais importante sobre essas duas estruturas é o elemento selecionado, que não tem nada a ver com UL e LI. Ul e Li são usados para a interface do usuário; O elemento selecionado não possui semântica e não há necessidade de identificar qual província, que é uma cidade e qual é um distrito ou município. Funcionalmente falando, uma seleção representa um item em cascata. Não importa onde essas seleções sejam definidas. Só precisamos dizer ao componente em cascata que selecionam elementos de que seus itens em cascata são compostos. A única coisa que precisa ser contada ao componente é a sequência desses elementos selecionados, mas isso geralmente é controlado pela ordem padrão dos elementos no HTML. Essa estrutura pode nos ajudar a separar as funções dos componentes do comportamento o máximo possível.
3) Separação de responsabilidades e o uso de listas vinculadas únicas
Pode -se ver da parte anterior que, se esse componente em cascata for dividido de acordo com as responsabilidades, poderá ser dividido em dois componentes principais, um é responsável pelo gerenciamento das funções gerais e dos itens em cascata interna (CascadeView) e o outro é responsável pela implementação funcional dos itens em cascata (cascadeitem). Além disso, para implementar mais convenientemente a lógica em cascata, precisamos apenas conectar todos os itens em cascata por meio de uma lista vinculada. Através do modo Publish-inscrição, este último item em cascata assina a mensagem de que o item anterior em cascata mudou; Quando o item atual de cascata é alterado, uma mensagem é publicada para notificar o item em cascata subsequente para processar a lógica relevante; Através do papel da lista vinculada, esta mensagem pode ser passada até o último item em cascata. Se você descrever em uma foto, será mais ou menos assim:
Tudo o que precisamos fazer é controlar a liberação e a entrega de boas notícias.
4) Submissão do formulário
Para enviar convenientemente o valor do componente em cascata para o plano de fundo, todo o componente em cascata pode ser tratado como um todo, e um evento ligado é fornecido para o exterior, através do qual o evento externo pode obter os valores de todos os itens em cascata. Como existem várias cascatas, ao publicar o evento Onchanged, este evento só pode ser acionado quando qualquer cascata mudar.
5) Cache do Ajax
Neste componente, precisamos considerar dois níveis de cache do Ajax. O primeiro está no nível do componente. Por exemplo, mudei o primeiro item em cascata para Pequim. Neste momento, o segundo item em cascata carregou os dados de Pequim. Então eu mudei o primeiro item em cascata de Pequim para Hebei e depois para Pequim. No momento, o segundo item em cascata ainda exibe a lista de dados associada de Pequim. Se armazenarmos seus dados quando a lista foi carregada, não precisamos iniciar uma solicitação de Ajax desta vez; O segundo é o pedido de Ajax. No nível, se houver vários componentes em cascata na página, primeiro alterno o primeiro item em cascata do primeiro componente em cascata para Pequim, e o navegador inicia uma solicitação AJAX para carregar dados. Quando eu alterno o primeiro item em cascata do segundo componente em cascata para Pequim, o navegador enviará outra solicitação para carregar dados. Se eu cache os dados retornados pela primeira solicitação AJAX do primeiro componente primeiro, quando o segundo componente usar os mesmos parâmetros para solicitar a mesma interface, ele usará diretamente o cache anterior para retornar o resultado, o que também pode reduzir a solicitação AJAX. O segundo nível do cache Ajax depende do "encapsulamento secundário acima do componente proxy do cache do jQuery Ajax e do Ajax: ajaxcache". Para o componente, ele implementa apenas o primeiro nível de cache internamente, mas não precisa considerar o segundo nível de cache, porque a implementação do cache do segundo nível é transparente e não sabe que o componente Ajax que ele usa tem a função do cache.
3. Detalhes da implementação
A implementação final inclui três componentes, Cascadeview, Cascadeitem e CascadepublicDefaults. Os dois primeiros são o núcleo do componente, e o último é usado apenas para definir algumas opções. Sua função é descrita em detalhes nos comentários de CascadeItem. Além disso, existem comentários muito detalhados no código a seguir que explicam o papel de alguns códigos -chave. Olhando para o código com base nos requisitos anteriores, deve ser relativamente fácil de entender. Eu costumava usar o texto para explicar alguns detalhes da implementação, mas depois gradualmente senti que esse método era um pouco ingrato. Primeiro, o idioma no nível de detalhes não era fácil de organizar. Às vezes eu não expressava meu significado. Obviamente, eu queria explicar algo claramente, mas acabou sendo ainda mais confuso. Pelo menos eu me sentiria assim quando li o que escrevi. Segundo, os próprios desenvolvedores têm a capacidade de ler o código -fonte, e a maioria dos desenvolvedores ativos está disposta a entender as idéias de implementação pensando sobre o código de outras pessoas; Então, usei a anotação para explicar os detalhes da implementação :)
CascadepublicDefaults:
define (function () {return {url: '', // Data Query Interface TextField: 'text', // retorna dados no nome do campo ValorField: 'text', // retorna dados no nome do campo que devem ser exibidos no elemento <pution>, paramfield: 'text', // retornar dados no nome do campo que devem ser definidos no valor do valor <> Dos dados a serem passados para o plano de fundo é o paramname: 'ParentId', // Ao chamar a interface de consulta de dados, o nome do parâmetro dos dados que passa após o URL é defaultParam: '', // ao consultar o primeiro item de cascata, o valor que você não pode manter o valor que se mantém no fundo é geralmente 0, '' ou -1, etc. (Usado como um prompt de entrada, como: Selecione uma província), se verdadeiro, a primeira opção de opção de solveajax não será limpa ao recarregar o item de cascata: function (res) {return res;} //} porque o item de cascata enviará um retorno de resposta assíncrono, quando a solicitação de carregamento, que é usada para o devolução;CascadeView:
define (function (requer, exportações, módulo) {var $ = requer ('jQuery'); var class = requer ('mod/class'); var eventBase = requer ('mod/eventbase'); var publicDefaults = requer ('mod/CascadepublicDefaults'); CascadeItem component*/var DEFAULTS = $.extend({}, PublicDefaults, {$elements: undefined, //Array of cascaded item jq objects, the order of elements in the data represents the order of cascaded valueSeparator: ',', //The separator used to obtain the values of all cascaded items. If it is an English comma, the returned value is like Beijing Cidade, distrito, Chaoyang District Valores: '', // A sequência separada pelo ValueParator representa o valor de cada um selecionado no início: $ .noop // Este evento será acionado quando o valor de qualquer item cascaded mudanças}); this.base (); $ el = $ (this); // instanciam o componente cascadeitem e aponte a propriedade previtem de cada instância para a instância anterior // Defina a primeira propriedade previtorem como cascadeitem indefinida = novo cascadeitem ($ el, $. $ .Trim (valores [i])}))); item.push (cascadeItem); // Cada instância em cascata alterará o evento de alteração do componente em cascata // para fora, pode lidar com a lógica de negócios nesse chamado de chamada/por exemplo, defina os valores de todos os itens em cascata como um campo oculto para o formulário em cascadem.on ('alterações'.casc ('cada). {that.trigger ('alterações.CascadeView', that.getValue ());});});}); // A inicialização completa carregando automaticamente os primeiros itens em cascata. {return padrão;}, getItemoptions: function () {var opts = {}, _Options = this.option; para (var i em publicDefaults) {if (publicDefaults.HasownProperty (i) && i em _options) {opts [i] = _options [i] que são uma sequência separada pelo valoreseparator // o valor de um item em cascata vazio não retornará getValue: function () {var value = []; this.items.foreach (function (item) {var EventBase}); retornar cascadeView;});Cascadeitem:
define (function (requer, exportações, módulo) {var $ = requer ('jQuery'); var class = require ('mod/class'); var eventBase = requer ('mod/eventbase'); var publicDefaults = requeting ('mod/cascadepublicDefaults'); var ajaxache = ('mod/ajaxxax//ajaxche'); new AjaxCache();/*** There is a part of the option defined in PublicDefaults, because the CascadeItem component will not be used directly by external * The CascadeView component is used externally, so some options must become public. When the CascadeView component is also defined once * All options are passed through the CascadeView component* When the CascadeView internal instantiation of the CascadeItem, then the option in PublicDefaults é passado para cascadeitem*/var defaults = $ .extend ({}, publicDefaults, {prevImeM: indefinido, // Aponte para o valor do item em cascata anterior: '' // Valor exibido no início}; this isto; function () de proxer o elemento de seleção {that.trigger ('alterado.cascadeItem');}); // Quando o valor de um item em cascata muda, o processamento é para limpar e recarregar os dados conforme necessário. limpou que.hascontent && that.clear (); // se não for o primeiro item em cascata e o item de cascata anterior não selecionar uma opção válida, ele não será processado se (that.previtem && $ .Trim (that.Previtem.getValue () ==. ') '' && this.one ('render.cascadeItem', function () {// Defina o valor inicial que. this.getDefaults (), options);}, getDefaults: function () {return padrão;}, limpe: function () {var $ el = this. $ el; $ el.val (''); if (this.options.keepfirstoption) {// mantenha a primeira opção $ e el.Children (). $ el.html ('');} // Notifique os itens em cascata subsequentes para limpar e recarregar os dados this.tigger ('alterado.cascadeItem'); Os dados do primeiro item em cascata são os dados de nível superior, uma chave fixa e exclusiva é usada quando cache: raiz // O nome da chave usado quando armazenado em cache por outros itens em cascata está relacionado à opção selecionada pela seleção anterior se (! this.previtem) {paramvalue = Opt.DefaultParam; Datakey = ''; this.previtem.getParamValue (); Datakey = paramvalue;} // primeiro verifique se há dados carregados no cache de dados e, se houver, será exibido diretamente para evitar ajaxif (Datakey nesse.cache) {this.render (this.cache [datay]; paramvalue; ajax.get (opts.url, params) .done (function (res) {// resolveajax Este retorno de chamada é usado para analisar os dados retornados pelo ajax externamente // precisa retornar uma matriz de dados var data = opts.resolveajax (res); if (data) {that.cache [datakey] dados; that.render (data);}});}}, render: function (data) {var html = [], opts = this.options; data.foreach (function (item) {html.push (['<opção value = ", [item. do item de opção [opts.paramfield], '">', item [opts.textfield], '</ppthment>']. junção (''));}); // Adicione dinamicamente na forma de anexar para evitar afetar a primeira opção // no final, cenando o valor para esvaziar este. this.Trigger ('render.cascadeItem');}, getValue: function () {return th This.4. Instruções de demonstração
Demonstrar a estrutura do código:
O que é enquadrado é a parte relevante da demonstração. html/regist.html é a página que demonstra o efeito, e js/app/regist.js é a entrada no efeito de demonstração js:
define (função (requer, exporta, módulo) {var $ = requer ('jQuery'); var cascadeView = require ('mod/cascadeview'); função publicSetCasCadeView (fieldname, opts) {this.CascadeView = new CascadeView ({$ elements: $ ('#' fieldname + '-View). '../api/cascade.json', ONHANGED: this. ('input [name = "licensElocation"]'), KeepFirStoption: true, setCascadeView: PublicSetCasCadeView, Onnchanged: function (e, valor) {location_views.licenselocation. SetCascadeView: PublicSetCasCadeView, Onnchanged: function (e, valor) {location_views.companylocation. $ input.val (value); Location_Views.companylocation.setCascadeView ('CompanyLocation', {valores: location_views.companylocation. $ Input.val ()});});Preste atenção à função dos Variable Location_Views no código acima, porque existem vários componentes em cascata na página. Essa variável é realmente gerenciada de maneira semelhante através do modelo de política. Se você não fizer isso, é fácil gerar código duplicado; Este formulário também é mais propício à separação e encapsulamento de alguma lógica de negócios no arquivo de entrada, como o local onde a lógica de negócios é processada.
5 outros
Este é provavelmente o último blog escrito pela empresa agora. Você tem que ir trabalhar em uma nova unidade em dois dias. Não tenho certeza se você tem muito tempo livre para registrar suas idéias habituais de trabalho, mas pelo menos você desenvolveu o hábito de escrever blogs e irá espremer o tempo se não tiver tempo no futuro. O objetivo deste ano é ampliar principalmente o conhecimento e melhorar a qualidade do código. Os blogs subsequentes estarão mais na categoria de desenvolvimento de componentes. Espero que você possa continuar prestando atenção ao site do Wulin.com no futuro!