node.js 使用ejs模板引擎时后缀换成.html

1
app.set('view engine', 'jade');

换成

1
2
3
4
//将引擎修改为html
var jade = require('jade');//在app.js的头上定义jade
app.engine('html',jade.__express);//注册html模板引擎
app.set('view engine', 'html');//将模板引擎换成html

修改模板文件的后缀为.html。

JavaScript常用API总结

下面是我整理的一些JavaScript常用的API清单。

目录

元素查找
class操作
节点操作
属性操作
内容操作
css操作
位置大小
事件
DOM加载完毕
绑定上下文
去除空格
Ajax
JSON处理
节点遍历
元素查找

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Node
document.getElementById(id) // document.getElementById('test')
document.querySelector(selectors) // document.querySelector('#test div')
document.doctype
document.documentElement
document.head
document.title
document.body
// NodeList
document.getElementsByClassName(names) // document.getElementsByClassName('test')
document.getElementsByName(name) // document.getElementsByName('demo')
document.getElementsByTagName(name) // document.getElementsByTagName('div')
document.getElementsByTagNameNS(namespace, name) // document.getElementsByTagNameNS('http://www.w3.org/1999/xhtml', 'div')
document.querySelectorAll(selectors) // document.querySelectorAll('#test div')
document.links
document.scripts
document.images
document.embeds
document.forms

class操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// ie8
// add class
el.className += ' ' + className;
// has class
function hasClass(el,className){
return new RegExp('(^| )' + className + '( |$)', 'gi').test(el.className);
}
// toggle class
function toggleClass(el,className){
var classes = el.className.split(' ');
var existingIndex = -1;
for (var i = classes.length; i--;) {
if (classes[i] === className){
existingIndex = i;
}
}
if (existingIndex >= 0){
classes.splice(existingIndex, 1);
}
else{
classes.push(className);
}
el.className = classes.join(' ');
}
// remove class
function remove(el,className){
el.className = el.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
}
// ie 10
el.classList.add(className); // add class
el.classList.remove(className); // remove class
el.classList.contains(className); // has class
el.classList.toggle(className); // toggle class

节点操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
// 创建
var el = document.createElement(name);
// 复制
el.cloneNode(true); // 默认为false(克隆节点及其后代), true(克隆节点及其属性,以及后代)
// 向节点添加最后一个子节点
parent.appendChild(el);
// 在指定子节点之前插入新的子节点
parent.insertBefore(el, parent.childNodes[0]);
// insertAdjacentHTML方法
el.insertAdjacentHTML(where, htmlString);
el.insertAdjacentHTML('beforeBegin', htmlString); // 在该元素前插入
el.insertAdjacentHTML('afterBegin', htmlString); // 在该元素第一个子元素前插入
el.insertAdjacentHTML('beforeEnd', htmlString); // 在该元素最后一个子元素后面插入
el.insertAdjacentHTML('afterEnd', htmlString); // 在该元素后插入
// 父元素
el.parentNode
// 删除节点
el.parentNode.removeChild(el);
// 兄弟节点 ie9+
var siblings = Array.prototype.filter.call(el.parentNode.children, function(child){
return child !== el;
})
// 下一个兄弟节点
// ie8
function nextElementSibling(el) {
do { el = el.nextSibling; } while ( el && el.nodeType !== 1 );
return el;
}
nextElementSibling(el);
// ie9+
el.nextElementSibling;
// 上一个兄弟节点
// ie8
function previousElementSibling(el) {
do {
el = el.previousSibling;
}
while ( el && el.nodeType !== 1 );
return el;
}
previousElementSibling(el);
// ie9+
el.previousElementSibling;
// Children
// ie8
var children = [];
for (var i = el.children.length; i--;) {
// Skip comment nodes on IE8
if (el.children[i].nodeType != 8)
children.unshift(el.children[i]);
}
// ie9+
el.children

属性操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 获取属性值
el.getAttribute('alt');
// 设置属性值
el.setAttribute('alt', '图片描述');
内容操作
// 获取元素内容
el.innerHTML
// 设置元素内容
el.innerHTML = string
// 获取元素内容(包含元素自身)
el.outerHTML
// 设置元素内容(包含元素自身)
el.outerHTML = string
// 获取文本内容
// ie8
el.innerText
// ie9+
el.textContent
// 设置文本内容
// ie8
el.innerText = string
// ie9+
el.textContent = string

