Code Monkey home page Code Monkey logo

blog's Issues

当autocomplete遇到中文输入法

当autocomplete遇到中文输入法

1.需求场景

常见的搜索输入框,输入一个字符之后会调用后台的服务传入关键字进行查询。

以往实现,监听输入框的keydown/change事件,当输入参数改变的时候触发keydown事件,获取当前输入的参数然后调用后端服务。

1.1弊端:

  • change事件,必须要等到鼠标焦点离开输入框才会被触发
  • keydown事件则需要配合tab使用才能监听到正确的值(目前我试验是这样的),同时有时候会出现监听值和输入框中的值不匹配的情况

1.2 html5 oninput事件

关于oninput事件

该事件类似于 onchange 事件。不同之处在于 oninput 事件在元素值发生变化是立即触发, onchange 在元素失去焦点时触发。

浏览器兼容性:现代浏览器, IE9+(ie9以下需要用onpropertychange来代替)

1.3 实践

<input type="text" 
    v-model="inputtext"  
    @input="input"
    placeholder="请试试中文输入法和英文输入法">
input: function (val) {
    if (this.inputtext != this.inputvalue) {
        console.log("doquery:" + this.inputtext)
        this.inputvalue = this.inputtext
        //使用inputvalue进行查询
    }
}

查看demo地址

1.4 But Doesn't work In Vue 1.0.26

翻开vue2.1.4 的源码
//vue 2.1.4
//line 5433
el.addEventListener('compositionstart', onCompositionStart);
el.addEventListener('compositionend', onCompositionEnd);

line  5511
function onCompositionEnd (e) {
  e.target.composing = false;
  trigger(e.target, 'input');
}

原来在compositionend之后手动触发了input方法

再打开vue 1.0.26的源码
vue 1.0.26
line 4721
this.on('compositionend', function () {
  composing = false;
  // in IE11 the "compositionend" event fires AFTER
  // the "input" event, so the input handler is blocked
  // at the end... have to call it here.
  //
  // #1327: in lazy mode this is unecessary.
  if (!lazy) {
    self.listener();
  }
});

似乎好像明白了什么

input + compositionend 来联合解决这个问题

<input type="text" 
    v-model="compositiontext" 
    @input="compositioninput" 
    @compositionend="compositionend" placeholder="请试试中文输入法和英文输入法">
compositioninput: function (val) {
    if(this.compositionvalue != this.compositiontext) {
        console.log("do query:" + this.compositiontext)
        this.compositionvalue = this.compositiontext
    }
},
compositionend: function(val) {
    console.log("do query:" + this.compositiontext)
    this.compositionvalue = this.compositiontext
}

查看demo地址

1.5 回过头来看compositionevent

复合事件

复合事件(composition event)是DOM3级事件中新添加的一类事件,用于处理IME的输入序列。IME(Input Method Editor,输入法编辑器)可以让用户输入在物理键盘上找不到的字符。复合事件就是针对检测和处理这种输入而设计的。

  • compositionstart:在IME的文本复合系统打开时触发,表示要开始输入了。

  • compositionupdate:在向输入字段中插入新字符时触发。

  • compositionend:在IME的文本复合系统关闭时触发,表示返回正常键盘的输入状态。

结语: 遇到问题 + 解决问题 = 提升。其实不仅仅是vue,本身input+compositionevent都是解决不同IME输入的统一解决办法

vue1.x升级到vue2.x需要注意的点

  1. ready事件改变(生命周期事件的改变)
    image
    需要把ready改成mounted

  2. : show 缩写貌似不好用了,需要改成v-show来使用

这里其实我有一点混乱,到底是因为我使用组件的问题还是其他问题,后续来更正

  1. props.coerce被废弃

vue1.0中用于属性转换,可以看到在vue-strap里有了大量的使用,主要通过计算属性来解决了

  1. props.sync props.once 被废除了

其实不管是以往在使用vux还是其他第三方组件的时候,使用了大量的.sync来双向绑定,官方的解释是只保留了单向数据流的绑定,如果子组件需要影响父组件则需要通过事件派发的机制,降低了子组件和父组件的耦合

  1. 新增了render function

本质上 render function和写一个模版是等价的,但是具体为什么要新增render,等我深入了解后再来解答吧。

  1. 废弃了 vm.$dispatch和vm.$broadcast

全局事件或vuex代替

  1. 服务器端渲染
    在下才疏学浅,还没有到这个地步。

这里有一个帮助从vue1.x升级到vue2.0的开源项目,号称是能够覆盖80%需要升级的内容,对于老项目来说是一个很不错的选择哦

PS:关于vue2.0 UI框架的选择:

个人目前决定pc端UI框架从vue-strap转移到element UI上,毕竟基于vue2.0开发,而且vue-strap的文档我一直觉得不够友好。另外如果有其他好的项目,也希望大家推荐给我。

