segunda-feira, 17 de junho de 2019

Maxsize don't work on number field of HTML INPUT

Por incrível que pareça, o grupo Google introduziu um controle de valores em seu campo número, que anulou os atributos "min" e "max", quando da entrada manual de INPUT.

A resolução quase que traz de volta os velhos tempo de controle de edição de texto "na unha" que fazíamos em linguagem C e Pascal.

A resolução se dá em duas partes:

Instrução HTML:


<input id="Id" type="number" data-anterior="" size="6" maxlength="6" onkeydown="checkLen(this,event);">

Código Javascript:

function checkLen(obj,evento){
var taMax = obj.maxLength;
var vrCampo = obj.value;
var vId = obj.id;
var vrant = obj.getAttribute("data-anterior");
        // Captura tecla
if( evento.key ){


console.log(obj+" "+evento.key);
var key = event.keyCode || event.charCode;
var vrCampo = obj.value;
if( ( key == 8 || key == 46 ) && vrCampo.length > 0 ){
vrCampo = vrCampo.substr(0,vrCampo.length-1);
obj.setAttribute("data-anterior",vrCampo);
document.querySelector("#"+vId).value = vrCampo;
evento.preventDefault();
return;
}
} else return;
event.stopPropagation();

var lista = "0123456789";
var posicao = lista.indexOf(evento.key);
// Não é número
if( posicao < 0 ){
vrCampo = vrant;
obj.value = vrCampo;
document.querySelector("#"+vId).value = vrant;
evento.preventDefault();
} else {
// É numero
if( vrCampo.length >= taMax ){
vrCampo = vrant;
obj.value = vrCampo
document.querySelector("#"+vId).value = vrant;
evento.preventDefault();
} else {
vrCampo = vrant + evento.key
obj.setAttribute("data-anterior",vrCampo);
document.querySelector("#"+vId).value = vrCampo;
evento.preventDefault();
}
}
}

Quando utilizávamos a biblioteca "curses" da linguagem "C" tinhamos que nos preocupar com cada tecla pressionada, e seus efeitos. Reparem a necessidade de tratamento do backspace.

Resolvendo o problema de Maxlength de campos número no Chrome

Por incrível que pareça, o grupo Google introduziu um controle de valores em seu campo número, que anulou os atributos "min" e "max", quando da entrada manual de INPUT.

A resolução quase que traz de volta os velhos tempo de controle de edição de texto "na unha" que fazíamos em linguagem C e Pascal.

A resolução se dá em duas partes:

Instrução HTML:


<input id="Id" type="number" data-anterior="" size="6" maxlength="6" onkeydown="checkLen(this,event);">

Código Javascript:

function checkLen(obj,evento){
var taMax = obj.maxLength;
var vrCampo = obj.value;
var vId = obj.id;
var vrant = obj.getAttribute("data-anterior");
        // Captura tecla
if( evento.key ){


console.log(obj+" "+evento.key);
var key = event.keyCode || event.charCode;
var vrCampo = obj.value;
if( ( key == 8 || key == 46 ) && vrCampo.length > 0 ){
vrCampo = vrCampo.substr(0,vrCampo.length-1);
obj.setAttribute("data-anterior",vrCampo);
document.querySelector("#"+vId).value = vrCampo;
evento.preventDefault();
return;
}
} else return;
event.stopPropagation();

var lista = "0123456789";
var posicao = lista.indexOf(evento.key);
// Não é número
if( posicao < 0 ){
vrCampo = vrant;
obj.value = vrCampo;
document.querySelector("#"+vId).value = vrant;
evento.preventDefault();
} else {
// É numero
if( vrCampo.length >= taMax ){
vrCampo = vrant;
obj.value = vrCampo
document.querySelector("#"+vId).value = vrant;
evento.preventDefault();
} else {
vrCampo = vrant + evento.key
obj.setAttribute("data-anterior",vrCampo);
document.querySelector("#"+vId).value = vrCampo;
evento.preventDefault();
}
}
}

Quando utilizávamos a biblioteca "curses" da linguagem "C" tinhamos que nos preocupar com cada tecla pressionada, e seus efeitos. Reparem a necessidade de tratamento do backspace.

sábado, 8 de junho de 2019

Javascript - Proxy

Chega de tentar manter o controle das variáveis pelo escopo global, e de resistir à programação orientada a objetos. As novas frameworks do mercado Web, voltadas para javascript, colocaram tudo dentro de objetos, e mantem rígido controle sobre propriedades, e não mais valores soltos de variáveis, que tornam a vida do programador um inferno.

Manipulador de atribuição e recuperação

Usaremos um manipulador de atribuição (set) e recuperação de propriedades (get) bem simples, para todo conjunto de parâmetros proxiados de uma script javascript:

var handler = {
    get: function(obj, prop) {
        return name in target ? target[name] : null;
        },
    set: function(obj, prop, value) {
        obj[prop] = value;
        }
};