CSS操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
// 获取css样式
// ie8
el.currentStyle[attrName]
// ie9+
window.getComputedStyle(el)[attrName]
// 伪类
window.getComputedStyle(el , ":after")[attrName];
// 设置CSS样式
el.style.display = 'none';
位置大小
// getBoundingClientRect返回一个对象,包含top,left,right,bottom,width,height
// width、height 元素自身宽高
// top 元素上外边界距窗口最上面的距离
// right 元素右外边界距窗口最上面的距离
// bottom 元素下外边界距窗口最上面的距离
// left 元素左外边界距窗口最上面的距离
// width 元素自身宽(包含border,padding)
// height 元素自身高(包含border,padding)
// 元素在页面上的偏移量
var rect = el.getBoundingClientRect()
return {
top: rect.top + document.body.scrollTop,
left: rect.left + document.body.scrollLeft
}
// 元素自身宽(包含border,padding)
el.offsetWidth
// 元素自身高(包含border,padding)
el.offsetHeight
// 元素的左外边框至包含元素的左内边框之间的像素距离
el.offsetLeft
// 元素的上外边框至包含元素的上内边框之间的像素距离
el.offsetTop
//通常认为 <html> 元素是在 Web 浏览器的视口中滚动的元素(IE6 之前版本运行在混杂模式下时是 <body> 元素)
//因此,带有垂直滚动条的页面总高度就是 document.documentElement.scrollHeight
// 在没有滚动条的情况下,元素内容的总高度
scrollHeight
// 在没有滚动条的情况下,元素内容的总宽度
scrollWidth
// 被隐藏在内容区域左侧的像素数。通过设置这个属性可以改变元素的滚动位置
scrollLeft
// 被隐藏在内容区域上方的像素数。通过设置这个属性可以改变元素的滚动位置
scrollTop
// 视口大小
// ie9+
var pageWidth = window.innerWidth,
pageHeight = window.innerHeight;
if (typeof pageWidth != "number"){
// ie8
if (document.compatMode == "CSS1Compat"){
pageWidth = document.documentElement.clientWidth;
pageHeight = document.documentElement.clientHeight;
} else {
// ie6混杂模式
pageWidth = document.body.clientWidth;
pageHeight = document.body.clientHeight;
}
}

事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// 绑定事件
// ie9+
el.addEventListener(eventName, handler , Booleans); // Booleans默认false(事件在冒泡阶段执行),true(事件在捕获阶段执行)
// ie8
el.attachEvent('on' + eventName, function(){
handler.call(el);
});
// 移除事件
// ie9+
el.removeEventListener(eventName, handler);
// ie8
el.detachEvent('on' + eventName, handler);
// 事件触发
if (document.createEvent) {
// ie9+
var event = document.createEvent('HTMLEvents');
event.initEvent('change', true, false);
el.dispatchEvent(event);
} else {
// ie8
el.fireEvent('onchange');
}
// event对象
var event = window.event||event;
// 事件的目标节点
var target = event.target || event.srcElement;
// 事件代理
ul.addEventListener('click', function(event) {
if (event.target.tagName.toLowerCase() === 'li') {
console.log(event.target.innerHTML)
}
});
DOM加载完毕
function ready(fn) {
if (document.readyState != 'loading'){
// ie9+
document.addEventListener('DOMContentLoaded', fn);
} else {
// ie8
document.attachEvent('onreadystatechange', function() {
if (document.readyState != 'loading'){
fn();
}
});
}
}