[思考]前端工程化方面的计划

  • 很惭愧,虽然做了几年前端,积累了很多的经验,但是在前端工程化领域,总觉得自己还是一个小白,在不断摸索的前进。
  • 最近在摸索如何更彻底的做前后端分离,于是又回到前端工程化的问题上来,也很纠结到底如何去选择去使用。
  • fis3的出现似乎给了我一套看起来比较完整的解决方案,但是也担心如何在实践中逐步去一步步对现有的内容进行改造。不多说持续关注吧。

最近看的几篇文章列一下,开始实践之后再回头来看看
1.你是如何构建 Web 前端 Mock Server 的?
2.web开发模式的演变-玉伯
3.前后端分离思考与实践

[vue]vue+vue-router+es6搭建一个简单的spa应用(一)

vue+vue-router+es6搭建一个简单的spa应用

使用es6+简单的vue componet
点我看效果
1.创建工程,引入依赖

npm init
//引入vue
npm install vue --save-dev
//引入 vue router
npm install vue-router --save-dev

2.创建如下目录结构

assert
build
dist
src
|--pages
|----index
|------index.vue
|----setting
|------setting.vue
|--main.js
test
index.html
package.json

3.index.html结构

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=0">
    <title>vue-router</title>
</head>
<body>
<div id="app">
    <h1>header</h1>
    <hr>
    <!-- 路由外链 -->
    <router-view></router-view>
    <hr>
    <h2>footer</h2>
</div>
<script src="dist/build.js"></script>
</body>
</html>

4.main.js

import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

// 创建一个路由器实例
// 创建实例时可以传入配置参数进行定制,为保持简单,这里使用了一个记住滚动条位置的配置 随意忽略吧
var router = new VueRouter({
    saveScrollPosition: true
})
//定义页面路由,这里url路由切换到/index 会加载index.vue
//然后将组件内容替换html中的<router-view></router-view>
router.map({
    '/index':{
        component:require("./pages/index/index.vue")
    },
    '/setting':{
        component:require("./pages/setting/setting.vue")
    }
})

var App = Vue.extend({})
router.start(App, '#app')

window.router = router

5.index.vue/setting.vue

//index.vue
<script>
    export default {}
</script>
<template>
    <div class="content">
        <p>i am page index</p>
        <a v-link="{path:'/setting'}">跳转到setting</a>
    </div>
</template>
<style scoped>
    p{color:red;}
</style>

//setting.vue
<script>
    export default {}
</script>
<template>
    <div class="content">
        <p>i am page setting2</p>
        <a v-link="{path:'/index'}">index</a>
    </div>
</template>
<style scoped>
    p{color:black;}
</style>

以上,所有的代码就编写完了

6.然后开始配置webpack相关的东西咯,这里不去详解把我package.json的配置直接贴出来了。

基本就是引入babel解析es6 引入vue-loader解析.vue文件,引入vue-hot-reload-api方便开发时候调试。

//依赖配置
  "devDependencies": {
    "babel-core": "^6.10.4",
    "babel-loader": "^6.2.4",
    "babel-plugin-transform-runtime": "^6.9.0",
    "babel-preset-es2015": "^6.9.0",
    "babel-preset-stage-0": "^6.1.2",
    "babel-runtime": "^6.0.0",
    "css-loader": "^0.23.1",
    "style-loader": "^0.13.1",
    "vue-hot-reload-api": "^1.2.0",
    "vue-html-loader": "^1.2.3",
    "vue-loader": "^8.5.3",
    "vue-style-loader": "^1.0.0",
    "webpack": "^1.13.1",
    "webpack-dev-server": "^1.14.1"
  }

//运行配置
"scripts": {
    "dev": "webpack-dev-server --inline --hot --config build/webpack.dev.config.js",
    "build": "webpack --progress --hide-modules --config build/webpack.prod.config.js"
  }

这里要注意一下vue-hot-reload-api的版本,别引入2.x的版本,2.x的版本是专门给vue2.0用的 这点要注意。

7.运行看一看

npm install

npm run build 

npm run dev

然后访问http://localhost:8080/index
点击切换看一看咯,就是如此简单

[翻译]内联布局之内联元素之间的空白

引:flexbox布局的出现解决了以往float布局以及inline-block布局遗留的问题,本文先针对inline-block布局出现的元素间空白的问题做出描述

文章原文:https://css-tricks.com/video-screencasts/

攻克inline-block元素间的空格问题

问题现象:当你对一系列的内联元素进行普通的格式化时,这些内联元素之间就出现了空白。

比如:

HTML

<nav>
  <a href="#">One</a>
  <a href="#">Two</a>
  <a href="#">Three</a>
</nav>

CSS

nav a {
  display: inline-block;
  padding: 5px;
  background: red;
}

结果

点我看图片

我们通常希望这些元素紧密的连接在一起,在使用到导航时不会出现中间不可点击的空白区域。

