拿一段 code 放著,在頁面上會插入 code。
用 webpack 做 plugin,因為 webpack 可以把東西包成 library。
改成 JS
因為之後內容都只有 JS,所以要將全部東西都改成 JS。所以 HTML、CSS 都要拿掉。
終極目標:BODY 為空,所有東西都以 JS 動態新增
先拿掉 callback function
先將這個拿掉,解放裡面的東西,現在裡面只有 getComments()
$(document).ready( () => {})
宣告初始化 function
如果在另外一個頁面,
假設最後打包出的是 commentPlugin,傳一些參數他就回給我一個留言板。
commentPlugin.init({
apiUrl: '',
siteKey: 'anglea',
containerSelector: '#comments' //將plugin放在哪
})
要放到外面是因為其他 function 也要用到,另外 selector 本身不會用到所以先宣告為 null
let siteKey = ''
let apiUrl = ''
let containerElement = null
function init(options) {
siteKey = options.siteKey
apiUrl = options.apiUrl
containerElement = $(options.container)
}
呼叫 init function,做完會解釋
init({
siteKey: 'angela',
apiUrl: 'http://mentor-program.co/mtr04group3/s103071049/week12/hw1/api_comments.php',
containerElement: '.comments-area'
})
將留言區變成用 JS 產生,
將 HTML 變成 formTemplate,目的是為了之後的動態產生。
<form class="add-comment-form">
<label for="form-nickname" class="form-label">暱稱</label>
<input type="text" class="form-nickname" id="form-nickname" name="nickname">
<div class="mb-3">
<label for="comments__block" class="form-label">留言內容</label>
<textarea class="form-control" id="comments__block" rows="3" name="content"></textarea>
</div>
<button type="submit" class="btn btn-primary">送出留言</button>
</form>
<div class="comments__list">
</div>
const formTemplate = `
<div>
<form class="add-comment-form">
<label for="form-nickname" class="form-label">暱稱</label>
<input type="text" class="form-nickname" id="form-nickname" name="nickname">
<div class="mb-3">
<label for="comments__block" class="form-label">留言內容</label>
<textarea class="form-control" id="comments__block" rows="3" name="content"></textarea>
</div>
<button type="submit" class="btn btn-primary">送出留言</button>
</form>
<div class="comments__list">
</div>
</div>
`
有了 formTemplate,將他用 js 方式動態放上
function init(options) {
siteKey = options.siteKey
apiUrl = options.apiUrl
containerElement = $(options.container)
containerElement.append(formTemplate)
}
<body>
<div class="container">
<div class="comments-area"></div>
</div>
</body>
因為執行順序的問題,放置位置導致 dom 的物件還沒載入完。
解決方式:
方式一、將 <script src="index.js"></script>
放到 </body>
前。
方式二、dom 的結構準備好後,才做初始化。
$(document).ready( () => {
init({
siteKey: 'angela',
apiUrl: 'http://mentor-program.co/mtr04group3/s103071049/week12/hw1/api_comments.php',
containerSelector: '.comments-area'
})
})
將這一堆放到 init
getComments()
$('.comments__list').on('click', '.load-more', () => {
getComments()
})
$('.add-comment-form').submit( (e) => {
e.preventDefault()
const datas = {
'site_key': 'angela',
'nickname' : $('input[name=nickname]').val(),
'content' : $('textarea[name=content]').val(),
}
$.ajax({
type: 'POST',
url: 'http://mentor-program.co/mtr04group3/s103071049/week12/hw1/api_add_comments.php',
data: datas
}).done(function(data) {
if (!data.ok) {
alert(data.msg)
return
}
$('input[name=nickname]').val(''),
$('textarea[name=content]').val('')
const commentToDom = $('.comments__list')
appendCommentToDom(commentToDom, datas, true)
})
})
調整所有相關地方的 url
url: `${apiUrl}/api_add_comments.php`
透過 siteKey 來區分不同的網站。
css 動態放入 js
var css = 'h1 { background: red; }',
head = document.head || document.getElementsByTagName('head')[0],
style = document.createElement('style');
head.appendChild(style);
style.type = 'text/css';
if (style.styleSheet){
// This is required for IE8 and below.
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
所以原本的 css 這樣改
const css = `
.card {
margin-top: 12px;
margin-bottom: 12px;
}
body {
padding: 12px;
}
`
function init(options) {
siteKey = options.siteKey
apiUrl = options.apiUrl
containerElement = $(options.containerSelector)
containerElement.append(formTemplate)
commentDom = $('.comments__list')
const styleElement = document.createElement('style') // 新建立一個 style 元素
styleElement.type = 'text/css' // 指定 styleElement 的 type
styleElement.appendChild(document.createTextNode(css)
document.head.appendChild(styleElement) // 將 styleElement 給放進去
// 下面 code 同之前,所以略
}
變成 js 後就可以搬到 webpack 去。先做 webpack 的環境設置,做完後將 js 檔案放到 src 中。在 src 中新增檔案 api.js,先來模組化原本的檔案。
api.js 中加入這兩個 function
export function getComments(apiUrl, siteKey, before, cb) {
let url = `${apiUrl}/api_comments.php?site_key=` + siteKey
if (before) {
url += '&before=' + before
}
$.ajax({
url,
}).done(function(data) {
cb(data)
})
}
export function addComments(apiUrl, siteKey, data, cb) {
$.ajax({
type: 'POST',
url: `${apiUrl}/api_add_comments.php`,
data
}).done(function(data) {
cb(data)
})
}
在 index.js 中引入這兩個函式,又因為 getComments 撞名,所以將原本的 getComments 取名為 getNewComments
import {getComments, addComments} from './api'
jQuery 也要引入、另外將常用的函式放到 utils.js、固定引入的變數放入 templates.js,用 export 的方式輸出。
另外,index.html 要放打包好的 js
<script src="./dist/main.js"></script>
確定可以跑後,優化初始化 code
這一段程式碼,是我們想要移到外面變成 plugin 形式。
$(document).ready( () => {
init({
siteKey: 'angela',
apiUrl: 'http://mentor-program.co/mtr04group3/s103071049/week12/hw1',
containerSelector: '.comments-area'
})
})
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
library: 'commentPlugin', // 加這個,就會把 library build 成一個 global 變數
},
修正細節
撞名問題
透過加 prefix 改善。首先,將 template 寫死的 classname 改成 function 形式。
export function getLoadMoreButton(className) {
return `<button type="submit" class="${className} btn btn-primary">載入更多</button>`
}
// prefix 不同,className 就會不一樣
將 index.js 相對應的地方換掉。
lastId = comments[length-1].id
const lodaMoreButtonHTML = getLoadMoreButton(siteKey)
$('.comments__list').append(lodaMoreButtonHTML)
找出哪些地方有衝突,調整那些地方。
.init 做了兩次,但因為參數放在 module 裡面會被共用,
<script>
$(document).ready( () => {
commentPlugin.init({
siteKey: 'angela',
apiUrl: 'http://mentor-program.co/mtr04group3/s103071049/week12/hw1',
containerSelector: '.comments-area'
})
})
$(document).ready( () => {
commentPlugin.init({
siteKey: 'angela2',
apiUrl: 'http://mentor-program.co/mtr04group3/s103071049/week12/hw1',
containerSelector: '.comments-area2'
})
})
</script>