绑定上下文

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// ie8
fn.apply(context, arguments);
// ie9+
fn.bind(context);
去除空格
// ie8
string.replace(/^\s+|\s+$/g, '');
// ie9+
string.trim();
ajax
// GET
var request = new XMLHttpRequest();
request.open('GET', 'user.php?fname=Bill&lname=Gates', true); // false(同步)
request.send();
// ie8
request.onreadystatechange = function() {
if (this.readyState === 4) {
if (this.status >= 200 && this.status < 400) {
// Success!
var data = JSON.parse(this.responseText);
} else {
// 错误
}
}
};
// ie9+
request.onload = function() {
if (request.status >= 200 && request.status < 400) {
// Success!
var data = JSON.parse(request.responseText);
} else {
// 服务器返回出错
}
};
request.onerror = function() {
// 连接错误
};
// POST
var request = new XMLHttpRequest();
request.open('POST', 'user.php', true); // false(同步)
request.setRequestHeader("Content-type","application/x-www-form-urlencoded");
request.send(dataString);

JSON处理

1
2
JSON.parse(string);
JSON.String(Object)

节点遍历

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function forEach( nodeList, callback ) {
if(Array.prototype.forEach){
// ie9+
Array.prototype.forEach.call( nodeList, callback );
}else {
// ie8
for (var i = 0; i < nodeList.length; i++){
callback(nodeList[i], i);
}
}
}
forEach(document.querySelectorAll(selector),function(el, i){
})

Vue.js实践:一个Node.js+mongoDB+Vue.js的博客内容管理系统

项目来源
以前曾用过WordPress搭建自己的博客网站,但感觉WordPress很是臃肿。所以一直想自己写一个博客内容管理器。

正好近日看完了Vue各个插件的文档,就用着Vue尝试写了这个简约的博客内容管理器(CMS)。

完成的功能

  • 一个基本的博客内容管理器功能,如后台登陆,发布并管理文章等 支持markdown语法编辑
  • 支持代码高亮
  • 可以管理博客页面的链接
  • 博客页面对移动端适配优化
  • 账户管理(修改密码)
  • 页面足够大气、酷炫~

于是,为了彰显一贯的酷炫,我给后台写了一套星空主题。。。

登陆页面

这里写图片描述

后台管理页面

这里写图片描述
但博客页面最后没用后台的星空主题,主要是觉得黑色不太好搭配。

于是我想,既然前端都是用Vue.js写的,那就参chao考xi一下Vue.js尤雨溪的博客样式吧!

在这基础上博客页面又加了自己写的canvas动画,应该是足够优雅了~
这里写图片描述

Demo

登陆后台按钮在页面最下方“站长登陆”,可以以游客身份登入后台系统。

源码

用到的技术和实现思路
前端:Vue全家桶

1
2
3
4
5
6
7
Vue.js
Vue-Cli
Vue-Resource
Vue-Validator
Vue-Router
Vuex
Vue-loader

后端

1
2
3
Node.js
mongoDB (mongoose)
Express

工具和语言

1
2
3
4
Webpack
ES6
SASS
Jade

整体思路

1
2
3
Node服务端除了主页外,不做模板渲染,渲染交给浏览器完成
Node服务端不做任何路由切换的内容,这部分交给Vue-Router完成
Node服务端只用来接收请求,查询数据库并用来返回值

所以这样做前后端几乎完全解耦,只要约定好restful风格的数据接口,和数据存取格式就OK啦。

后端我用了mongoDB做数据库,并在Express中通过mongoose操作mongoDB,省去了复杂的命令行,通过Javascript操作无疑方便了很多。

简单的说一下Vue的各个插件:

1
2
3
4
5
6
Vue-Cli:官方的脚手架,用来初始化项目
Vue-Resource:可以看作一个Ajax库,通过在跟组件引入,可以方便的注入子组件。子组件以this.$http调用
Vue-Validator:用来验证表单
Vue-Router:官方的路由工具,用来切换子组件,是用来做SPA应用的关键
Vuex:控制组件中数据的流动,使得数据流动更加清晰,有迹可循。通过官方的vue-devtools可以无缝对接
Vue-loader:webpack中对Vue文件的加载器

文件目录
这里写图片描述
我将前端的文件统一放到了src目录下,其中的mian.js是webpack的入口。

所有页面分割成一个单一的vue组件,放在componentss中,通过入口文件mian.js,由webpack打包生成,生成的文件放在public文件夹下。

后端文件放在server文件夹内,这就是基于Express的node服务器,在server文件夹内执行

1
node www