这其实并不是一个bug(至少作者认为),这只是设置这些元素在同一行显示的一种方式。我们通常也希望在文字和文字之间存在空格以方便阅读。这并不意味着这些文字之间的空格不应该存在,但我相当肯定,如果休整了它就能够解决一系列的问题。

删除空格

产生以上现象的原因,因为你的这些元素之间存在着空格,可能是换行符,也可能是tab产生的空格。压缩html代码可以解决这个问题,或者像下面这样的小戏法

HTML

<ul>
  <li>
   one</li><li>
   two</li><li>
   three</li>
</ul>

或者

HTML

<ul>
  <li>one</li
  ><li>two</li
  ><li>three</li>
</ul>

或者使用注释

<ul>
  <li>one</li><!--
  --><li>two</li><!--
  --><li>three</li>
</ul>

使用margin的负值

你可以给元素设置一个-4px的margin。

nav a {
  display: inline-block;
  margin-right: -4px;
}

忽略结束标签

当然,这会让你感觉怪怪的。

<ul>
  <li>one
  <li>two
  <li>three
</ul>

设置字号大小为0

nav {
  font-size: 0;
}
nav a {
  font-size: 16px;
}

ps:Android端不起作用

使用浮动就好了

或许并不需要把元素设置成inline-block,设置成浮动就好了。你同样可以设置宽度高度padding和其他一些特性,只不过不能使用text-align:center;内敛元素的父元素。你可以这么做,就是还是优点奇怪。

最好的方案,使用flexbox来取代

浏览器支持 的情况下

  • Chrome any
  • Firefox any
  • Safari any
  • Opera 12.1+
  • IE 10+
  • iOS any
  • Android any

关于demo

参考demo

编者注:每个东西出现总有其必然性,了解背后的原因能帮你更好的了解它

[js基础]关于事件冒泡(待续)

学习前端大全的文章,顺带了解一下自己并不懂的时间冒泡,需要好好把js的基础知识恶补一下了。

事件流包含三个部分:事件捕获,处于目标,事件冒泡

  • 事件捕获
    事件捕获从document元素开始,从上而下的过程,越高级的父级元素越早接收到事件,
    常见的坑:
    • 新插入的子元素没有绑定点击事件(具体怎么解决,用事件委托,委托给他的父级容器)

    • 如果目标有子元素,怎么办?

      event.target可能变成了他的子元素,这里有一个css的解决方式,假定li.item 是要绑定的元素;

li.item > *{
      pointer-events:none;
}

实际上以上常见的坑在jquery已经都帮我们处理掉了,就安心的直接使用delegate或者

$("ul").on("click","li.item",function(events){
    //do your things
})

就可以了

利用json-server搭建本地mock-server

前后端分离之本地mock-server

前后端分离之后,前端不依赖于后端服务的进度,在前后端定义好json接口之后,就可以开始开发了。

基于json-server我们可以很方便的定义好本地调用的restful服务,然后在前端通过proxy,修改服务调用即可。

json-server:Github地址

  • 安装json-server
$ npm install -g json-server
  • 简单的例子:
  1. 在目录下创建一个 db.json
{
  "posts": [
    { "id": 1, "title": "json-server", "author": "typicode" }
  ],
  "comments": [
    { "id": 1, "body": "some comment", "postId": 1 }
  ],
  "profile": { "name": "typicode" }
}
  1. 运行json-server
$ json-server --watch db.json

默认json-server会启动本地3000端口。
通过访问http://localhost:3000/posts/1, 会返回以下数据

{ "id": 1, "title": "json-server", "author": "typicode" }
  1. 使用routes

以当前项目例子,实际后台服务访问路径为

http://localhost/yuncai/qutate/loaddata

然后json-server 初步使用发现json-server好像不支持超过三层路径的访问

{
  "qutate/getdata": [
    { "id": 1, "title": "json-server", "author": "typicode" }
  ],
  "yuncai/qutate/loaddata": [
    { "id": 1, "body": "some comment", "postId": 1 }
  ],
  "profile": { "name": "typicode" }
}

通过以上定义的db.json

通过下面的url,可以正常返回数据。

http://localhost:3000/qutate/getdata

但通过下面的url则返回结果为{}

http://localhost:3000/yuncai/qutate/loaddata

还没有深入研究详细原因,目前暂时通过配置routes.json的方式来解决。

1. 在本地创建routes.json
2. 启动参数改成 json-server db.json --watch --routes routes.json
3. 访问http://localhost:3000/yuncai/qutate/loaddata 成功返回数据
  1. get请求里带请求的访问
http://localhost:3000/qutate/getdata/1 //返回id 为1 的数据

http://localhost:3000/qutate/getdata?title=json-server //返回title字段等于json-server的数据

以上就能用最简单的方式搭建起本地的mock-server 进行前后端分离的调试啦。
本地可以使用proxy或者nginx都可以进行跳转啦,详细的会在下一篇文章进行介绍

