AngularJS的增删改查、state嵌套案例,不涉及服务端
本篇实践一个案例,大致是:左边有导航菜单,右边显示列表,并可对列表项编辑或删除,也可添加新的列表项。借此,可体会到:如何组织可扩展的AngualrJS文件结构,如何点击左侧菜单项右侧显示相应内容,angular-ui-router的使用以及嵌套state,增删改查,等等。
大致如下:
当点击添加按钮:
当点击更新按钮:
文件结构
node_modules/
src/
.....app/
..........categories/
...............categories.js <包含一个名称为categories的module>
...............categories.tmpl.html <左侧的导航菜单>
...............bookmarks/
....................bookmark.js <包含一个名称为categories.bookmarks的module>
....................bookmarks.tmpl.html <右侧的列表项>
....................create/
.........................bookmark-create.js <包含一个名称为categories.bookmarks.create的module>
.........................bookmark-create.tmpl.html <添加表单>
....................edit/
.........................bookmark-edit.js <包含一个名称为categories.bookmarks.edit>
.........................bookmark-edit.tmpl.html <更新表单>
..........common/
...............models/
....................bookmarks-model.js <包含一个名称为darren.models.bookmarks的module>
....................categoires-model.js <包含一个名称为darren.models.categories的module>
..........app.js <包含一个名称为darren的module>
.....asserts/
..........css/
...............animation.css <有关state对应视图间切换的动画效果>
...............darren.css <项目css>
...............normalize.css
..........img/
...............logo.png
.....data/
..........bookmarks.json <右侧列表的json数据>
..........categories.json <左侧菜单的json数据>
.....vendor/
..........angular-ui-router.min.js
..........lodash.min.js
index.html
modules
modules之间的相互依赖如图:
万剑归一,所有的module都和名称为Darren的主module产生了联系。
index.html
<!--引用的css--> <link rel="stylesheet" href="assets/css/normalize.css"/>
<link rel="stylesheet" href="../node_modules/bootstrap/dist/css/bootstrap.min.css"/>
<link rel="stylesheet" href="assets/css/eggly.css"/>
<link rel="stylesheet" href="assets/css/animations.css"/> <!--左侧菜单->
<div ui-view="categories"></div> <!--右侧列表-->
<div ui-view="bookmarks"></div> <!--引用的js--> <script src="../node_modules/jquery/dist/jquery.min.js"></script>
<script src="../node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
<script src="vendor/lodash.min.js"></script>
<script src="../node_modules/angular/angular.min.js"></script>
<script src="../node_modules/angular-animate/angular-animate.min.js"></script>
<script src="vendor/angular-ui-router.min.js"></script> <!--以下引用js的顺序和module之间的依赖关系基本一致-->
<script src="app/app.js"></script>
<script src="app/categories/categories.js"></script>
<script src="app/categories/bookmarks/bookmark.js"></script>
<script src="app/categories/bookmarks/create/bookmark-create.js"></script>
<script src="app/categories/bookmarks/edit/bookmark-edit.js"></script>
<script src="app/common/models/bookmarks-model.js"></script>
<script src="app/common/models/categories-model.js"></script>
以上,<div ui-view="categories"></div>和<div ui-view="bookmarks"></div>的数据从某个state中来,再具体定义state之前,首先先定义一个抽象的state,是在app.js中定义的。
app.js
名称为Darren的主module就定义在这里,并在module中定义了一个抽象sate,以便state的继承和嵌套。
angular.module('Darren', ['ngAnimate',
'ui.router',
'categories',
'categories.bookmarks'
])
.config(function($stateProvider, $urlRouterProvider){ //默认情况下导航到首页
$stateProvider
.state('darren',{
url: '',
abstract: true
});
$urlRouterProvider.otherwise('/');
})
;
现在,应该到具体的state了,把index.html中<div ui-view="categories"></div>和<div ui-view="bookmarks"></div>的数据显示出来,但我们还没有看过数据源呢,本项目的数据源是以json形式存在的。
数据源
categories.json
[
{"id": 0, "name": ""},
{"id": 1, "name": ""},
{"id": 2, "name": ""},
{"id": 3, "name": ""}
]
bookmarks.json
[
{"id":0, "title": "", "url": "", "category": "" },
{"id":1, "": "", "url": "", "category": "" },
...
]
接下来就是对这些数据的操作,所有针对category和bookmark的操作都放在了service中。
categories-model.js
这里定义了针对category的service。
angular.module('darren.models.categories',[])
.service('CategoriesModel', function($http, $q){ var model=this,
URLS={
FETCH:'data/categories.json'
},
categories,
currentCategory; model.getCategoires = function(){ //如果categories存在,使用$q返回promise
//如果不存在才去提取数据
return (categories) ? $q.when(categories) : $http.get(URLS.FETCH).then(cacheCategories);
} function extract(result){
return result.data;
} function cacheCategories(result){
categories = extract(result);
return categories;
} model.getCategoryByName = function(categoryName){
var defered = $q.defer(); function findCategory(){
return _.find(categories, function(c){
return c.name == categoryName;
});
} if(categories){
defered.resolve(findCategory());
} else{
model.getCategoires()
.then(function(result){
defered.resolve(findCategory());
});
} return defered.promise;
}; model.setCurrentCategory = function(categoryName){
return model.getCategoryByName(categoryName)
.then(function(category){
currentCategory = category;
});
}; model.getCurrentCategory = function(){
return currentCategory;
} model.getCurrentCategoryName = function(){
return currentCategory ? currentCategory.name : '';
}; })
;
以上,
● 对外提供了getCategories方法
如果categories存在,通过$q.when返回promise,如果categories不存在,通过或$http.get结合then返回一个promoise。
● 对外提供了getCategoryByName方法,根据categoryName获取category
通过$q.defer返回一个deferred对象,通过defered.promise返回promise。其中定义了一个内部函数findCategory,通过lodash的find方法获取到要找的category,如果categories存在,就使用deferred.reslove当前category, 如果categories不存在,就调用getCategories方法获取到categories后在defered.resolve。
● 对外提供了setCurrentCategory方法
把获取到的category赋值给了一个currentCategory变量。当点击界面上左侧菜单项的时候需要调用这个方法。
● 对外提供了getCurrentCategory方法
实际是返回currentCategory这个变量值。
● 对外getCurrentCategoryName方法
如果currentCategory变量值为null,就返回空字符串,如果不是null,那就返回currentCategory的name字段值。
接下来,就是针对bookmark的servcie。
bookmarks-model.js
angular.module('darren.models.bookmarks',[])
.service('BookmarksModel', function($http, $q){
var model = this,
bookmarks,
URL={
FETCH: 'data/bookmarks.json'
}; //获取
model.getBookmarks = function(){ var deferred = $q.defer(); if(bookmarks){
deferred.resolve(bookmarks);
} else{
$http.get(URL.FETCH).then(function(bookmarks){
deferred.resolve(cacheBookmarks(bookmarks));
});
} return deferred.promise;
} function extract(result){
return result.data;
} function cacheBookmarks(result){
bookmarks = extract(result);
return bookmarks;
} //创建
model.createBookmark = function(bookmark){
bookmark.id = bookmarks.length;
bookmarks.push(bookmark);
} //根据编号查找
function findBookmark(bookmarkId){
return _.find(bookmarks, function(bookmark){
return bookmark.id === parseInt(bookmarkId, 10);
});
} model.getBookmarkById = function(bookmarkId){
//创建defered object
var deferred = $q.defer(); if(bookmarks){
deferred.resolve(findBookmark(bookmarkId));
} else{
model.getBookmarks().then(function(){
deferred.resolve(findBookmark(bookmarkId));
});
} return deferred.promise;
} //更新
model.updateBookmark = function(bookmark){
var index = _.findIndex(bookmarks, function(b){
return b.id == bookmark.id;
}); bookmarks[index] = bookmark;
} //删除
model.deleteBookmark = function(bookmark){
_.remove(bookmarks, function(item){
return item.id == bookmark.id;
});
}
})
;
以上,
● 对外提供getBookmarks方法
也是返回以promise类型的bookmarks。
● 对外提供createBookmark方法,接受bookmark形参
就是给bookmark赋一个id值,然后放到当前的bookmarks数组中。
● 对外提供getBookmarkById方法,根据bookmarkId形参获取
返回一个promise的bookmark。
● 对外提供updateBookmark,接受bookmark形参
使用lodash的findIndex方法获取当前bookmark在数组中的索引值,再根据这个索引值为对应的数组元素赋上新值。
● 对外提供deleteBookmark方法,接受bookmark形参
使用lodash的remove方法删除数组元素。
好了,数据源以及操作数据的各种方法都具备了,现在就到了路由,控制器等了。
category.js
还记得首页<div ui-view="categories"></div>和<div ui-view="bookmarks"></div>中的数据还没着落吗?其实是在这里定义的。
angular.module('categories',[
'darren.models.categories'
])
.config(function($stateProvider){
$stateProvider
.state('darren.categories',{
url: '/',
views: {
//target the ui-view named categories in root state
'categories@':{
controller: 'CategoriesCtrl as categoriesListCtrl',
templateUrl: 'app/categories/categories.tmpl.html'
},
//target the ui-view named 'bookmarks' in root state to show all bookmarks for all categories
'bookmarks@':{
controller: 'BookmarksCtrl as bookmarksListCtrl',
templateUrl: 'app/categories/bookmarks/bookmarks.tmpl.html'
}
}
});
})
.controller('CategoriesCtrl', function CategoriesCtrl(CategoriesModel){
var categoriesListCtrl = this; CategoriesModel.getCategoires()
.then(function(result){
categoriesListCtrl.categories = result;
}); })
;
以上,
● 定义了一个名称为darren.categories的state
url: '/'表示首页url路径,views字段中定义了两组controller和templateUrl的配对。categories@对应首页视图中的<div ui-view="categories"></div>,bookmarks@对应首页视图中的<div ui-view="bookmarks"></div>。
在 controller: 'CategoriesCtrl as categoriesListCtrl'中,CategoriesCtrl这个控制器有了别名,也就意味着如果在界面中调用CategoriesCtrl就使用它的别名categoriesListCtrl。
现在,有关state的关系如下:
当在首页,即路径是/,首先经过类型为abstract名称为darren的state,然后来到darren.categories(这里的书写格式符合惯例:上一级.下一级)这个state,页面上的<div ui-view="categories"></div>找到这里的categories@字段,就让categorieslistCtrl负责为categories.tmpl.html这个视图提供数据。
<div ui-view="bookmarks"></div>找到这里的bookmarks@字段,让bookmarksListCtrl和bookmarks.tmpl.html配对,可这里的问题是:bookmarksListCtrl并不在categories这个module中,到底是去哪里找bookmarksListCtrl了?
● 定义了控制器,对外通过了categores这个字段
在控制器中注入了CategoriesModel这个service,通过该service获取到数据。
categories.tmpl.html
这里即是首页左侧菜单。
<ul>
<!--判断是否为选中的category,逻辑是点击当前的category,把这个category保存在$scope.currentCategory中,再判断当前的category是否和$scope.currentCategory相等,相等就为选中状态。就像非常勿扰女嘉宾按灯,系统就记录下当前按灯的桌号,系统再遍历所有的桌号,如果桌号和系统记录的桌号相等,就让该桌号的灯亮起来,道理是一样一样滴。-->
<li ng-repeat="category in categoriesListCtrl.categories">
<a ui-sref="darren.categories.bookmarks({category:category.name})">
{{category.name}}
</a>
</li>
</ul>
以上,好玩的是ui-sref="darren.categories.bookmarks({category:category.name}),也就是说,当点击左侧的某个菜单项,就指向darren.categories.bookmarks这个state,并带着参数category,之所以把category的name键值传递出去,是因为在右侧列表项要显示点击了哪个类别。
darren.categories.bookmarks这个state被定义在了bookmark.js中了。
bookmark.js
angular.module('categories.bookmarks',[
'categories.bookmarks.create',
'categories.bookmarks.edit',
'darren.models.bookmarks'
])
.config(function($stateProvider){
$stateProvider
.state('darren.categories.bookmarks',{
url: 'categories/:category',
views: {
'bookmarks@':{
templateUrl: 'app/categories/bookmarks/bookmarks.tmpl.html',
controller:'BookmarksCtrl as bookmarksListCtrl'
}
}
});
}) //不需要$scope的写法
.controller('BookmarksCtrl', function($stateParams,BookmarksModel,CategoriesModel){
var bookmarksListCtrl = this; CategoriesModel.setCurrentCategory($stateParams.category); BookmarksModel.getBookmarks()
.then(function(bookmarks){
bookmarksListCtrl.bookmarks = bookmarks;
}); bookmarksListCtrl.getCurrentCategory = CategoriesModel.getCurrentCategory;
bookmarksListCtrl.getCurrentCategoryName = CategoriesModel.getCurrentCategoryName;
bookmarksListCtrl.deleteBookmark = BookmarksModel.deleteBookmark; })
;
以上,在categories.tmpl.html中点击菜单项(ui-sref="darren.categories.bookmarks({category:category.name}))传递出的category是和这里的categories/:category对应。
具体来说,当点击菜单项(ui-sref="darren.categories.bookmarks({category:category.name})),来到darren.categories.bookmarks这个state,且url符合categories/:category格式,stateParams把url中的category存储下来,首页上的<div ui-view="bookmarks"></div>找到bookmarks@字段,最终把bookmarksListCtrl和bookmarks.tmpl.html匹配。
另外,在category.js中,还提到了这样的一个问题:bookmarksListCtrl并不在categories这个module中,到底是去哪里找bookmarksListCtrl了?在这里也找到了答案,当在categories这个module中没有bookmarksListCtrl的时候,会按照darren→darren.categores→darren.categores.bookmarks整条线路找到bookmarks$对应的controller和view的匹配。
bookmarks.tmpl.html
<!--不使用$scope的写法,给controller别名的写法-->
<h1>{{bookmarksListCtrl.getCurrentCategoryName()}}</h1> <!--对bookmarks进行了过滤,过滤的标准是bookmark的字段category-->
<div ng-repeat="bookmark in bookmarksListCtrl.bookmarks | filter:{category:bookmarksListCtrl.getCurrentCategoryName()}">
<button type="button" class="close" ng-click="bookmarksListCtrl.deleteBookmark(bookmark)">×</button>
<button type="button" class="btn btn-link" ui-sref="darren.categories.bookmarks.edit({bookmarkId: bookmark.id})">更新</button>
<a href="{{bookmark.url}}" target="_blank">{{bookmark.title}}</a>
</div>
<hr/>
<!-- CREATING -->
<ui-view ng-if="bookmarksListCtrl.getCurrentCategory()">
<button type="button" ui-sref="darren.categories.bookmarks.create">添加</button>
</ui-view>
以上,
点击更新按钮,ui-sref="darren.categories.bookmarks.edit({bookmarkId: bookmark.id})",来到了darren.categories.bookmarks.edit这个state,并带上了bookmarkId这个参数,这个state被定义在了bookmark-edit.js中了。
点击添加按钮。ui-sref="darren.categories.bookmarks.create",来到darren.categories.bookmarks.create这个state,这个state被定义在了bookmark-create.js中了。
即<ui-view></ui-view>中显示的内容有可能是添加的内容,也有可能是更新的内容。
bookmark-edit.js
angular.module('categories.bookmarks.edit',[])
.config(function($stateProvider){
$stateProvider
.state('darren.categories.bookmarks.edit',{
url: '/bookmarks/:bookmarkId/edit',
templateUrl: 'app/categories/bookmarks/edit/bookmark-edit.tmpl.html',
controller: 'EditBookmarkCtrl as editBookmarkCtrl'
});
})
.controller('EditBookmarkCtrl', function($state, $stateParams, BookmarksModel){
var editBookmarkCtrl = this; //更新成功或取消更新
function returnToBookmarks(){
$state.go('darren.categories.bookmarks',{
category: $stateParams.category
});
} function cancelEditing(){
returnToBookmarks();
} //editBookmarkCtrl.bookmark
//editBookmarkCtrl.editedBookmark
BookmarksModel.getBookmarkById($stateParams.bookmarkId)
.then(function(bookmark){
if(bookmark){
editBookmarkCtrl.bookmark = bookmark;
editBookmarkCtrl.editedBookmark = angular.copy(editBookmarkCtrl.bookmark);
} else {
returnToBookmarks();
}
}); //更新
function updateBookmark(){
editBookmarkCtrl.bookmark = angular.copy(editBookmarkCtrl.editedBookmark);
BookmarksModel.updateBookmark(editBookmarkCtrl.bookmark);
returnToBookmarks();
} editBookmarkCtrl.cancelEditing = cancelEditing;
editBookmarkCtrl.updateBookmark = updateBookmark;
})
;
以上,点击更新按钮,ui-sref="darren.categories.bookmarks.edit({bookmarkId: bookmark.id})"中的bookmarkId被url: '/bookmarks/:bookmarkId/edit'接受。state之间的关系现在变成这样:
具体来说,点击更新按钮,ui-sref="darren.categories.bookmarks.edit({bookmarkId: bookmark.id})"来到darren.categories.bookmarks.edit这个state,其中的bookmarkId被$stateParams.bookmarkId接受,配对editBookmarkCtrl和bookmark-edit.tmpl.html,bookmark-edit.tmpl.html的内容显示在bookmarks.tmpl.html中的<ui-view></ui-view>里。
bookmark.edit.tmpl.html
<h4>Editing {{editBookmarkCtrl.bookmark.title}}</h4>
<form class="edit-form" role="form" ng-submit="editBookmarkCtrl.updateBookmark(editBookmarkCtrl.editedBookmark)" novalidate>
<div class="form-group">
<label>Bookmark Title</label>
<input type="text" class="form-control" ng-model="editBookmarkCtrl.editedBookmark.title" placeholder="Enter title">
</div>
<div class="form-group">
<label>Bookmark URL</label>
<input type="text" class="form-control" ng-model="editBookmarkCtrl.editedBookmark.url" placeholder="Enter URL">
</div>
<button type="submit" class="btn btn-info btn-lg">Save</button>
<button type="button" class="btn btn-default btn-lg pull-right" ng-click="editBookmarkCtrl.cancelEditing()">Cancel</button>
</form>
bookmark-create.js
点击添加按钮。ui-sref="darren.categories.bookmarks.create",这里的darren.categories.bookmarks.create定义在了bookmark-create.js中。
angular.module('categories.bookmarks.create',[]) .config(function($stateProvider){
$stateProvider
.state('darren.categories.bookmarks.create',{
url: '/bookmarks/create',
templateUrl: 'app/categories/bookmarks/create/bookmark-create.tmpl.html',
controller: 'CreateBookmarkCtrl as createBookmarkCtrl'
});
})
.controller('CreateBookmarkCtrl', function($state, $stateParams, BookmarksModel){
var createBookmarkCtrl = this; //添加或取消完成后执行
function returnToBookmarks(){
$state.go('darren.categories.bookmarks',{
category: $stateParams.category
});
} //取消
function cancelCreating(){
returnToBookmarks();
} //添加
function createBookmark(bookmark){
BookmarksModel.createBookmark(bookmark);
returnToBookmarks();
} createBookmarkCtrl.cancelCreating = cancelCreating;
createBookmarkCtrl.createBookmark = createBookmark; //重置表单
function resetForm(){
createBookmarkCtrl.newBookmark = {
title: '',
url: '',
category: $stateParams.category
};
} resetForm();
})
;
state之间的关系现在变成这样:
具体来说,点击添加按钮。ui-sref="darren.categories.bookmarks.create",来到darren.categories.bookmarks.create这个state,由于url和url: '/bookmarks/create'格式一致,配对createBookmarkCtrl和bookmark-create.tmpl.html,上级state中的$stateParams.category被这里运用到。
bookmark-create.tmpl.html
<form class="create-form" role="form" ng-submit="createBookmarkCtrl.createBookmark(createBookmarkCtrl.newBookmark)" novalidate>
<div class="form-group">
<label for="newBookmarkTitle">Bookmark Title</label>
<input type="text" class="form-control" id="newBookmarkTitle" ng-model="createBookmarkCtrl.newBookmark.title" placeholder="Enter title">
</div>
<div class="form-group">
<label for="newBookmarkURL">Bookmark URL</label>
<input type="text" class="form-control" id="newBookmarkURL" ng-model="createBookmarkCtrl.newBookmark.url" placeholder="Enter URL">
</div>
<button type="submit" class="btn btn-info btn-lg">Create</button>
<button type="button" class="btn btn-default btn-lg pull-right" ng-click="createBookmarkCtrl.cancelCreating()">Cancel</button>
</form>
结束。☺
AngularJS的增删改查、state嵌套案例,不涉及服务端的更多相关文章
- Python列表的增删改查排嵌套特殊输出格式
Python列表的增删改查排嵌套特殊输出格式 一.列表的样子: a = ['q' , 'w' , 'e ', 'r','t'] a为列表名,[ ]为列表内容,' '为列表内的元素,'q'为a[0] 二 ...
- python之路day05--字典的增删改查,嵌套
字典dic 数据类型划分:可变数据类型,不可变数据类型 不可变数据类型:元组,bool,int str -->可哈希可变数据类型:list,dict,set --> 不可哈希 dict k ...
- python之路day04--列表的增删改查,嵌套、元组的嵌套、range、for循环嵌套
列表增删改查 增加 append li = ['taibai','zy','nvshen'] li.append('aa') print(li) #['taibai', 'zy', 'nvshen', ...
- thinkPHP增删改查的方法案例
thinkphp对数据库增删改查进行了封装操作,使得使用更加方便,但是不一定灵活. 可以用封装的用,需要写sql,可以执行sql. 1.原始的 $Model = new Model(); // 实例化 ...
- python列表的增删改查和嵌套
列表 python常用的数据类型 可承载任意的数据类型 列表是有序的,可索引.切片(步长) 列表的创建 list1 = [1, 2, 'whll'] #1. list2 = list() #2. #3 ...
- Python字典的初识、增删改查及嵌套
为什么要有字典? 列表可以存储大量的数据,但数据间的关联型不强 列表的查询速度相对慢 dict:字典,容器型数据类型 数据类型的分类: 可变与不可变 可变(不可哈希)的数据类型: 列表list,字典d ...
- Dapper逆天入门~强类型,动态类型,多映射,多返回值,增删改查+存储过程+事物案例演示
Dapper的牛逼就不扯蛋了,答应群友做个入门Demo的,现有园友需要,那么公开分享一下: 完整Demo:http://pan.baidu.com/s/1i3TcEzj 注 意 事 项:http:// ...
- 【转载】ASP.NET MVC Web API 学习笔记---联系人增删改查
本章节简单介绍一下使用ASP.NET MVC Web API 做增删改查.目前很多Http服务还是通过REST或者类似RESP的模型来进行数据操作的.下面我们通过创建一个简单的Web API来管理联系 ...
- ASP.NET MVC Web API 学习笔记---联系人增删改查
本章节简单介绍一下使用ASP.NET MVC Web API 做增删改查. 目前很多Http服务还是通过REST或者类似RESP的模型来进行数据操作的. 下面我们通过创建一个简单的Web API来管理 ...
随机推荐
- TCP长连接和短连接的区别【转】
转自:https://www.cnblogs.com/onlysun/p/4520553.html 当网络通信时采用TCP协议时,在真正的读写操作之前,server与client之间必须建立一个连接, ...
- 使用@SpringBootApplication注解
很多Spring Boot开发者总是使用@Configuration , @EnableAutoConfiguration 和 @ComponentScan 注解他们的main类. 由于这些注解被如此 ...
- centos7系统下安装配置jdk、tomcat教程
JDK安装与配置 1.下载linux版本的jdk,我下的版本是jdk6.0,下载rpm版本的. 可通过百度搜索文件名:jdk-6u45-linux-x64-rpm.bin下载 也可通过oracle官网 ...
- selenium用jquery改变元素属性
一.jQuery 语法 jQuery 语法是通过选取 HTML 元素,并对选取的元素执行某些操作. 1.基础语法: $(selector).action() 选择符(selector)即," ...
- python try详细说明(python的异常捕捉模块)
#自己常用 try: pass except Exception as e: print("break for :"+str(e)) # 划重点: 1. 正常执行try情况 pri ...
- .NetCore下 Exceptionless 分布式日志的个性化处理
Event Type 在Exceptionless中有 Exception .LogMessage.Broken Links .Feature Usages 接下来就这几种类型分别添加日志记录 Exc ...
- 如何安装pycharm
Ubuntu系统安装PyCharm教程(详细图文) 参考(http://jingyan.baidu.com/article/60ccbceb4e3b0e64cab19733.html)
- 【LOJ】#2075. 「JSOI2016」位运算
题解 压的状态是一个二进制位,我们规定1到n的数字互不相同是从小到大,二进制位记录的是每一位和后一个数是否相等,第n位记录第n个数和原串是否相等,处理出50个转移矩阵然后相乘,再快速幂即可 代码 #i ...
- WebStorm failing to start with 'idea.system.path' error
WebStorm failing to start with 'idea.system.path' error Ask Question up vote 2 down vote favorite ...
- web理论知识--HTML结构及标签
一.参考书籍: <Web 前端开发 HTML5+CSS3+jQuery+AJAX 从学到用完美实践> 备注:本书为工具书. 二.HTML5元素: 按功能划分:基础.格式.表单.框架.图像. ...