Vamos definir, igualmente, um objeto proxiado "p":

var p = new Proxy({}, handler);

Quando a página for carregada, vamos carregar a função init(), que faz as atribuições. Este é o método correto para garantir que toda a página e suas scripts estejam carregadas, antes que qualquer instrução possa ter sido executada:

function init(){
    p.a = 144;
    p.b = 225;
    }

Página completa

<script>
var handler = {
    get: function(obj, prop) {
        return prop in obj ? obj[prop] : null;
        },
    set: function(obj, prop, value) {
        obj[prop] = value;
        }
};

// Propriedade/Variável a ser proxiada
var p = new Proxy({}, handler);

function init(){
    p.a = 144;
    p.b = 225;
    }
</script>
<body onload="init();alert(p.a)">
</body>

Execução

Vamos utilizar o navegador Chrome para o debug da script:

Vejamos o que será feito em relação a esta atribuição, seguindo o debug:

O objeto em questão "p" terá sua propriedade "a" definida com valor 144. Este objeto é realmente um array.

Vamos saltar para o método de recuperação, quando for emitido o alert(p.a):


 A chamada alcança o método "get" do handler de objetos. Como a propriedade pertence ao objeto, o valor do item do array é correspondente.

Aumentando a eficiência

Mas a eficiência e a proteção das "variáveis" proxiadas aumenta com o expediente de se fazer o proxiamento ser um comportamento natural de objetos instanciados por funções anônimas, associado à camada de exibição das páginas HTML

Trataremos disto em nosso próximo encontro neste blog.

sexta-feira, 5 de outubro de 2018

Tutorial VUE - Menu Vertical

Como vimos em exemplos anteriores, a boa prática no uso do VUE consiste em aproveitar da organização dos array objetos ( em formato JSON ) para armazenagem das informações a serem usadas para funcionalidades dinâmicas que ele permite.

Arquivo de opções

As opções do menu vertical estarão, como dissemos, armazenadas em um array de nome opcoes:

opcoes: [
{ titulo: 'Caminhante', imagem: 'caminhante.jpg', checked: true },    
{ titulo: 'Ciclista', imagem: 'ciclista.jpg', checked: true }, 
{ titulo: 'Cavaleiro', imagem: 'cavaleiro.jpg', checked: true }
]

Os campos titulo contém os rótulos das opções de menu. Os campos imagem contém o nome das imagens que serão mostradas à esquerda dos rótulos. Os campos checked contém um valor true ou false, para que o editor e o publicador de conteúdo possa suprimir ou recuperar opções do menu, sem ter que apagar ou inserir linhas de programação.

Template HTML

Para fazer as opções serem exibidas, o trecho HTML com as inclusões VUE será o seguinte:

<ul style="list-style-type: none;">
<li v-for="opcao in opcoes" v-if="opcao.checked">
<div class="checkbox">
<label>
<img border=0 v-bind:src="opcao.imagem"> <big>{{opcao.titulo}}</big>
</label>
</div>
</li>
</ul>

Código completo

<html>
<head>
<title>Menu Vert.</title>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript">
function init(){
// Comando 1
var data = { 
opcoes: [
{ titulo: 'Caminhante', imagem: 'caminhante.jpg', checked: true },    
{ titulo: 'Ciclista', imagem: 'ciclista.jpg', checked: true }, 
{ titulo: 'Cavaleiro', imagem: 'cavaleiro.jpg', checked: true }
], 
cabecalho: 'SUPORTE', 
novoLivro: '',
novoimagem: ''
};
// Comando 2
new Vue({ 
el: '#app', 
data: data 
});
  }
</script>
<style>
div#app.container {
width: 360px;
}
</style>
</head>
<body onload="init();">
<div id="app" class="container">
<center>
<h2>{{cabecalho}}</h2>
</center>
<ul style="list-style-type: none;">
<li v-for="opcao in opcoes" v-if="opcao.checked">
<div class="checkbox">
<label>
<img border=0 v-bind:src="opcao.imagem"> <big>{{opcao.titulo}}</big>
</label>
</div>
</li>
</ul>
<div class="footer">
<hr/>
</div>

</div>
</body>
</html>

















segunda-feira, 24 de setembro de 2018

Tutorial VUE - Múltiplas instâncias

Fizemos este exemplo com duas numerações paralelas, no entanto com intervalos diferentes, para mostrar as múltiplas instâncias que podem ser feitas utilizando o framework VUE.

Corpo da template

A template se divide realmente em duas: "app1" e "app2". Veja no código abaixo:

<div id="app1" class="container" align="center">
<div  v-for="slide in slides">
<div v-bind:id="'d'+slide.campo" v-show="slide.mostra" class="sld">{{ slide.campo}}</div>
</div>
</div>
<div id="app2" class="container" align="center">
<div  v-for="slide in banners">
<div v-bind:id="'d'+slide.campo" v-show="slide.mostra" class="sld">{{ slide.tag}}</div>
</div>
</div>