vue pr Code Style

一入vue 终身脑残粉

vue pull request code style

持续关注vue 2.0(github vue-next 分支下的内容)

于是关注到 readme 中的 Pull Request Guidelines中关于代码风格的描述,原文如下:

  • No semicolons unless necessary.
  • Follow JSDoc.
  • 2 spaces indentation.
  • multiple var declarations.
  • 1 space after function and function names.
  • 1 space between arguments, but not between parentheses.
  • Break long ternary conditionals like this:

翻译如下:

  • 尽量不使用分号
  • 遵循JSDoc规范
  • 使用两个空格做为字符缩进
  • (我不太确定这里的意思,是否是如下代码的意思,将变量分开定义)
// good way
var variable1 = "Hello World!";
var variable2 = "Testing...";
var variable3 = 42;
// not recommend way
var variable1 = "Hello World!",
    variable2 = "Testing...",
    variable3 = 42;
  • 再function和函数名之间使用一个空格
  • 参数与参数之间使用一个空格(不包括圆括号)
  • 如下使用三目运算符
var a = superLongConditionalStatement
  ? 'yep'
  : 'nope'
  • 遇到疑惑时,读一下源代码

总结启示再使用eslint的时候以上的代码风格都是需要遵循的,所以这里看完后并没有太多严格的地方,最严格的在最后一句,读源代码,参考它原有的方式

[vue]vue学习and云采超市app实践(一、vue基础)

为什么选择vue,因为实在太轻量,太好学了。里面组件化开发的**再加上指令和过滤器,以及自带的一些动画效果,上手起来比react学习成本低很多,在已有hybrid app的经验下结合移动的场景非常适合,并且和第三方框架集成的也很好。后续会逐步结合正在做的云采超市app 点我看演示demo04/a111111 ,从一个更简化的思路去学习vue。PS:官方文档写的很棒,大家可以进行参考。

<div id="app">
  {{ message }}
</div>
new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue.js!'
  }
})

最终效果

Hello Vue.js!
  • 绑定列表
<div id="app">
  <ul>
    <li v-for="todo in todos">
      {{ todo.text }}
    </li>
  </ul>
</div>
new Vue({
  el: '#app',
  data: {
    todos: [
      { text: 'Learn JavaScript' },
      { text: 'Learn Vue.js' },
      { text: 'Build Something Awesome' }
    ]
  }
})
  • 双向数据绑定,事件绑定
<div id="app">
<input v-model="newTodo" v-on:keyup.enter="addTodo">
</div>
new Vue({
  el: '#app',
  data: {
    newTodo: '',
    todos: [
      { text: 'Add some todos' }
    ]
  },
  methods: {
    addTodo: function () {
      var text = this.newTodo.trim()
      if (text) {
        this.todos.push({ text: text })
        this.newTodo = ''
      }
    }
  }
})

以上就是一个最简单的vue的数据绑定的简单实例,利用这些就可以完成最简单的双向数据绑定的例子了。
ps:关于重复绑定,在构造vue实例 new Vue()的时候会指定需要绑定到的元素el:"#app" ,之前在使用knockout的时候存在限制,相同的元素或自元素不允许存在重复绑定。但对于vue来说,目前暂时好像没有遇到此类限制,不过后续用到组件化开发的过程还是会通过不同组件的作用域来处理此类问题的。

[函数式编程]小记(1).纯函数

《js函数式编程》
书在这,先拿去自己看。
书里面提到 了一些简要的概念,乘热打铁。
1.纯函数。
所为纯函数就是同样的输入永远产生同样的输出,不会受到任何输入值的影响,这样的函数就是纯函数。纯函数的好处,当然就是上下文简单,可测试,可预测。
举个例子

function add(a,b){
   return a+b
}

再来看一个不纯的函数

var count = 0
function addwithCount(a,b){
     count++
     return a + b + count
}

很明显第一次调用addwithCount(0,1)和第二次调用addWithCount(0,1)明显产生的结果是不一样的。

这里不纯的函数就会产生副作用,至于具体的副作用那就看代码有多不纯了。
哦啦 一次学的东西不要太多,我们后续会慢慢展开讨论。
当然 第一次看这书的时候我对于书里的习题是一列懵逼不会写的。所以还是要多实践。
下一节见

[移动]混合式应用真机调试