就可以启动Node服务器,默认侦听3000端口。
关于Vue-Cli
我只是使用了simple的template,相对于默认的template,simple的配置简单得多,但已经有了浏览器自动刷新,生产环境代码压缩等功能。

1
vue init simple CMS-of-Blog

以下是Vue-Cli生成的webpack的配置文件,我只做了一点小改动。

话说React.js里就没用像Vue-Cli这样好用的脚手架,还是Vue.js简单优雅。。


Webpack.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
var path = require('path')
var webpack = require('webpack')
module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, './public'),
publicPath: '/public/',
filename: 'build.js',
},
resolveLoader: {
root: path.join(__dirname, 'node_modules'),
},
module: {
loaders: [
{
test: /\.vue$/,
loader: 'vue'
},
{
test: /\.js$/,
loader: 'babel',
exclude: /node_modules/
},
{
test: /\.json$/,
loader: 'json'
},
{
test: /\.html$/,
loader: 'vue-html'
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'url',
query: {
limit: 10000,
name: '[name].[ext]?[hash]'
}
}
, {
test: /\.(woff|svg|eot|ttf)\??.*$/,
loader: 'url-loader?limit=50000&name=[path][name].[ext]'
}
]
},
babel: {
presets: ['es2015'],
},
devServer: {
historyApiFallback: true,
noInfo: true
},
devtool: '#eval-source-map'
}
if (process.env.NODE_ENV === 'production') {
module.exports.devtool = '#source-map'
// http://vue-loader.vuejs.org/en/workflow/production.html
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
output: {
comments: false,
},
compress: {
warnings: false
}
}),
new webpack.optimize.OccurenceOrderPlugin()
])
}

可以看出尤大大帮我们把浏览器自动刷新,热加载和生产环境的代码压缩都写好了,简直超贴心。

然而实际项目中,我还是碰到一个麻烦的问题,下面是package.json中的script脚本

1
2
3
4
5
6
"scripts": {
"dev": "webpack-dev-server --inline --hot",
"build": "cross-env NODE_ENV=production webpack --progress --hide-modules",
"watch": "webpack --progress --color --watch",
"server": "supervisor ./server/www"
},

运行

1
npm run dev

后,浏览器在8080端口开了一个服务器,然而这个服务器是用来服务前端页面的,也就是说,从这里启动服务器而不是开启Node服务器会造成数据无法交互,毕竟这个服务器不能连接数据库。但这个端口是可以在文件修改之后自动刷新浏览器的。

然后,通过分别执行

1
2
npm run watch
npm run server

来侦听文件改动,并重启Node服务器,此时浏览器是不能自动刷新的。找了一些方法但终归没解决。习惯了自动浏览器刷新,碰到这种情况蛮蛋疼的。

于是只好这样:

在修改样式的时候使用8080端口的服务器,在修改数据交互的时候手动刷新在3000端口服务器的浏览器。

虽然不是很方便,但至少通过supervisor不用自己重启Node服务器了。。。

关于Vue-Router
因为写的是但也应用(SPA),服务器不负责路由,所以路由方面交给Vue-Router来控制。

下面是根组件,路由控制就在这里,组件挂载在body元素下:

main.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
let router = new VueRouter()
router.map({
'/': {
component: Archive
},
'login': {
component: Login
},
'/article': {
component: Article
},
'/console': {
component: Console,
subRoutes: {
'/': {
component: ArticleList
},
'/editor': {
component: Editor
},
'/articleList': {
component: ArticleList
},
'/menu': {
component: Links
},
'account': {
component: Account
},
},
},
})
let App = Vue.extend({
data(){
return {}
},
components: {Waiting,Pop,NightSky,MyCanvas},
http: {
root: '/'
},
computed: {
waiting: ()=>store.state.waiting,
pop:()=>store.state.popPara.pop,
bg:()=>store.state.bg,
},
store
})
router.start(App, 'body')

对应的文档首页 index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<title>Blog-CMS</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<waiting v-if="waiting"></waiting>
<pop v-show="pop"></pop>
<component :is="bg"></component>
<router-view></router-view>
<script src="public/build.js"></script>
</body>
</html>