Como a ativação de visibilidade (v-show) se dá pelo estado de uma propriedade contida em arranjo, não podemos utilizar o mesmo arranjo para ambas as instâncias, exceto se os tempos de sincronismo forem iguais. Portanto, precisamos de dois arranjos: slides e banners.

Definição inicial dos dados

Apesar de existirem duas instâncias, podemos, sem problema algum, ter as mesmas variáveis definidas em ambas:

var data = { 
negrito: 'bold',
slides: arrSlides,
banners: arrBanners,
cabecalhos : arrCabecalhos,
cabecalho: 'SUPORTE', 
largura: '20px',
tfonte: '10px',
tftevr: '10px',
action:'graf'
};

Se uma variável não for utilizada em uma instância, não existe problema algum. O contrário é que não vale. Se uma instância chamar uma variável e esta não tiver sido definida, o Vue aponta o erro.

Instanciações

Existem algumas variáveis globais, com o intuito de prover a necessária configuração do comportamento das instâncias:

var ACTIVE_SLIDE1 = -1;
var ACTIVE_SLIDE2 = -1;
var TIME_OF_SLIDE1 = 3000;
var TIME_OF_SLIDE2 = 1000;
var NUMBER_OF_SLIDES = arrSlides.length;

Em nosso exemplo o número de slides de ambas as instâncias é igual. Se não for o seu caso, defina, como foi feito para as outras constantes, NUMBER_OF_SLIDES1 e NUMBER_OF_SLIDES2 e substitua de acordo com a lógica em seu código.

As instâncias são definidas como segue:

Primeira instância

var v1 = new Vue({ 
el: '#app1', 
data: data,
mounted: function () {
this.viraPagina1();
},
methods: {
viraPagina1: function(){ 
if(ACTIVE_SLIDE1 > -1) {
this.slides[ACTIVE_SLIDE1].mostra = false;
} else {
this.slides[ACTIVE_SLIDE1+1].mostra = true;
}
ACTIVE_SLIDE1++;
if( ACTIVE_SLIDE1 >= NUMBER_OF_SLIDES ){
ACTIVE_SLIDE1 = 0;
}
this.slides[ACTIVE_SLIDE1].mostra = true;
setTimeout(this.viraPagina1, TIME_OF_SLIDE1);
}
},
watch: {
slides: {
handler: function (linque) {
console.log("w: "+arguments.callee.name)
},
deep: true
}
},
});

Segunda instância

var v2 = new Vue({ 
el: '#app2', 
data: data,
mounted: function () {
this.viraPagina2();
},
methods: {
viraPagina2: function(){ 
if(ACTIVE_SLIDE2 > -1) {
this.banners[ACTIVE_SLIDE2].mostra = false;
} else {
this.banners[ACTIVE_SLIDE2+1].mostra = true;
}
ACTIVE_SLIDE2++;
if( ACTIVE_SLIDE2 >= NUMBER_OF_SLIDES ){
ACTIVE_SLIDE2 = 0;
}
this.banners[ACTIVE_SLIDE2].mostra = true;
setTimeout(this.viraPagina2, TIME_OF_SLIDE2);
}
},
watch: {
banners: {
handler: function (linque) {
console.log("w: "+arguments.callee.name)
},
deep: true
}
},
});

Obtendo o sincronismo ou dessincronismo

Repare que a diferença na cadência da contagem é obtida configurando as constantes  TIME_OF_SLIDE1 e TIME_OF_SLIDE2. É fornecendo valores diferentes para ambas que podemos constatar que cada uma tem o seu comportamento próprio. Imagine a utilidade desta característica para o sincronismo.

Código completo

Para não incorrer no erro de alguns foruns, que apresentam trechos de códigos sem mostrá-lo no corpo global, apresentamos a seguir o código completo deste exemplo, inclusive para o saudável Copiar e Colar:

<html>
<head>
<title>SLD 021</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<style>
/* Animação de slide*/
CAPTION {font-family: Arial;font-size:18px;padding-bottom: 50px;}
DIV.sld {
font-family: Verdana;
color: skyblue;
overflow-x: hidden;
width: 450px;
/* float:left; */
font-size:120px;
font-family: Arial;
}
DIV.fig {float:left;font-size:72px;font-family: Arial;transition: width 4s;background-color:salmon;}
LABEL {font-family: Arial;font-size:12px;}
</style>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript" src="SLD_Opcoes.js"></script>
<script type="text/javascript">
var ACTIVE_SLIDE1 = -1;
var ACTIVE_SLIDE2 = -1;
var TIME_OF_SLIDE1 = 3000;
var TIME_OF_SLIDE2 = 1000;
var NUMBER_OF_SLIDES = arrSlides.length;
function init(){
// Comando 1
var data = { 
negrito: 'bold',
slides: arrSlides,
banners: arrBanners,
cabecalhos : arrCabecalhos,
cabecalho: 'SUPORTE', 
largura: '20px',
tfonte: '10px',
tftevr: '10px',
action:'graf'
};
// Comando 2
var v1 = new Vue({ 
el: '#app1', 
data: data,
mounted: function () {
this.viraPagina1();
},
methods: {
viraPagina1: function(){ 
if(ACTIVE_SLIDE1 > -1) {
this.slides[ACTIVE_SLIDE1].mostra = false;
} else {
this.slides[ACTIVE_SLIDE1+1].mostra = true;
}
ACTIVE_SLIDE1++;
if( ACTIVE_SLIDE1 >= NUMBER_OF_SLIDES ){
ACTIVE_SLIDE1 = 0;
}
this.slides[ACTIVE_SLIDE1].mostra = true;
setTimeout(this.viraPagina1, TIME_OF_SLIDE1);
}
},
watch: {
slides: {
handler: function (linque) {
console.log("w: "+arguments.callee.name)
},
deep: true
}
},
});
var v2 = new Vue({ 
el: '#app2', 
data: data,
mounted: function () {
this.viraPagina2();
},
methods: {
viraPagina2: function(){ 
if(ACTIVE_SLIDE2 > -1) {
this.banners[ACTIVE_SLIDE2].mostra = false;
} else {
this.banners[ACTIVE_SLIDE2+1].mostra = true;
}
ACTIVE_SLIDE2++;
if( ACTIVE_SLIDE2 >= NUMBER_OF_SLIDES ){
ACTIVE_SLIDE2 = 0;
}
this.banners[ACTIVE_SLIDE2].mostra = true;
setTimeout(this.viraPagina2, TIME_OF_SLIDE2);
}
},
watch: {
banners: {
handler: function (linque) {
console.log("w: "+arguments.callee.name)
},
deep: true
}
},
});
}
</script>
</head>
<body onload="init();">
<div id="app1" class="container"  style="float:clear;" align="center">
<div  v-for="slide in slides">
<div v-bind:id="'d'+slide.campo" v-show="slide.mostra" class="sld">{{ slide.campo}}</div>
</div>
</div>
<div id="app2" class="container" style="float:clear;" align="center">
<div  v-for="slide in banners">
<div v-bind:id="'d'+slide.campo" v-show="slide.mostra" class="sld">{{ slide.tag}}</div>
</div>
</div>
</body>
</html>





















quinta-feira, 20 de setembro de 2018

Tutorial VUE - Gráficos de barras

Apresentamos aqui um tutorial VUE mostrando como é fácil produzir uma script HTML5 e javascript VUE para produção de gráficos de barras.

Trecho principal

Este trecho de código contém o princípio geral da script de gráfico:

<table cellspacing=1 border=0>
<caption class="cab">{{ cabecalhos["graf"].nome }}</caption>
<tr>
<td  v-for="barra in barras" valign=bottom>
<div class="vrBar" v-bind:style="{fontSize: tfonte}">{{ barra.altura}}</div>
<div class="barraH" v-bind:style="{height:barra.altura, backgroundColor: barra.cor, width: largura}">
</div>
<div class="txtBar" v-bind:style="{fontSize: tfonte}">{{ barra.campo}}</div>
</td>
</tr>
</table>

A formatação do gráficos se utiliza das facilidades providas pela tag TABLE. Estas facilidades são (1) dimensionamento dinâmico, (2) estabelecimento das colunas de forma bem definida, (3) oferecem parâmetros para espaçamento entre as colunas e (4) garantem a continuidade do gráfico em uma mesma região.

O conteúdo

O conteúdo, ou seja, as informações de cada barra a ser representada está no arranjo abaixo:

var arrBarras = [
{ campo: '01', tipo: 'N', titulo: 'Mes 01', altura:  60,  cor: '#002A36', checked: true, secao: 'graf' },
{ campo: '02', tipo: 'N', titulo: 'Mes 02', altura: 200, cor: '#402A36', checked: true, secao: 'graf' },
{ campo: '03', tipo: 'N', titulo: 'Mes 03', altura:  80,  cor: '#802A36', checked: true, secao: 'graf' },
{ campo: '04', tipo: 'N', titulo: 'Mes 04', altura: 160, cor: '#C02A36', checked: true, secao: 'graf' },
{ campo: '05', tipo: 'N', titulo: 'Mes 05', altura:  90,  cor: '#008A36', checked: true, secao: 'graf' },
{ campo: '06', tipo: 'N', titulo: 'Mes 06', altura:  80,  cor: '#008A80', checked: true, secao: 'graf' },
{ campo: '07', tipo: 'N', titulo: 'Mes 07', altura: 140, cor: '#008AC0', checked: true, secao: 'graf' },
{ campo: '08', tipo: 'N', titulo: 'Mes 08', altura: 120, cor: '#008AF0', checked: true, secao: 'graf' },
{ campo: '09', tipo: 'N', titulo: 'Mes 09', altura:   80, cor: '#00CA80', checked: true, secao: 'graf' },
{ campo: '10', tipo: 'N', titulo: 'Mes 10', altura: 110, cor: '#00CAC0', checked: true, secao: 'graf' },
{ campo: 'FF', tipo: 'N', titulo: 'Mes 0N', altura:   80,  cor: '#00FA36', checked: true, secao: 'graf' }
];