在做混合式App/web app 通常一般开发时会通过chrome或者android/ios模拟器进行调试。
但实际上有些问题在chrome和模拟器上跑的好好的,放到真机上就见了鬼了。所以怎么在真机上调试就真是一件很头疼的事,以下结合自己在做移动应用时的实践经验简单分享一下。

  • Android调试
    拿数据线把手机连上你的电脑,然后允许usb调试,然后打开chrome,浏览器中输入chrome://inspect 然后在列表中找到你的设备,点击inspect(我也忘了具体是不是这个按钮了),然后就可以打开chrome开发者工具进行愉快的调试了。
    要求
    Android>4.0
    Chrome>32
    打开手机中的开发者选项中的USB调试
    不过好像貌似第一次需要翻墙然后会自动下载驱动。。。反正做前端的还是都去买一个翻墙代理吧
  • IOS调试
    这个需要有一个前提:
    你需要有一个mac。对的 需要一个mac。
    然后把你的iphone连上你的电脑,打开手机safari,输入你要访问的网址,然后在mac的safari-开发 下打开你的设备,默认会列出当前你手机访问的网址,就可以借助safari的调试工具进行真机调试了。

以上,不论是直接用chrome访问,还是打开app使用app里内嵌的webview 都是可以做到真机调试的。
如果有遇到问题欢迎反馈。
希望对大家有用。

[工具]敏捷开发的一些工具推荐

推荐一款目前团队在用的一个在线敏捷看板
leangoo
目前来说基本能满足我的需求:
场景、故事、工作量、团队成员、检查项(需求验证条目)、截止时间、标签、燃尽图
毕竟有一个敏捷看板对于当前项目所处状态的把握还是很好的。

关于敏捷开发是否重要,当然不是我本文需要讨论的内容,毕竟敏捷开发对于快速迭代的好处毋庸置疑。如何更好的使用工具去辅助我门的开发事一件必然的事情。

不断学习进步中

=====
不愿意的加班的前端不是好前端,好前端是会找办法让团队尽量少的加班的。
=====

如何使用webpack里的CommonsChunkPlugin插件

如何使用webpack里的CommonsChunkPlugin插件

CommonsChunkPlugin用于将一个传统的js应用拆分成不同的模块,并在重用公共依赖的模块

为什么要使用CommonsChunkPlugin?

它非常适合用于开发一个由很多页面组成的应用(无论是传统的页面或者是页面路由)

1.单入口文件

在使用webpack时,通常会把所有的代码都打包到一个入口文件entry.js 之中。当项目规模比较小的时候并没有什么,但如果项目规模比较大里之后,这就意味着在不同页面会有一堆无用的代码被引用。

//不存在代码分割
entry.js
 - app
 - page1
 - page2 
 - jquery
 - underscore
 - moment

2.多页面文件

进行代码分隔之后在entry.js之中只需要引入启动工程所必须的代码,对于每一个页面则只引入页面需要的代码。

entry.js
 - app
 - jquery
 - underscore

page1.js
 - page1
 - jquery
 - moment

page2.js
 - page2
 - underscore

问题:jquery和underscore引用重复了

CommonsChunkPlugin的出现就是为了更高效的解决这些外部的依赖关系

3.优化后的结构

entry.js
 - app
 - jquery
 - underscore

page1.js
 - page1
 - moment

page2.js
 - page2

在这个示例中,juqery和underscore因为众多页面都有对它的依赖,所以移入了入口文件entry.js之中。

提取可重用依赖

在webpack中,通过给plugin添加一个webpack.optimize.CommonsChunkPlugin实例来实现,如下:

// webpack configuration
const webpack = require("webpack");
module.exports = {
  entry: {
    entry: './app.js'
  },
  output: {
    ...
  },
  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      // name of the entry chunk to scan for common (shared) dependencies
      // the common dependencies will be moved into this entry chunk
      name: 'entry',
      // indicate that we want to scan for common dependencies in
      // child (code split) chunks of the named entry chunk
      children: true,
      // minimum number of different chunks (entry or split) which a dependency
      // must be used by to deem it a common dependency
      minChunks: 2
    })
  ]
};

关于其他更多的CommonsChunkPlugin的配置请看
http://webpack.github.io/docs/list-of-plugins.html#commonschunkplugin

ps:后续会更新vue-cli 创建的webpack模板的例子解析

[vue]vue学习and云采超市app实践(三、vue组件)

什么是组件

vue组件在这里是可扩展的html自定义元素,封装可复用的代码。比如

<div id="example">
  <my-component></my-component>
</div>

使用组件

  • 组件注册
var MyComponent = Vue.extend({
  // 选项...
})
// 全局注册组件,tag 为 my-component
Vue.component('my-component', MyComponent)
  • 局部注册
var Child = Vue.extend({ /* ... */ })

var Parent = Vue.extend({
  template: '...',
  components: {
    // <my-component> 只能用在父组件模板内
    'my-component': Child
  }
})

Props

组件实例的作用域是孤立的。这意味着不能并且不应该在子组件的模板内直接引用父组件的数据。可以使用 props 把数据传给子组件。

  • 声明props
Vue.component('child', {
  // 声明 props
  props: ['msg'],
  // prop 可以用在模板内
  // 可以用 `this.msg` 设置
  template: '<span>{{ msg }}</span>'
})
  • 传入参数
<child msg="hello!"></child>
  • 动态props
