從頭開始一步一步將 youtube 筆記功能做一下整理
由於有使用 vue ,所以下載 Vue 的範本使用 :
$ npm install -g vue-cli
$ vue init YuraDev/vue-chrome-extension-template my-project
$ cd my-project
$ npm install
$ npm run dev
該範本有使用 eslint
,如果要避免嚴格規則的錯誤,可以到 core\webpack.base.js
再 rule
底下註解掉 :
下載 JQuery 檔案,並放到 src 的 lib 資料夾
在 core 找到 webpack.base.js 的 entry 添加 jquery : resolve('./lib/jquery-3.3.1.min.js')
entry: {
tab: resolve('./tab'),
popup: resolve('./popup'),
options: resolve('./options'),
content: resolve('./content'),
devtools: resolve('./devtools'),
background: resolve('./backend'),
panel: resolve('./devtools/panel'),
inject: resolve('./content/inject'),
jquery : resolve('./lib/jquery-3.3.1.min.js'),
},
manifest.js 的 content_scripts 修正為 :
content_scripts: [{
js: [ 'js/jquery.js','js/content.js' ],
run_at: 'document_end',
matches: ['https://www.youtube.com/*'],
all_frames: true
}],
修改 content\index.js
import Vue from 'vue'
import root from './content.vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.config.productionTip = false
Vue.use(ElementUI)
var vueLoop = setInterval(function() {
if($('#related').length > 0 && $('#items').length){
$('<div id="root"></div').prependTo( "#related");
new Vue({
el: '#root',
render: h => h(root)
});
clearTimeout(vueLoop);
}
}, 500);
在 content 資料夾底下建立 content.vue
content.vue 內容 :
其他備註 - 資料儲存發現無法使用變數來存,導致資料存取有問題,所以採取全讀的方式 :
var myName ="helloData";
chrome.storage.sync.set({ myName: "123" }, function() {});
儲存的 key 會是 myName
而不是 helloData
chrome.storage.sync.get("helloData", function(result) {
console.log(result);
})
chrome.storage.sync.get("myName", function(result) {
console.log(result);
})
其他備註 - 點選其他影片時不會重載網頁,所以使用迴圈檢查影片參數(v) :
showTime(){
var vm = this;
(function() {
let animationTimer = setInterval(function() {
var videoKey = vm.getParameter('v');
if (videoKey != vm.videoKey) {
vm.videoKey = videoKey;
vm.items = [];
vm.loadData();
}
var video = document.getElementsByClassName('video-stream')[0];
vm.isPaused = video.paused;
var t = Math.floor(video.currentTime);
if (vm.currentTime !== t) {
vm.currentTime = t;
}
}, 500);
})();
}
其他備註 - youtube 影片使用 Html5 Video 所以可以用它來操作影片相關功能 :
var video = document.getElementsByClassName('video-stream')[0];
video.currentTime = time; //指定時間
video.pause(); //暫停
video.play(); //播放
video.paused; //狀態,是否暫停
content.vue 的 templdate 部分 :
<template>
<el-container>
<el-main>
<el-row v-show="!isPaused">
<el-col>
<el-button type="primary" @click="play()">輸入訊息</el-button>
</el-col>
</el-row>
<el-row v-show="isPaused">
<el-col>
<el-button type="success" @click="addData()">儲存</el-button>
<el-button type="primary" @click="play()">繼續撥放</el-button>
</el-col>
</el-row>
<el-row v-show="isPaused">
<el-col>
<el-input type="textarea" :rows="2" placeholder="请输入内容" v-model="currentMessage"></el-input>
</el-col>
</el-row>
<el-row>
<el-col :span="16">
<ul v-for="(item,index) in items">
<li>
<el-button type="danger" size="mini" icon="el-icon-delete" circle @click=deleteItem(index)></el-button>
<el-button size="mini" @click="gotoTime(item.time)">{{getMinSec(item.time)}} - {{item.message}}</el-button>
</li>
</ul>
</el-col>
</el-row>
</el-main>
</el-container>
</template>
content.vue 的 script 部分 :
<script>
export default {
data: () => ({
currentTime: 0,
currentMessage: '',
items: [],
videoKey: '',
isPaused: false
}),
computed: {},
created() {},
mounted() {
this.videoKey = this.getParameter('v');
this.showTime();
this.loadData();
},
updated() {
},
computed: {
},
methods: {
play() {
document.querySelector('.ytp-play-button').click();
},
getMinSec(t) {
return Math.floor(t / 60) + '分' + (t % 60) + '秒';
},
gotoTime(time){
var video = document.getElementsByClassName('video-stream')[0];
video.currentTime = time;
video.pause();
},
showTime(){
var vm = this;
(function() {
let animationTimer = setInterval(function() {
var videoKey = vm.getParameter('v');
if (videoKey != vm.videoKey) {
vm.videoKey = videoKey;
vm.items = [];
vm.loadData();
}
var video = document.getElementsByClassName('video-stream')[0];
vm.isPaused = video.paused;
var t = Math.floor(video.currentTime);
if (vm.currentTime !== t) {
vm.currentTime = t;
}
}, 500);
})();
},
loadData() {
var vm = this;
chrome.storage.sync.get("tempData", function(result) {
if (result !== undefined) {
var tempData = result.tempData;
var jsonResult = [];
if (tempData !== undefined) {
jsonResult = tempData;
}
jsonResult.forEach(function(video) {
if (video.videoKey == vm.videoKey) {
vm.items = video.items;
}
})
}
if (vm.items === undefined) {
vm.items = [];
}
});
},
addData() {
var vm = this;
var filterByTime = vm.items.filter(function(item, index, array) {
return item.time == vm.currentTime;
});
if (filterByTime.length > 0) {
vm.items.forEach(function(item, index, array) {
if (item.time == vm.currentTime) {
item.message = vm.currentMessage;
}
});
} else {
var item = {
time: vm.currentTime,
message: vm.currentMessage
}
vm.items.push(item);
}
vm.saveData();
},
saveData(){
var vm = this;
chrome.storage.sync.get("tempData", function(result) {
var tempData = result.tempData;
var jsonResult = [];
if (tempData !== undefined) {
jsonResult = tempData;
}
var isExist = false;
jsonResult.forEach(function(video) {
if (video.videoKey == vm.videoKey) {
video.items = vm.items;
isExist = true;
}
});
if (!isExist) {
var videoItem = {
videoKey: vm.videoKey,
items: vm.items
};
jsonResult.push(videoItem);
}
chrome.storage.sync.set({ "tempData": jsonResult }, function() {});
});
},
deleteItem(index){
var vm = this;
vm.items.splice(index,1);
vm.saveData();
},
getParameter(name, url) {
if (!url) url = window.location.href;
name = name.replace(/[\[\]]/g, "\\$&");
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, " "));
}
},
watch: {
currentTime: function(newValue, oldValue) {
var vm = this;
var filterA = vm.items.filter(function(item, index, array) {
return item.time == newValue;
});
if (filterA.length > 0) {
vm.currentMessage = filterA[0].message;
} else {
vm.currentMessage = '';
}
}
}
}
</script>
執行結果 - 最終完成可以在網頁上增加類似影片標籤的功能 :
感謝收看 :)