Ele fica armazenado no arquivo javascript GRAF_Opcoes.js, bem como o arranjo cabecalhos

var arrCabecalhos = {
graf:{nome:"GRÁFICO DE DESEMPENHO MENSAL", acao: "" },
traj:{ nome:"MAPA", acao:""}
};

Você deve estar estranhando o fato de que os nomes de variáveis utilizados na template HTML não batem com os nomes dos arranjos mostrados. Na seção data do objeto VUE é feita a associação, conforme colocamos abaixo:

var data = { 
negrito: 'bold',
barras: arrBarras,
cabecalhos : arrCabecalhos,
cabecalho: 'SUPORTE', 
largura: '20px',
tfonte: '10px',
action:'graf'
};

Aqui vemos a associação entre os nomes que serão usados na instanciação do VUE, na seção data . Mostramos a seção na instanciação do VUE, que segue:

var v1 = new Vue({ 
el: '#app', 
data: data,
watch: {
barras: {
handler: function (linque) {
console.log("w: "+arguments.callee.name)
},
deep: true
}
},
});

A seção data aponta para as variáveis definidas no array JSON data mostrado anteriormente.

Código completo

<html>
<head>
<title>Graf 03</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<style>
CAPTION {font-family: Arial;font-size:18px;padding-bottom: 50px;}
DIV.barraH {background-color:gray;vertical-align: bottom;float:clear;}
DIV.txtBar {float:clear;vertical-align: bottom;display: inline-block;font-family: Arial;font-size:10px;}
DIV.vrBar {float:clear;vertical-align: bottom;display: inline-block;font-family: Arial;font-size:10px;color:maroon;}
LABEL {font-family: Arial;font-size:12px;}
</style>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript" src="GRAF_Opcoes.js"></script>
<script type="text/javascript">
function init(){
// Comando 1
var data = { 
negrito: 'bold',
barras: arrBarras,
cabecalhos : arrCabecalhos,
cabecalho: 'SUPORTE', 
largura: '20px',
tfonte: '10px',
action:'graf'
};
// Comando 2
var v1 = new Vue({ 
el: '#app', 
data: data,
watch: {
barras: {
handler: function (linque) {
console.log("w: "+arguments.callee.name)
},
deep: true
}
},
});
}
</script>
</head>
<body onload="init();">
<div id="app" class="container" align="center">
<table cellspacing=1 border=0>
<caption class="cab">{{ cabecalhos["graf"].nome }}</caption>
<tr>
<td  v-for="barra in barras" valign=bottom>
<div class="vrBar" v-bind:style="{fontSize: tfonte}">{{ barra.altura}}</div>
<div class="barraH" v-bind:style="{height:barra.altura, backgroundColor: barra.cor, width: largura}">
</div>
<div class="txtBar" v-bind:style="{fontSize: tfonte}">{{ barra.campo}}</div>
</td>
</tr>
</table>
<label>Largura da barra:</label><select name="larg" v-model="largura">
<option value="15px">15px
<option value="20px">20px
<option value="25px">25px
<option value="30px">30px
<option value="35px">35px
<option value="40px">40px
<option value="45px">45px
<option value="50px">50px
</select>
<label>Tamanho da fonte:</label><select name="fonte" v-model="tfonte">
<option value="10px">10px
<option value="15px">15px
<option value="20px">20px
<option value="25px">25px
<option value="30px">30px
<option value="35px">35px
<option value="40px">40px
<option value="45px">45px
<option value="50px">50px
</select>
</div>
</body>
</html>

Conclusão

Com o framework VUE, não é preciso procurar plugins ou complementos para fazer aplicações dinâmicas. Ele possui características extensivas de HTML, como se as tags tivessem sido melhoradas, em um sincronismo muito eficiente. Aqueles comportamentos que esperávamos das tags, de forma que, quando um parâmetro fosse alterado, a página "reagisse" de acordo, agora estão disponíveis.















terça-feira, 18 de setembro de 2018

Tutorial VUE - Exemplo Formulários

O recurso mais procurado para solução em sistemas de informação é o formulário para entrada de dados.

Neste exemplo, vamos explicar a melhor forma de implementar os formulários utilizando o VUE.

Arquivo de configuração

Para utilizar o VUE, vá se acostumando aos arquivos de configuração sob a forma de arrays objeto. Abaixo listamos o arquivo de configuração para este fim:

var arrOpcoes = [
{ campo: 'Id', tipo: 'N', obrigatorio: 'N', titulo: 'Identificador', tamanho: 6, cor: '#002A36', soLeitura: true, imagem: '', link: '', checked: true, secao: 'form' , destino:'',quadro:''},
{ campo: 'Descri', tipo: 'T', obrigatorio: 'N', titulo: 'Descrição', tamanho: 50, cor: '#003745', soLeitura: false, imagem: '', link: '', checked: true, secao: 'form' , destino:'' ,quadro:''},
{ campo: 'Area', tipo: 'T', obrigatorio: 'S', titulo: 'Área', tamanho: 4, cor: '#003745', soLeitura: false, imagem: '', link: '', checked: true, secao: 'form' , destino:'' ,quadro:''},
{ campo: 'DtNascto', tipo: 'D', obrigatorio: 'N', titulo: 'Data de Nascimento', tamanho: 10, cor: '#003745', soLeitura: false, imagem: '', link: '', checked: true, secao: 'form' , destino:'' ,quadro:''},
{ campo: 'UF', tipo: 'T', obrigatorio: 'N', titulo: 'Uf', tamanho: 2, cor: '#003745', soLeitura: false, imagem: '', link: '', checked: true, secao: 'form' , destino:'' ,quadro:'', multivalue: [{vr:"", descri: "[Escolha a UF]"},{vr:"AC", descri: "Acre"},{vr:"AM", descri: "Amapá"},{vr:"MG", descri: "Minas Gerais"},{vr:"RJ", descri: "Rio de Janeiro"},{vr:"SP", descri: "São Paulo"}]},
{ campo: 'VrNo', tipo: 'N', obrigatorio: 'N', titulo: 'Número', tamanho: 6, cor: '#002A36', soLeitura: false, imagem: '', link: '', checked: true, secao: 'form' , destino:'',quadro:''}
];
var arrCabecalhos = {
form:{nome:"ENTRADA DE DADOS PADRÃO", acao: "" },
traj:{ nome:"MAPA", acao:""}
};

arrOpcoes - contém as informações de configuração de cada campo do formulário, de acordo com as seguintes convenções:

campo: nome do campo na tabela do banco de dados;
tipo: "N"umérico, "T"exto ou "D"ata;
obrigatório: "N"ão obrigatório ou "S" obrigatório;
título: Descrição que aparece à frente do campo INPUT no formulário;
tamanho: Tamanho do campo na tabela do banco de dados;
cor: cor da letra usada para descrição do campo no formulário;
soLeitura: Diz se o campo será somente leitura no INPUT do formulário;
imagem: Para uso futuro;
link: Para uso futuro;
checked: Seleção dos campos a serem exibidos;
secao: campo para filtragem de grupos de campos para diversos fins do formulário;
destino: Para uso futuro;
quadro: Para uso futuro;
multivalue: Array para armazenamento de opções de campos do tipo HTML Select;

Como o VUE exibe conteúdos de arranjos

O recurso mais utilizado pelo VUE é justamente o de prover conteúdo dinâmico a partir de arranjos. E justamente será este arranjo de opções, mostrado anteriormente, o ponto de apoio para isto. O trecho mais importante para este fim é:

<table border=0>
<tr v-for="opcao in opcoes" v-if="opcao.checked && opcao.secao == action">
<td>
<label v-bind:style="{fontWeight:negrito, color: opcao.cor}">{{ opcao.titulo }}</label>
</td>
<td>
 <input v-bind:id="opcao.campo" v-bind:size="opcao.tamanho" v-bind:readonly="opcao.soLeitura" />
</td>
</tr>
</table>

Explicação

Os campos serão, cada um, linhas de uma tabela HTML. Para enumerá-los, estabelecemos um loop na tag TR, que corresponde à linha da tabela.

A explicação se inicia a partir da variável opcoes. Esta é uma variável a ser declarada no corpo do javascript, no momento da instanciação do objeto Vue:

var v1 = new Vue({ 
el: '#app', 
data: data,
watch: {
action: {
handler: function (linque) {
console.log("w: "+arguments.callee.name+" vis: "+this.action)
},
deep: true
},
opcoes: {
handler: function (linque) {
console.log("w: "+arguments.callee.name)
},
deep: true
}
},
methods: {
goLink: function (linque,quadro) {
this.action = linque;
if( quadro != '' ){
houveQuadro = true;
} else {
houveQuadro = false;
}
},
viraPagina: function(){ 
this.mostraForm=true; 
}
}
});

Estando na seção watch do Vue, informamos a ele para manter um monitoramento dinâmico desta variável. Mas qual é o protótipo da mesma. Vejamos a seção data do mesmo objeto Vue. Ela aponta para outro data, desta vez uma variável, array ou objeto, no corpo do javascript FORA do objeto Vue:

var data = { 
negrito: 'bold',
opcoes: arrOpcoes,
cabecalhos : arrCabecalhos,
cabecalho: 'SUPORTE', 
linque:'',
novoopcao: '',
novoimagem: '',
mostraForm:false,
houveQuadro:false,
action:'form'
};