<child v-bind:my-message="parentMsg"></child>
  • props绑定类型
    props默认是单向绑定,当父组件的属性变化时,将传导给子组件,但是反过来不会,防止子组件改变父组件属性。不过也支持通过.sync 或 .once 绑定修饰符显式地强制双向或单次绑定。

关于父子组件的通信

  • 父子组件通信
    • 1.父链:通过this.$parent访问父组件;
    • 2.自定义事件
    • 3.v-on 绑定自定义事件
      不详细描述了 看官方文档里组件页的详细介绍吧

通过slot对组件进行组合

例子:

<app>
  <app-header></app-header>
  <app-footer></app-footer>
</app>

疑问:如果app下也有自己的模板,怎么处理。

父组件模板

<my-component>
  <p>This is some original content</p>
  <p>This is some more original content</p>
</my-component>

子组件(my-component)模板

<div>
  <h1>This is my component!</h1>
  <slot>
    如果没有分发内容则显示我。
  </slot>
</div>

渲染结果

<div>
  <h1>This is my component!</h1>
  <p>This is some original content</p>
  <p>This is some more original content</p>
</div>

如果没有slot,渲染结果

<div>
  <h1>This is my component!</h1>
</div>

====
以上就是个人觉得初识vue需要了解到的vue 组件相关的一些细节,其实还有很多详细的内容,都欢迎到官网进行查看吧。

下一篇计划是介绍一下vue-router并结合vue-router来做一个spa webapp,敬请期待咯

[vue]vue学习and云采超市app实践(二、事件监听、过滤器)

上篇主要简单介绍了vue简单数据绑定的一些基础,本篇对vue的事件监听、指令和过滤器做一些简单的介绍。

事件监听

  • v-on指令监听dom事件
<div id="example">
  <button v-on:click="greet">Greet</button>
</div>

同时在js里定义这个方法

var vm = new Vue({
  el: '#example',
  data: {
    name: 'Vue.js'
  },
  // 在 `methods` 对象中定义方法
  methods: {
    greet: function (event) {
      // 方法内 `this` 指向 vm
      alert('Hello ' + this.name + '!')
      // `event` 是原生 DOM 事件
      alert(event.target.tagName)
    }
  }
})

ps:你也可以在js里这么调greet方法

vm.greet();

在html中监听事件的好处

    1. 轻松定位js中的方法
    1. viewmodel与html解藕,方便测试
    1. viewmodel销毁时,事件自动销毁不用担心重复绑定和事件注销的问题

自定义过滤器

  • 全局注册过滤器
Vue.filter('reverse', function (value) {
  return value.split('').reverse().join('')
})
  • 使用过滤器
<!-- 'abc' => 'cba' -->
<span v-text="message | reverse"></span>

综合以上例子,过滤器可常用于,显示格式的转换,比如价格显示精度处理,格式转化等等通用场景都可以使用过滤器的方式来处理

  • 双向过滤器(把input输入框的值写回成转换filter转化之前的值)
Vue.filter('currencyDisplay', {
  // model -> view
  // 在更新 `<input>` 元素之前格式化值
  read: function(val) {
    return '$'+val.toFixed(2)
  },
  // view -> model
  // 在写回数据之前格式化值
  write: function(val, oldVal) {
    var number = +val.replace(/[^\d.]/g, '')
    return isNaN(number) ? 0 : parseFloat(number.toFixed(2))
  }
})

另外过滤器还支持动态参数。具体详细查看 动态参数
===============下章节计划介绍component的内容===============

提问的智慧

《提问的智慧》
如何提问,如何描述一个问题,如何降低沟通成本。
有时候开发老反馈,测试提的问题描述看不懂。
我做过一年的测试,对这方面也感触颇深,降低沟通成本,让对方更容易懂你,绝对是对双方都有好处的。推荐看一看上面这本《提问的智慧》,会让你收获颇多。

css水平垂直居中在实际中的应用

前端面试过程中经常都会问一个问题:一个元素如何实现水平垂直居中?

这里我们抛开技术层面的实现,直接从实际业务角度,通过不同的场景来回答这个问题,毕竟任何技术都是为了业务服务的,有了具体业务,也方便我们更好的去实践。

  • 场景1:文章的标题需要水平居中
  • 场景2:table中文字垂直居中
  • 场景3:弹出模态框需要水平垂直居中
  • 场景4:图标+文字,文字要和图标对齐

直接看代码,所有demo地址

场景1

<article>
    <p class="title"><span>我是title</span></p>
    <p class="content">我是文章的内容,我通常来说会有多段去显示</p>
</article>

<style>
.demo1 .title{
    text-align: center;
}
</style>

场景2

<table>
        <thead>
        <th>姓名</th>
        <th>年龄</th>
        <th>性别</th>
        <th>个人描述</th>
        </thead>
        <tbody>
        <tr>
            <td>张三</td>
            <td>18</td>
            <td>男</td>
            <td>我通常来说会超过一行所能显示的内容</td>
        </tr>
        <tr>
            <td>张三</td>
            <td>18</td>
            <td>男</td>
            <td>我通常来</td>
        </tr>
        </tbody>
    </table>