可以看到路由控制在body元素下的router-view中。之前的waiting,pop和component元素分别是等待效果(就是转圈圈)的弹出层,信息的弹出层,和背景样式的切换。

其实这个index.html是有express通过jade生成的,实际项目中并没有html文件,我是把生成好的html放在这里方便展示。

关于Vue-loader
Vue-loader是Vue官方支持webpack的工具,用来将组件写在一个文件里。之前的目录中,有很多分割好的vue文件,每一个文件是一个独立的组件。

比如,这是一个弹出层的组件:

Pop.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<template>
<div class="shade">
<div class="content">
<p>{{getPopPara.content}}</p>
<div class="button">
<button class="ok" @click="ok">确定</button>
<button class="cancel" @click="cancel"
v-if="getPopPara.cb2">取消
</button>
</div>
</div>
</div>
</template>
<script>
import {getPopPara} from '../vuex/getters'
export default{
vuex: {
getters: {
getPopPara,
}
},
methods: {
ok(){
let fn = this.getPopPara.cb1
typeof fn == 'function' && fn()
},
cancel(){
let fn = this.getPopPara.cb2
typeof fn == 'function' && fn()
}
}
}
</script>
<style lang="sass">
@import "../SCSS/Pop.scss";
</style>

每一个vue文件都有三个部分(其实是可选的),分别是template,script和style,这也很好理解,就是把html,JS和CSS合并在一起写了嘛。

这个弹窗组件,通过vuex获得其他组件传递过来的参数,参数是一个对象,包括弹出层的展示信息和点击确定或取消时的回调函数。

因为编辑器不支持在vue文件中用sass语法,所以我把sass文件放在外部,通过@import引入。

关于Vue-Resource
Vue-Resource可以看成一个与Vue集成的Ajax库,用来创建xhr和获取xhr的response。

因为和Vue高度集成,所以在vue组件中使用很方便。

Article.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<template>
<div class="wrap">
<my-header></my-header>
<section class="article">
<article class="post-block">
<div class="post-title">{{title}}</div>
<div class="post-info">{{date}}</div>
<div class="post-content"
v-html="content | marked">
</div>
</article>
</section>
<my-footer></my-footer>
</div>
</template>
<script>
import myHeader from './MyHeader.vue'
import myFooter from './MyFooter.vue'
import marked from '../js/marked.min.js'
import {bgToggle} from '../vuex/actions'
export default{
data(){
return {
title: '',
date: '',
content: ''
}
},
filters: {
marked
},
created(){
let id = this.$route.query.id
this.$http.get('/article?id=' + id)
.then((response)=> {
let body = JSON.parse(response.body)
this.content = body.content
this.title = body.title
let d = new Date(body.date)
this.date = d.getFullYear() + '年' +
(d.getMonth() + 1) + '月' +
d.getDate() + '日'
}, (response)=> {
console.log(response)
})
},
components: {
myHeader,
myFooter
},
ready(){
this.bgToggle('MyCanvas')
},
vuex:{
actions:{
bgToggle
}
}
}
</script>
<style lang="sass">
@import "../SCSS/Article.scss";
</style>

Article.vue组件种在created生命周期时创建并发送了一个xhr的get请求,在获取成果后把response对象中的属性在赋值给data中相应的属性,vue会自动更新视图。

博客所支持的markdown语法的关键所在也在这个组件里。

1
2
3
<div class="post-content">
{{{content | marked}}}
</div>

通过引入markdown的filter使得输出的html直接被转换成html结构,还是很方便的。

关于后端
后端是用node.js作为服务器的,使用了最流行Express框架。

主体是由Express生成,本身十分精简。在实践中修改的地方主要是添加了各种前端发送的get和post请求。

1
2
3
4
5
6
7
8
9
10
router.get('/article', function (req, res, next) {
var id = req.query.id
db.Article.findOne({_id: id}, function (err, doc) {
if (err) {
return console.log(err)
} else if (doc) {
res.send(doc)
}
})
})

比如这个请求处理来自前端的get请求,通过mongoose来查询数据库并返回数据。

前端页面通过promise控制异步操作,把得到的数据放入组件的data对象中,Vue侦测变化并更新视图。