Aqui verificamos que opcoes aponta para uma variável, array ou objeto arrOpcoes, definido anteriormente (ao final exibiremos o código completo):

var arrOpcoes = [
{ campo: 'Id', tipo: 'N', obrigatorio: 'N', titulo: 'Identificador', tamanho: 6, cor: '#002A36', soLeitura: true, imagem: '', link: '', checked: true, secao: 'form' , destino:'',quadro:''},
{ campo: 'Descri', tipo: 'T', obrigatorio: 'N', titulo: 'Descrição', tamanho: 50, cor: '#003745', soLeitura: false, imagem: '', link: '', checked: true, secao: 'form' , destino:'' ,quadro:''},
{ campo: 'Area', tipo: 'T', obrigatorio: 'S', titulo: 'Área', tamanho: 4, cor: '#003745', soLeitura: false, imagem: '', link: '', checked: true, secao: 'form' , destino:'' ,quadro:''},
{ campo: 'DtNascto', tipo: 'D', obrigatorio: 'N', titulo: 'Data de Nascimento', tamanho: 10, cor: '#003745', soLeitura: false, imagem: '', link: '', checked: true, secao: 'form' , destino:'' ,quadro:''},
{ campo: 'UF', tipo: 'T', obrigatorio: 'N', titulo: 'Uf', tamanho: 2, cor: '#003745', soLeitura: false, imagem: '', link: '', checked: true, secao: 'form' , destino:'' ,quadro:'', multivalue: [{vr:"", descri: "[Escolha a UF]"},{vr:"AC", descri: "Acre"},{vr:"AM", descri: "Amapá"},{vr:"MG", descri: "Minas Gerais"},{vr:"RJ", descri: "Rio de Janeiro"},{vr:"SP", descri: "São Paulo"}]},
{ campo: 'VrNo', tipo: 'N', obrigatorio: 'N', titulo: 'Número', tamanho: 6, cor: '#002A36', soLeitura: false, imagem: '', link: '', checked: true, secao: 'form' , destino:'',quadro:''}
];

v-for

Como v-for percorre estes valores ? O atributo v-for (v-for="opcao in opcoes") estabelece um loop neste array-objeto, de forma que a coleção de itens existente possa ser escaneada

v-if

Em qualquer contexto do Vue podemos fazer uma filtragem dos elementos a serem considerados. Como isto é feito ? O atributo v-if ( v-if="opcao.checked && opcao.secao == action") condiciona a escolha destes itens.

Conclusão intermediária

Portanto, a tag

<tr v-for="opcao in opcoesv-if="opcao.checked && opcao.secao == action">

percorre os valores de arrOpcoes (devido às ligações estabelecidas pelo data) colocando cada item na variável opcao, caso a propriedade (ou atributo) secao tenha o valor armazenado na variável action:

var data = { 
negrito: 'bold',
opcoes: arrOpcoes,
cabecalhos : arrCabecalhos,
cabecalho: 'SUPORTE', 
linque:'',
novoopcao: '',
novoimagem: '',
mostraForm:false,
houveQuadro:false,
action:'form'
};

v-bind:style

O modificador v-bind, em conjunto com qualquer atributo HTML, faz com que o valor seja obtido em segundo nível. O que vem a ser isto ? Ao invés de encarar o conteúdo do atributo tal como está, ele executa um "eval" da expressão. Ou seja, se a expressão é uma chamada de função, a função é chamada, e o valor aproveitado é o resultado dela. Se for uma variável, o valor considerado será o conteúdo desta última variável:

v-bind:style="{fontWeight:negrito, color: opcao.cor}"

Como o atributo aqui discutido é o style, deduzimos que toda a expressão sofrerá um "eval" do Javascript. Mas existem algumas observações a serem feitas, neste caso:

O style está realmente no formato JSON;
Não foi utilizada a cláusula de style "font-weight" do CSS3, e sim uma forma já interna do VUE. Todas as cláusulas compostas do CSS3, separadas por hifens, deverão ser expressas nesta notação (primeira letra que sucede o hífen será maiúscula);
O conjunto de estilos estará entre chaves;
Os estilos estarão separados por "," (vírgula) e não ";" (ponto e vírgula);

v-bind no INPUT

O que aconteceu em relação ao estilo na tag LABEL também se dará com a tag INPUT:

<input v-bind:id="opcao.campo" v-bind:size="opcao.tamanhov-bind:readonly="opcao.soLeitura" />