<style>
table td{
    border:solid 1px #eee;
    vertical-align: middle;
    text-align: center;
}
</style>

当然多数浏览器下table默认是会垂直居中的,这里只是为了引入下面对table-cell的使用

<div class="demo-cell">
    <div class="table-like">
        <div class="table-cell-like">
            姓名
        </div>
        <div class="table-cell-like">
            年龄
        </div>
        <div class="table-cell-like">
            性别
        </div>
        <div class="table-cell-like">
            描述
        </div>
    </div>
    <div class="table-like">
        <div class="table-cell-like">
张三
        </div>
        <div class="table-cell-like">
18
        </div>
        <div class="table-cell-like">
男
        </div>
        <div class="table-cell-like">
我要超过两行了哦我要超过两行了哦我要超过两行了哦
        </div>
    </div>
</div>
<style>
.table-like{
    display: table;
    width: 400px;
}
.table-cell-like{
    display: table-cell;
    text-align: center;
    vertical-align: middle;
}
</style>

利用display:table 就能像表格一样使用vertical-align来实现垂直居中了

ps:table-cell只是可以用来做这个,但并不是最适合用做垂直居中的

场景3

弹出的模态框一般来说都是通过绝对定位来做,即:postion:absolute/fixed,所以基本可以用下面的方法实现。

<div class="demo3">
    <div class="modal-ab">
        假设我是一个弹出的模态框 <br>如果当弹出框高度和宽度是固定值的时候,<br>可以使用     <br>margin-left:-弹框width%;<br>
        margin-top:-弹框height%; <br>来支持ie8.
    </div>
</div>
<style>
.demo3{
    position: relative;
    width: 500px;
    height: 300px;
    border:solid 1px #eee;
}
.demo3 .modal-ab{
    position: absolute;
    top:50%;
    left:50%;
    width: 200px;
    height: 120px;
    border:solid 1px #000000;
    text-align: left;
    padding:10px;
    -webkit-transform: translateX(-50%) translateY(-50%);
    -moz-transform: translateX(-50%) translateY(-50%);
    -ms-transform: translateX(-50%) translateY(-50%);
    transform: translateX(-50%) translateY(-50%);
}
</style>

这种方式启示算是一种通用方式,利用定位来做垂直水平居中(IE9+),当然,在IE8中如果已知元素高宽是可以用margin负值的方式去实现的,如下:

.demo3 .modal-ab{
    position: absolute;
    top:50%;
    left:50%;
    width: 200px;
    height: 120px;
    margin-left: -100px;
    margin-top:-60px;
}

场景4

图标和文字对齐(不使用position:relative)

<h2>图标大 文字小</h2>
<div class="demo4">
    <span class="fa fa-edit big" ></span><span class="small">我是文字</span>
</div>
<h2>图标小 文字大</h2>
<div class="demo4">
    <span class="fa fa-edit small"></span><span class="big">我是文字</span>
</div>
<style>
.demo4 .big{
    vertical-align: middle;
}
</style>

场景4中,因为inline-block默认的vertical-align是baseline,所以会产生底部和文字底部对齐的现象,所以需要设置成middle来保证垂直居中。启示以前我都是一直用postion:relative的方式来处理这个问题。

[移动]一个移动端扫码插件(二维码、条形码等)

