INFOR 31st
Tony Yang | t510599
> Explore those deep inside the cave.
▲ INFOR 31st Web Development 考幹題
▲ A buggy version
更簡潔,沒有像 Bootstrap 那樣雜亂的樣式名稱(如:.m-l-1, .p-x-2, .p-a-3)
以意義為樣式命名的主要精神
以支援行動裝置為優先
更加彈性的格線系統,並達到 16 格線
具有回饋力的動畫
元件之間可交互使用
模塊不需要 jQuery(耶!)
.comment.header {
position: sticky;
position: -webkit-sticky; /* Safari */
top: 0;
}
message.replace(regex, function (_match, name, id, _offset, _string) {
return `<a href="user.php?username=${id}">${name}</a>`;
});
名稱 | 內容 |
---|---|
match | 匹配到的整段字串 |
p1, p2... | 依照分組,依序填入的字串 |
offset | 位置 |
string | 將被替換的完整原始字串 |
Example:
Normally we...
-> Create eventListener for each element.
It leads to:
-> 1000 eventListener
=> lag website
$('tr').each((i, ele) => {
$(ele).on('click', function(e) {
let el = this;
// do something
});
});
$('table').on('click', 'tr', function(e) {
let el = e.currentTarget;
// do something
});
Table
Table
tr
tr
tr
tr
tr
tr
ob_start(), ob_flush(), ob_get_contents()
include/view.php
class View {
private $master_content;
// some private attribute...
public function __construct($master, $nav, $sidebar, $title, $part) {
$this->load($master,$nav,$sidebar);
ob_start();
}
private function load($master, $nav, $sidebar) {
ob_start();
include($master);
$this->master_content = ob_get_contents();
ob_end_clean();
// load navbar and sidebar...
}
public function render() {
$content = ob_get_contents();
ob_end_clean();
echo strtr($this->master_content, array(
// ...
'{content}' => $content
));
@ob_flush();
flush();
}
};
filter_var()
You can validate or sanatize specific data.
filter_var($variable [, $filter = FILTER_DEFAULT [, $options ]])
Validate filters | FILTER_VALIDATE_EMAIL FILTER_VALIDATE_IP FILTER_VALIDATE_URL |
Sanatize filters | FILTER_SANITIZE_EMAIL FILTER_SANITIZE_URL |
return sanatized value if pass
or otherwise return false
SELECT `post`.*, `user`.name FROM `post` INNER JOIN `user`
ON `post`.username = `user`.username
setInterval(() => {
axios.request({
url: "ajax/notification.php?fetch",
method: "GET"
}).done((res) => {
setNotificationCounter(res.data);
}).catch((err) => {
console.error(err);
});
});
Login
SESSION_ID
example.blog
<img src="example.blog/post?del=1">
SESSION_ID
another.site
Post deleted!
GET example.blog/post?del=1
SESSION & No Token
another.site
CSRF!
GET example.blog/post?del=1
TOKEN
example.blog
Post deleted!
& X-CSRF-TOKEN
axios.defaults.withCredentials = true;
axios.interceptors.request.use(function (config) {
var crypto = window.crypto || window.msCrypto;
let csrfToken = btoa(String(crypto.getRandomValues(new Uint32Array(1))[0]));
document.cookie = `${axios.defaults.xsrfCookieName}=${csrfToken}; max-age=10; path=/`;
return config;
}, function (error) {
return Promise.reject(error);
});
var root = "./";
var useHash = true;
var hash = "#";
let router = new Navigo(root, useHash, hash);
router.on({
'/post': function () {
render('post');
},
'/post/:id': function () {
render('post', params.id);
},
'/user/:username': function () {
render('user', params.username)
}
}).resolve();
router.hooks({
before: (done, params) => {
resetMenu();
done();
},
after: params => {
scrollTop();
}
});
<a href="/post" data-navigo>文章列表</a>
Use data-navigo attribute
router.navigate("/post")
router.navigate()
router.updatePageLinks()
router.updatePageLinks()
JavaScript 68.4% : PHP 27.3%
Cavern is inspired by, and used code of secret-blog by gdsecret, which is licensed under AGPL v3.