v-bind:id - Terá como valor o conteúdo da propriedade opcao.campo;
v-bind:size - Terá como valor o conteúdo da propriedade opcao.tamanho;
v-bind:readonly - Terá como valor o conteúdo da propriedade opcao.soLeitura;
Código completo
<html>
<head>
<title>Menu Vert.</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript" src="CRUD_menuOpcoes.js"></script>
<script type="text/javascript">
function init(){
// Comando 1
var data = { 
negrito: 'bold',
opcoes: arrOpcoes,
cabecalhos : arrCabecalhos,
cabecalho: 'SUPORTE', 
linque:'',
novoopcao: '',
novoimagem: '',
mostraForm:false,
houveQuadro:false,
action:'form'
};
// Comando 2
var v1 = new Vue({ 
el: '#app', 
data: data,
watch: {
action: {
handler: function (linque) {
console.log("w: "+arguments.callee.name+" vis: "+this.action)
},
deep: true
},
opcoes: {
handler: function (linque) {
console.log("w: "+arguments.callee.name)
},
deep: true
}
},
methods: {
goLink: function (linque,quadro) {
this.action = linque;
if( quadro != '' ){
houveQuadro = true;
} else {
houveQuadro = false;
}
},
viraPagina: function(){ 
this.mostraForm=true; 
}
}
});
setTimeout(function(){v1.viraPagina();}, 1500);
}
</script>
<style>
A,A:link { color: midnightblue; text-decoration: none; }
BIG { font-size: 22px; }
BUTTON {
background-color: white; border-width: 0px; color: midnightblue;
font-weight: bold; width: 200px;
}
DIV#app { font-family: Arial; font-size: 16px; width: 320px; }
H2 { color: midnightblue; font-weight: bold; }
P { color: midnightblue; }
</style>
</head>
<body onload="init();">
<div id="app" class="container">
<div id="cabecalho" v-show="!mostraForm">
<center><h1>CRUD</h1></center>
</div>
<div id="menus" v-show="mostraForm">
<center>
<h2>{{cabecalhos["form"].nome}}</h2>
</center>
<center>
<table border=0>
<tr v-for="opcao in opcoes" v-if="opcao.checked && opcao.secao == action">
<td>
<label v-bind:style="{fontWeight:negrito, color: opcao.cor}">{{ opcao.titulo }}</label>
</td>
<td>
<input v-bind:id="opcao.campo" v-bind:size="opcao.tamanho" v-bind:readonly="opcao.soLeitura" />
</td>
</tr>
</table>
</center>
<div class="footer">
<hr/>
</div>
</div>
</div>
</body>
</html>

CRUD_menuOpcoes.js

var arrOpcoes = [
{ campo: 'Id', tipo: 'N', obrigatorio: 'N', titulo: 'Identificador', tamanho: 6, cor: '#002A36', soLeitura: true, imagem: '', link: '', checked: true, secao: 'form' , destino:'',quadro:''},
{ campo: 'Descri', tipo: 'T', obrigatorio: 'N', titulo: 'Descrição', tamanho: 50, cor: '#003745', soLeitura: false, imagem: '', link: '', checked: true, secao: 'form' , destino:'' ,quadro:''},
{ campo: 'Area', tipo: 'T', obrigatorio: 'S', titulo: 'Área', tamanho: 4, cor: '#003745', soLeitura: false, imagem: '', link: '', checked: true, secao: 'form' , destino:'' ,quadro:''},
{ campo: 'DtNascto', tipo: 'D', obrigatorio: 'N', titulo: 'Data de Nascimento', tamanho: 10, cor: '#003745', soLeitura: false, imagem: '', link: '', checked: true, secao: 'form' , destino:'' ,quadro:''},
{ campo: 'UF', tipo: 'T', obrigatorio: 'N', titulo: 'Uf', tamanho: 2, cor: '#003745', soLeitura: false, imagem: '', link: '', checked: true, secao: 'form' , destino:'' ,quadro:'', multivalue: [{vr:"", descri: "[Escolha a UF]"},{vr:"AC", descri: "Acre"},{vr:"AM", descri: "Amapá"},{vr:"MG", descri: "Minas Gerais"},{vr:"RJ", descri: "Rio de Janeiro"},{vr:"SP", descri: "São Paulo"}]},
{ campo: 'VrNo', tipo: 'N', obrigatorio: 'N', titulo: 'Número', tamanho: 6, cor: '#002A36', soLeitura: false, imagem: '', link: '', checked: true, secao: 'form' , destino:'',quadro:''},
{ campo: '', titulo: 'Caminhante', imagem: 'caminhante.jpg', link: 'none', checked: true, secao: 'traj' ,destino:'' ,quadro:''},    
{ campo: '', titulo: 'Ciclista', imagem: 'ciclista.jpg', link: 'none', checked: true, secao: 'traj' ,destino:'' ,quadro:''}, 
{ campo: '', titulo: 'Cavaleiro', imagem: 'cavaleiro.jpg', link: 'none', checked: true, secao: 'traj' ,destino:'' ,quadro:''},
{ campo: '', titulo: 'SAIR', imagem: '', link: 'main', checked: true, secao: 'traj' ,destino:'' ,quadro:''}
];
var arrCabecalhos = {
form:{nome:"ENTRADA DE DADOS PADRÃO", acao: "" },
traj:{ nome:"MAPA", acao:""}

};

Recomendações

Faça testes com trechos pequenos de HTML5 combinados com o VUE, para ter domínio de seu uso.