最近手头上正在开发的app需要用到扫码功能,于是上用上了这一个cordova的插件目前来说适配ios以及安卓的效果还不错。推荐下大家尝试使用。

  • 关于cordova
    这就不去详细描述里,参考[cordova官网](http://cordova.apache.org/
  • 关于barcodescanner
    插件地址
  • 如何使用
    1. 通过npm安装corodva并在本地创建一个cordova工程,并添加platform:android/ios
    2. cordova plugin add phonegap-plugin-barcodescanner
    3. 核心代码:
cordova.plugins.barcodeScanner.scan(
      function (result) {
          alert("We got a barcode\n" +
                "Result: " + result.text + "\n" +
                "Format: " + result.format + "\n" +
                "Cancelled: " + result.cancelled);
      }, 
      function (error) {
          alert("Scanning failed: " + error);
      },
      {
          "preferFrontCamera" : true, // iOS and Android
          "showFlipCameraButton" : true, // iOS and Android
          "prompt" : "Place a barcode inside the scan area", // supported on Android only
          "formats" : "QR_CODE,PDF_417", // default: all but PDF_417 and RSS_EXPANDED
          "orientation" : "landscape" // Android only (portrait|landscape), default unset so it rotates with the device
      }
   );
4. 注意事项:scan方法需要在deviceReady之后调用
     document.addEventlisterner('deviceready',onDeviceReady,false);
     function onDeviceReady(){
           //here bind event to click to use camera to scan barcode
     }

html中需要通过script引入cordova.js(执行cordova build android之后在asserts目录下就能找到对应的文件)

  • 如果需要把文件放倒服务器端进行加载,请确保拷贝的文件包含以下目录:cordova-js-src 不同平台生成的对应文件不一样,请进行确认(build后自动生成的文件)

[实践]前后端分离:通过本地nginx配置来实现分离后cas认证服务的集成

  • 背景
    当前在做的一个手机app/微信webapp,需要集成已有的网页版cas用户登录(不要问我为什么,因为没有资源把登录重新做一遍),这样就涉及到怎么把手机端的静态代码分离成单独的前端工程,也方便后续的手机app打包(目前先不考虑手机打包app啦,还会有各种坑)
  • 分析
    由于cas用户认证,以及回写客户端cookie需要后端java代码的支持,所以只好把这部分事情老老实实交给后端去做,而又为了保证登录后cookie能正确写入到当前开发态的域下面,所以当前采用了nginx本地配置跳转的方式来实现。
  • 最终效果
    本地开发访问localhost/mall-cli-portal/mobilelogin 实际跳转到xxx.com/mall-cli-portal/mobilelogin,被cas拦截后,完成用户登录,并把cookie回写到当前域(localhost)之下,然后localhost/mall/mobilelogin会执行url跳转到localhost/mobile/market/index/index.html(就是对应本地移动开发对应的页面),这样就能愉快的在localhost里取到cookie了。
  • nginx配置
location /mall-cli-portal{
        proxy_pass    http://songhlc:9001/mall-cli-portal;
        proxy_set_header Host localhost;
        proxy_set_header X-Real-IP  $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        add_header From localhost;
        proxy_set_header Cokkie $http_cookie;
        proxy_redirect default ;
}
location /mobile{
        proxy_pass    http://localhost:63342/mobile/web/src/main/webapp/static;
        proxy_redirect default
 }

如上,开发环境就可以通过简单本地nginx的配置解决这个问题啦,然后线上环境就不用管了,本来就在同一个域下嘛。done,愉快的进行前后端分离了。

  • 遗留问题
  • 后续如何判断登录失效(手动注销以及关闭浏览器之后)
  • 集成微信openid的免登
  • 好像还有一个,我忘了

[思考]关于当前前端团队的一些困惑和反思

回顾

团队从最终一个人到现在初具规模,一开始大家都是全栈,前端代码,写到dubbo服务,写到mybatis脚本,到代码自动构建、线上版本,开发版本、测试版本的初步稳定,走了很多坑。但毕竟我还是要专注到前端上来,所以借此来好好总结一下。

现状

关于加班

  • 我始终认为,不加班的前端不是好前端;好前端是加班是为了团队更好的不加班
  • 加班也一定要拿出时间来更好的总结

    关于反思

  • 1.经历了几次功能开发的迭代,如何更佳优化业务流程,产品从设计到前端实现到最终上线的流程需要作出哪些改进
  • 2.在迭代过程总是否有一些积累,公共服务、工具类是否能抽象出来
  • 3.如何去做一个好的前后端分离
  • 4.合适构建工具的选择
  • 5.UI库的沉淀
  • 6.如何形成优化体系
  • 7.如何形成统计体系

反思自我答疑

  • 1.从最开始的大家都是全栈,到现在前端工作拆分成(静态页面/jsview通用结构 + js页面逻辑),至少把大部分人都不太熟悉的CSS剥离出来,让更专业的前端去维护页面,当然后续还有更长的路要走。
  • 2.一直在抽象,一直在剥离出公共服务。从最早页面生命周期模型的搭建,到公共common.js的不同扩充,再到针对UE优化自己编写的一些jquery插件。总之抽象公共组件的过程是永远停不下来的。
    待完成的组件:文件上传下载组件、地区地址组件、下拉参照(非弹框组件)
  • 3.关于前后端分离,在不考虑seo的情况下(毕竟当前还是没有需要),nodejs暂时就不是那么必要了。
    需要尝试下这几种方式,哪一种是最适合的。
1.fiddler&charles做代理
2.提供测试服务器
3.支持jsonp跨域
4.支持cors跨域
  • 4.关于合适的构建工具,fis3刚看到时真是让我眼前一亮,但是对于代码的侵入似乎并不友好,是不是还是应该回到gulp构建的老路上去,很纠结,盼解答。
  • 5.UI库的沉淀,毕竟是基于inspina那套bootstrap主题在做,但是遇到了官网门户的问题,所以需要借助超市化采购来沉淀一套官网门户用的主题。
  • 6.再摸索吧
  • 7.现在还没想好要统计什么,一切以解决实际问题为例,已有的一些监控都是后端的,前端如何去做一些监控和统计呢?

思路并不清晰,只希望在前端的路上越来越快的成长

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.