数据库的初始化文件放在了init.js中,第一次运行的时候会新建名为admin的用户,初始密码为111,可以在控制台的账号管理中修改。

后记
其实还有很多很多没有在这篇文章提及的地方。毕竟这个博客框架相对是比较大的东西。

写过这个博客管理器后,感受还是蛮多的,对Vue.js中的数据绑定,组件化和数据流了解的更深入了一层,同时也对Node.js的后端有了一次优雅的实践。

所以,学过东西之后,实践是非常有必要的。前端很多时候就是不断踩坑的过程。一路踩坑再爬坑,获益匪浅。。。

怎么在页面里引入bootstrap的css和js文件呢?

怎么在页面里引入bootstrap的css和js文件呢?
这里写图片描述
这是一个nodejs+express工程 在npm install之后或使用npm install bootstrap命令安装bootstrap之后,怎么在views/index.ejs文件中引入bootstrap.css文件呢?

在app.js里面引入这句

1
app.use("/lib",express.static(path.join(__dirname, 'node_modules')));

制定程序的lib库文件目录
然后在ejs里的路径里直接写/lib/bootstrap/dist/js/bootstrap.min.js等,你的node_modules文件夹中的bootstrap包里面的文件就会被映射,因为 这个__dirname 已经是获取当前模块文件所在目录的完整绝对路径。

web开发时自动刷新网页:liveReload安装,sublime 3

需要插件
sublime text3:View in Browser;LiveReload

chrome:liveReload

配置方法

一:sublime text3

sublime 3下载地址:

http://download.csdn.net/download/reggergdsg/9541966

1、在sublime text3安装插件 view in browser

