天气小组件
// ==UserScript==
// @name 天气小组件
// @namespace https://bbs.tampermonkey.net.cn/
// @version 0.1.6
// @description ctrl + x 呼出或关闭面板;功能: 查询天气(目前就这一个功能);天气默认显示地区:北京(搜索框内输入地区名称后回车即可更新天气,自动保存最后一次查询的地区信息)
// @author 张仨
// @grant unsafeWindow
// @grant GM_addStyle
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_xmlhttpRequest
// @match *://*/*
// @connect api.szfx.top
// @require https://cdn.jsdelivr.net/npm/vue@3.2.31/dist/vue.global.prod.js
// ==/UserScript==
unsafeWindow.Vue = Vue;
var myapp = document.createElement('div');
document.body.appendChild(myapp)
myapp.id = 'my-app';
unsafeWindow.onkeydown = function (e) {
if (e.ctrlKey && e.key == 'x') {
if (myapp.style.display == 'block') {
myapp.style.display = 'none'
} else {
myapp.style.display = 'block'
}
}
}
myapp.innerHTML = `
<div class="my-box">
<div class="my-search">
<input type="text" class="my-search__input" placeholder="Search..." v-model="search" @keyup.enter="weatherSearch" />
<div class="my-search__icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<path
d="M456.69 421.39L362.6 327.3a173.81 173.81 0 0034.84-104.58C397.44 126.38 319.06 48 222.72 48S48 126.38 48 222.72s78.38 174.72 174.72 174.72A173.81 173.81 0 00327.3 362.6l94.09 94.09a25 25 0 0035.3-35.3zM97.92 222.72a124.8 124.8 0 11124.8 124.8 124.95 124.95 0 01-124.8-124.8z">
</path>
</svg>
</div>
</div>
<div class="my-icon">
<div class="icon__account">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 17 17">
<path
d="M12.566,8 L15.611,4.956 C16.031,4.535 16.031,3.853 15.611,3.434 L12.566,0.389 C12.146,-0.031 11.464,-0.031 11.043,0.389 L7.999,3.433 L4.955,0.389 C4.534,-0.031 3.852,-0.031 3.432,0.389 L0.388,3.434 C-0.034,3.854 -0.034,4.536 0.387,4.956 L3.431,8 L0.387,11.044 C-0.034,11.465 -0.034,12.147 0.388,12.567 L3.432,15.611 C3.852,16.032 4.534,16.032 4.955,15.611 L7.999,12.567 L11.043,15.611 C11.464,16.032 12.146,16.032 12.566,15.611 L15.611,12.567 C16.031,12.146 16.031,11.464 15.611,11.044 L12.566,8 L12.566,8 Z">
</path>
</svg>
</div>
</div>
<welcome-words :datetime="datetime" :ganmao="ganmao"></welcome-words>
<my-messages v-for="post in posts" :key="post.id" :id="post.id":time="post.time" :message="post.message"></my-messages>
</div>`
function Ajax(area) {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: "GET",
responseType: "json",
url: "https://api.szfx.top/weather/?city=" + area,
onload: function (xhr) {
console.log(xhr)
if (xhr.readyState === 4 && xhr.status === 200) {
resolve(xhr.response.data)
} else {
reject("获取数据失败")
}
}
})
})
}
function getTime() {
var weekday = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"];
var time = new Date();
var year = time.getFullYear();
var month = time.getMonth() + 1;
var date = time.getDate();
var week = weekday[time.getDay()];
var hours = time.getHours();
var minutes = time.getMinutes();
if (minutes.toString().length < 2) { minutes = "0" + minutes };
var seconds = time.getSeconds();
if (seconds.toString().length < 2) { seconds = "0" + seconds };
return (`${year}年${month}月${date}日 ${week} ${hours} : ${minutes} : ${seconds}`);
}
const app = Vue.createApp({
data() {
return {
posts: [
{ id: 'weather1', time: '', message: '' },
{ id: 'weather2', time: '', message: '' },
{ id: 'weather3', time: '', message: '' },
{ id: 'weather4', time: '', message: '' },
{ id: 'weather5', time: '', message: '' }
],
search: GM_getValue('newSearch') || '北京',
datetime: '',
ganmao: ''
}
},
mounted() {
this.weatherSearch()
setInterval(() => {
this.datetime = '现在是北京时间:' + getTime()
}, 1000)
},
methods: {
weatherSearch() {
var newAjax = new Ajax(this.search)
newAjax.then(res => {
GM_setValue('newSearch', this.search)
this.ganmao = "温馨提示:" + res.ganmao
for (let i = 0; i < this.posts.length; i++) {
this.posts[i].time = res.forecast[i].date
this.posts[i].message = "天气:" + res.forecast[i].type + "\n" + " 高温:" + res.forecast[i].high + "\n" + " 低温:" + res.forecast[i].low
}
}).catch(error => {
for (let i = 0; i < this.posts.length; i++) {
this.posts[i].message = error
}
})
}
}
})
app.component('welcome-words', {
props: ['datetime', 'ganmao'],
template: `
<div class="words-box">
<span>{{ datetime }}</span>
<span>{{ ganmao }}</span>
</div>`
})
app.component('my-messages', {
props: ['time', 'message', 'id'],
template: `
<div class="my-message" :id="id">
<p>{{ time }}</p>
{{ message }}
</div>`
})
app.mount('#my-app')
var icon__account = document.querySelector('.icon__account')
icon__account.onclick = function () {
myapp.style.display = 'none'
}
GM_addStyle(`
#my-app {
display: none;
}
.my-box {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
width: 780px !important;
height: 280px !important;
z-index: 9999999;
background: #E4EBF5;
border-radius: 15px;
box-shadow: 0.8rem 0.8rem 1.4rem #c8d0e7, -0.2rem -0.2rem 1.8rem #FFFFFF;
padding: 10px;
display: grid;
grid-template-columns: repeat(7, 1fr);
grid-template-rows: repeat(3, 1fr);
grid-column-gap: 0px;
grid-row-gap: 0px;
}
.my-search {
position: absolute;
top: 20px;
left: 20px;
cursor: pointer;
display: flex;
align-items: center;
}
.my-search__input {
width: 180px !important;
height: 50px !important;
border: none;
border-radius: 15px;
font-size: 22px;
padding-left: 60px;
box-shadow: inset 0.2rem 0.2rem 0.5rem #c8d0e7, inset -0.2rem -0.2rem 0.5rem #FFFFFF;
background: none;
font-family: inherit;
color: #9baacf;
z-index: 9999999;
}
.my-search__input::-moz-placeholder {
color: #bec8e4;
}
.my-search__input:-ms-input-placeholder {
color: #bec8e4;
}
.my-search__input::placeholder {
color: #bec8e4;
}
.my-search__input:focus {
outline: none;
box-shadow: 0.3rem 0.3rem 0.6rem #c8d0e7, -0.2rem -0.2rem 0.5rem #FFFFFF;
}
.my-search__input:focus+.my-search__icon {
fill: #6d5dfc;
}
.my-search__icon {
height: 32px;
position: absolute;
font-size: 36px;
padding: 0 16px;
display: flex;
transition: 0.3s ease;
fill: #bec8e4;
}
.my-icon {
position: absolute;
top: 10px;
right: 10px;
display: flex;
justify-content: space-between;
}
.icon__account,
.icon__home,
.icon__settings {
width: 60px;
height: 60px;
margin: 10px;
border-radius: 50%;
box-shadow: 0.3rem 0.3rem 0.6rem #c8d0e7, -0.2rem -0.2rem 0.5rem #FFFFFF;
display: flex;
justify-content: center;
align-items: center;
font-size: 2rem;
cursor: pointer;
fill: #9baacf;
transition: all 0.5s ease;
}
.icon__account svg,
.icon__home svg,
.icon__settings svg {
width: 30px;
height: 30px;
}
.icon__account:active,
.icon__home:active,
.icon__settings:active {
box-shadow: inset 0.2rem 0.2rem 0.5rem #c8d0e7, inset -0.2rem -0.2rem 0.5rem #FFFFFF;
fill: #6d5dfc;
}
.icon__account:hover,
.icon__home:hover,
.icon__settings:hover {
fill: #6d5dfc;
}
.words-box {
grid-area: 1 / 2 / 2 / 6;
color: #6d5dfc;
font-size: 14px !important;
padding-left: 80px;
}
.words-box span {
display: block;
margin: 10px;
}
.my-message {
color: #6d5dfc;
width: 140px !important;
height: 160px !important;
font-size: 14px !important;
margin-left: 10px;
box-shadow: 0.3rem 0.3rem 0.6rem #c8d0e7, -0.2rem -0.2rem 0.5rem #FFFFFF;
border-radius: 15px;
white-space: pre;
}
#weather1 { grid-area: 3 / 1 / 3 / 2; }
#weather2 { grid-area: 3 / 2 / 3 / 3; }
#weather3 { grid-area: 3 / 3 / 3 / 4; }
#weather4 { grid-area: 3 / 4 / 3 / 5; }
#weather5 { grid-area: 3 / 5 / 3 / 6; }
#weather6 { grid-area: 3 / 6 / 3 / 7; }
#weather7 { grid-area: 3 / 7 / 3 / 8; }
.my-message p {
margin: 10px;
text-align: center;
}
`)