注意(安装插件之前先安装Package Control:
http://blog.csdn.net/weixin_36401046/article/details/52880000,
http://devework.com/sublime-text-3-package-control.html)

1
ctrl+shift+p
1
输入install package回车

jojo's blog

1
view in browser

2、安装成功后,修改默认的浏览器:

1
preferences->package setting->view in browser->setting default

把firefox改为chrome64

jojo's blog

3、在sublime text3安装插件liveReload

1
ctrl+shift+p
1
输入install package回车
1
liveReload

jojo's blog

4、liveReload配置

1
preferences -> Packge Settings -> LiveReload -> Settings - Default

jojo's blog

输入以下内容保存即可

1
2
3
4
5
6
{
"enabled_plugins": [
"SimpleReloadPlugin",
"SimpleRefresh"
]
}

二、 chrome浏览器安装liveReload插件

1、

1
方法一:进入chrome插件中心,搜索liveReload,安装即可。

jojo's blog

1
方法二:如果进不到插件中心,下载安装包安装到chrome浏览器:

http://download.csdn.net/download/weixin_36401046/9659158

2、进入chrome扩展程序页面,将livereload中的允许访问文件网址打上勾

jojo's blog

三、测试
重新打开sublime text3,重新启动chrome。
在sublime text3编辑一个测试html文件,

1
2
3
4
5
6
7
<html>
<meta charset="UTF-8">
<body>
<h1>开心</h1>
<p>自动刷新</p>
</body>
</html>

按 ctr+alt+v 在chrome浏览器中运行,编辑器下方出现livereload提示,并且点击chrome浏览器的livereload图标中间小圆点由虚变实,说明配置成功。

jojo's blog

重点内容:只需要在sublime text3里编辑代码,按 ctr+s 保存,即可在chrome里面看到实时更新。

jojo's blog

如果没有成功自动刷新,把以下走一遍:

1、找到packages文件夹

jojo's blog

jojo's blog

2、从https://github.com/Grafikart/ST3-LiveReload 下载压缩包到本地

3、解压, 重命名为LiveReload,拷贝到packages中

参考文献:http://blog.csdn.net/neet007/article/details/51694643

hexo主题sausage

sausage是基于Yilia二次开发完成的.

关于主题

基于Yilia做的主要工作是删减, 包括:

  1. 左侧栏删除导航切换和下方的icon链接;

    私以为: 这些都可以放到 关于我 页面没必要在每个左侧栏都显示.

  2. 删除一些不必要的修饰元素, 比如文章信息标签前的树叶icon, 日期icon, 包裹文章整体的边框, more链接;

    一些不必要的修饰元素会干扰文章的阅读, 在列表页点击文章标题已经可以到达文章正文了就没必要再添加一个more链接.

  3. 删除手机端的顶部固定导航菜单;

    一是Yilia本身处理有触摸冲突问题, 二是干扰阅读.

当然除了删减外还是做了一点表面工作:

  1. CDN支持, 便于静态资源使用CDN加速, 也对样式修改后更好发版作出了支持(对于想要直接改主题源码的人来说);

  2. 文章内容是否可选的控制, 只是阻挡一下小白随意拷贝文章内容;

  3. 单篇文章控制是否开启评论功能, 相类似的控制包括是否标记为原创等, 后面作出具体说明;

  4. 单独生成标签页面;

使用

安装

1
git clone https://github.com/qbeenslee/hexo-theme-sausage.git themes/sausage

配置

一般情况下Hexo工程目录结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|A|_config.yml
|B|db.json
|C|node_modules

|D|package.json
|E|public

|F|scaffolds
|G| |draft.md
|H| |page.md
|I| |post.md
|J|source

|K|themes
|L| |sausage
|M| |_config.yml
|N| |layout

|O| |source

修改Hexo根目录下_config.yml (A文件)来应用本主题.

1
theme: sausage

修改主题目录下_config.yml (M文件)来配置本主题, 这里对几个主要的配置做个说明:

Key参数说明
CDN_PATH链接(可选)CDN仓库的地址, 比如http://xxxx.clouddn.com/static/ 下保存了和public(E)目录里生成全部静态资源
theme_version字符串(可选)避免CDN缓存造成的样式更新不及时, 现在仅支持style.css文件
avatar链接显示在左侧栏上方的环形头像(PC端)
apple_touch_icon链接桌面icon
shortcut_icon链接标签栏icon
aboutme链接(可选)链接到关于我, 在页面最下端个人表示会添加超链接
copyright链接(可选)如果文章开启了 original: true会对版权说明做超练级
duoshuo字符串(可选)填上多说的short_name
content_selectabletrue/false全局控制内容是否可选
fold_commentstrue/false是否全局折叠评论(不是移除, 可点击查看评论展开评论)

单篇文章属性配置

举个例子:

1
2
3
4
5
6
7
8
9
10
11
title: 技术博客整理
date: 2015-10-24 01:29:12
updated: 2015-10-24 01:29:12
original: false
top: true
categories: mobile
selectable: true
tags:
- android
- 技术博客
- 整理

主要的几个参数说明

key参数说明
originaltrue/false是否为原创文章, 为true是会在文章的右下方显示本文为原创,转载请遵守本站版权声明
selectabletrue/false文章内容是否可选, 只能防小白…
noDatetrue/false是否显示日期

简洁的多说评论

登录到多说后台, 设置 -> 基本设置 -> 自定义css

拷贝simple-duoshuo中的css文件内容, 保存即可.

生成标签页

需要手动生成一个page, hexo new page ‘tag’

编辑markdown文件内容如下:

1
2
3
4
5
6
7
title: 标签
original: false
comments: false
noDate: true
layout: post
selectable: false

hexo+github(windows版+ssh版),搭建Hexo博客并部署到Github

ssh优点:http部署时每次要输入github用户名密码,ssh不需要。
首先走完http版http://blog.csdn.net/weixin_36401046/article/details/52942683

设置SSH keys

1、在Git Bash输入以下指令(任意位置点击鼠标右键),检查是否已经存在了SSH keys。
ls -al ~/.ssh

2、如果不存在就没有关系,如果存在的话,直接删除.ssh文件夹里面所有文件:
jojo's blog

3、生成密钥:(与接下来的3二选一即可)

git config –global user.email “429359876@qq.com” # 填写你github注册并且验证的邮箱

git config –global user.name “jasmine-na” # github 用户名

ssh-keygen # 会出现下面的内容,一直按Enter键就行

Generating public/private rsa key pair.
Enter file in which to save the key (/home/logan/.ssh/id_rsa):
/home/logan/.ssh/id_rsa already exists.
Overwrite (y/n)? #因为我已经生成过了所以提示我,你就一直按就行

最后在你的.ssh 目录下面生成 id_rsa(私钥) id_rsa.pub(公钥)俩个文件

第二行会提示你在哪个目录下面生成文件。

3、生成密钥另外一种方法:
输入以下指令(邮箱就是你注册Github时候的邮箱)后,回车:

ssh-keygen -t rsa -C “429359876@qq.com”

jojo's blog

然后它会提示要你输入passphrase,直接回车:

jojo's blog

然后键入以下指令:

ssh-agent -s

jojo's blog

继续输入指令:

ssh-add ~/.ssh/id_rsa

输入之后,出错:
jojo's blog

出错,则输入:

eval ssh-agent -s
ssh-add

jojo's blog

4、打开.ssh/id_rsa.pub,全选复制Key
jojo's blog

5、到Github
jojo's blog

jojo's blog

jojo's blog

6、测试:

ssh -T git@github.com

jojo's blog

遇到警告输入“yes”,
最后输出 You’ve successfully authenticated 表示添加key 成功。

编辑_config.yml文件

修改文件里面的deploy,

修改后

1
2
3
4
deploy:
type: git
repo: git@github.com:jasmine-na/jasmine-na.github.io.git
branch: master

完成部署
1、 依次键入指令:

hexo clean

hexo generate

hexo deploy

2、在浏览器输入:http://jasmine-na.github.io/

jojo's blog

更多文章:
hexo+github(windows版+http版),搭建Hexo博客并部署到Github

hexo+github(windows版+http版),搭建Hexo博客并部署到Github

jojo's blog

工具/原料
• Windows(Mac也是差不多,可参照)
• Git
• Node.js

安装Hexo

1、利用 npm 命令即可安装。在任意位置点击鼠标右键,选择Git Bash。

jojo's blog

2、输入命令:

npm install -g hexo

注意:-g是指全局安装hexo。

创建Hexo文件夹

1、新建文件夹 Hexo
2、

cd Hexo

hexo init //Hexo 即会自动在目标文件夹建立网站所需要的所有文件。

npm install //安装依赖包

本地查看
• 现在我们已经搭建起本地的hexo博客了,执行以下命令(在Hexo文件夹下),然后到浏览器输入localhost:4000看看。

hexo generate

hexo server

jojo's blog

注册Github账号
• 这里不演示了。

创建Repository仓库

登录github后,

jojo's blog

jojo's blog

jojo's blog

• 注意:创建的时候注意Repository的名字。比如我的Github账号是jasmine-na,那么我应该创建的Repository的名字是:jasmine-na.github.io
(必须是Github账号名.github.io)

jojo's blog

修改配置文件
1、到你刚刚创建的Repository下,找到以下内容:

jojo's blog

2、先点击HTTPS,然后复制里面的地址。然后编辑_config.yml文件(在C:\Hexo下)。
jojo's blog

3、修改文件里面的deploy。其中的repository就改成你刚刚复制的地址。保存这个文件。

1
2
3
4
deploy:
type: git
repo: https://github.com/jasmine-na/jasmine-na.github.io.git
branch: master

jojo's blog

(注意格式)

完成部署

1、下载hexo-deployer-git

npm install hexo-deployer-git –save

2、最后一步,Git Bash下,依次键入以下指令:
(注意:每次修改本地文件后,都需要依次键入以下指令)

hexo clean //清除缓存文件 db.json 和已生成的静态文件 public

hexo generate //生成网站静态文件到默认设置的 public 文件夹

hexo deploy //自动生成网站静态文件,并部署到设定的仓库。

hexo deploy过程中会提示你输入账号名和密码,Username是你的Github账号名称,而不是邮箱;Password就是你的Github的密码。

jojo's blog

2、OK,我们的博客就已经完全搭建起来了,在浏览器输入(当然,是你的用户名):
http://jasmine-na.github.io/

jojo's blog

Tips
• hexo现在支持更加简单的命令格式了,比如:

hexo g == hexo generate

hexo d == hexo deploy

hexo s == hexo server

hexo n == hexo new

更多文章:
hexo+github(windows版+ssh版),搭建Hexo博客并部署到Github