1、添加数学公式渲染功能;2、增加数学公式渲染自定义指令(只适用h5);3、修改package.json
parent
32ddbd1316
commit
9d073a9d06
@ -0,0 +1,6 @@
|
||||
import mathJax from './mathJax'
|
||||
|
||||
export default function registerDirectives (app) {
|
||||
// 注册全局指令
|
||||
app.directive(mathJax.name, mathJax.inserted)
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
// 该指令只支持H5
|
||||
import renderMath from '@/utils/mathJax/renderMath.js'
|
||||
|
||||
export default {
|
||||
name: 'math',
|
||||
inserted (el, binding) {
|
||||
if (!binding.value) return;
|
||||
// console.log(binding.value)
|
||||
// console.log(Reflect.ownKeys(el.__vnode.el))
|
||||
// console.log(el.__vnode)
|
||||
el.__vnode.el.innerHTML = renderMath(binding.value)
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
declare namespace UniCrazyGlobalTypes {
|
||||
interface UniCrazyRouterParams {
|
||||
passedParams?: object | null;
|
||||
routeParams?: object | null;
|
||||
}
|
||||
}
|
||||
|
||||
declare namespace UniApp {
|
||||
interface RedirectToOptions extends UniCrazyGlobalTypes.UniCrazyRouterParams {}
|
||||
interface ReLaunchOptions extends UniCrazyGlobalTypes.UniCrazyRouterParams {}
|
||||
interface SwitchTabOptions extends UniCrazyGlobalTypes.UniCrazyRouterParams {}
|
||||
interface NavigateBackOptions extends UniCrazyGlobalTypes.UniCrazyRouterParams {}
|
||||
interface NavigateToOptions extends UniCrazyGlobalTypes.UniCrazyRouterParams {}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/// <reference path="./global.d.ts" />
|
||||
type to = {
|
||||
url: string;
|
||||
query?: object | null;
|
||||
jumpType: string;
|
||||
search?: string;
|
||||
} & UniCrazyGlobalTypes.UniCrazyRouterParams;
|
||||
type from = ({
|
||||
url: string;
|
||||
query?: object | null;
|
||||
search?: string;
|
||||
} & UniCrazyGlobalTypes.UniCrazyRouterParams) | null | undefined;
|
||||
interface callWithNext {
|
||||
(hook: (to: to, from: from, next: Function) => void) : Function;
|
||||
}
|
||||
interface callWithoutNext {
|
||||
(hook: (to: to, from: from) => void): Function;
|
||||
}
|
||||
interface normalCall {
|
||||
(call: Function): void;
|
||||
}
|
||||
export const beforeEach: callWithNext;
|
||||
export const afterEach: callWithoutNext;
|
||||
export const onError: callWithoutNext;
|
||||
export const afterNotNext: normalCall;
|
||||
interface uniCrazyRouter {
|
||||
beforeEach: callWithNext;
|
||||
afterEach: callWithoutNext;
|
||||
onError: callWithoutNext;
|
||||
afterNotNext: normalCall;
|
||||
install: any;
|
||||
}
|
||||
declare const uniCrazyRouter: uniCrazyRouter;
|
||||
export default uniCrazyRouter;
|
||||
// for Vue2
|
||||
declare module "vue/types/vue" {
|
||||
interface Vue {
|
||||
$routeParams?: object | null;
|
||||
$passedParams?: object | null;
|
||||
}
|
||||
}
|
||||
|
||||
// for Vue3
|
||||
declare module '@vue/runtime-core' {
|
||||
interface ComponentCustomProperties {
|
||||
$routeParams?: object | null;
|
||||
$passedParams?: object | null;
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,49 @@
|
||||
/// <reference path="./global.d.ts" />
|
||||
type to = {
|
||||
url: string;
|
||||
query?: object | null;
|
||||
jumpType: string;
|
||||
search?: string;
|
||||
} & UniCrazyGlobalTypes.UniCrazyRouterParams;
|
||||
type from = ({
|
||||
url: string;
|
||||
query?: object | null;
|
||||
search?: string;
|
||||
} & UniCrazyGlobalTypes.UniCrazyRouterParams) | null | undefined;
|
||||
interface callWithNext {
|
||||
(hook: (to: to, from: from, next: Function) => void) : Function;
|
||||
}
|
||||
interface callWithoutNext {
|
||||
(hook: (to: to, from: from) => void): Function;
|
||||
}
|
||||
interface normalCall {
|
||||
(call: Function): void;
|
||||
}
|
||||
export const beforeEach: callWithNext;
|
||||
export const afterEach: callWithoutNext;
|
||||
export const onError: callWithoutNext;
|
||||
export const afterNotNext: normalCall;
|
||||
interface uniCrazyRouter {
|
||||
beforeEach: callWithNext;
|
||||
afterEach: callWithoutNext;
|
||||
onError: callWithoutNext;
|
||||
afterNotNext: normalCall;
|
||||
install: any;
|
||||
}
|
||||
declare const uniCrazyRouter: uniCrazyRouter;
|
||||
export default uniCrazyRouter;
|
||||
// for Vue2
|
||||
declare module "vue/types/vue" {
|
||||
interface Vue {
|
||||
$routeParams?: object | null;
|
||||
$passedParams?: object | null;
|
||||
}
|
||||
}
|
||||
|
||||
// for Vue3
|
||||
declare module '@vue/runtime-core' {
|
||||
interface ComponentCustomProperties {
|
||||
$routeParams?: object | null;
|
||||
$passedParams?: object | null;
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,14 @@
|
||||
.search-btn {
|
||||
// margin-top: 15px;
|
||||
// margin-left: 20px;
|
||||
// margin-bottom: 15px;
|
||||
// margin-left: 50%;
|
||||
// transform: translateX(-50%);
|
||||
}
|
||||
|
||||
// 隐藏canvas
|
||||
uni-canvas {
|
||||
// position: absolute;
|
||||
// top: -1000px;
|
||||
// left: -1000px;
|
||||
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,90 @@
|
||||
import katex from "katex";
|
||||
import splitAtDelimiters from "./splitAtDelimiters";
|
||||
|
||||
const renderMathInText = function(text, optionsCopy) {
|
||||
const data = splitAtDelimiters(text, optionsCopy.delimiters);
|
||||
if (data.length === 1 && data[0].type === 'text') {
|
||||
// There is no formula in the text.
|
||||
// Let's return null which means there is no need to replace
|
||||
// the current text node with a new one.
|
||||
return data[0].data;
|
||||
}
|
||||
|
||||
let html = ''
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
if (data[i].type === "text") {
|
||||
html += data[i].data;
|
||||
} else {
|
||||
let math = data[i].data;
|
||||
// Override any display mode defined in the settings with that
|
||||
// defined by the text itself
|
||||
optionsCopy.displayMode = data[i].display;
|
||||
try {
|
||||
if (optionsCopy.preProcess) {
|
||||
math = optionsCopy.preProcess(math);
|
||||
}
|
||||
html += katex.renderToString(math, optionsCopy);
|
||||
} catch (e) {
|
||||
if (!(e instanceof katex.ParseError)) {
|
||||
throw e;
|
||||
}
|
||||
optionsCopy.errorCallback(
|
||||
"KaTeX auto-render: Failed to parse `" + data[i].data +
|
||||
"` with ",
|
||||
e
|
||||
);
|
||||
html += data[i].rawData;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return html;
|
||||
};
|
||||
|
||||
const renderMath = function(text, options) {
|
||||
if (!text) {
|
||||
throw new Error("No text provided to render");
|
||||
}
|
||||
|
||||
const optionsCopy = {};
|
||||
|
||||
// Object.assign(optionsCopy, option)
|
||||
for (const option in options) {
|
||||
if (options.hasOwnProperty(option)) {
|
||||
optionsCopy[option] = options[option];
|
||||
}
|
||||
}
|
||||
|
||||
// default options
|
||||
optionsCopy.delimiters = optionsCopy.delimiters || [
|
||||
{left: "$$", right: "$$", display: true},
|
||||
{left: "\\(", right: "\\)", display: false},
|
||||
// LaTeX uses $…$, but it ruins the display of normal `$` in text:
|
||||
{left: "$", right: "$", display: false},
|
||||
// $ must come after $$
|
||||
|
||||
// Render AMS environments even if outside $$…$$ delimiters.
|
||||
{left: "\\begin{equation}", right: "\\end{equation}", display: true},
|
||||
{left: "\\begin{align}", right: "\\end{align}", display: true},
|
||||
{left: "\\begin{alignat}", right: "\\end{alignat}", display: true},
|
||||
{left: "\\begin{gather}", right: "\\end{gather}", display: true},
|
||||
{left: "\\begin{CD}", right: "\\end{CD}", display: true},
|
||||
|
||||
{left: "\\[", right: "\\]", display: true},
|
||||
];
|
||||
optionsCopy.ignoredTags = optionsCopy.ignoredTags || [
|
||||
"script", "noscript", "style", "textarea", "pre", "code", "option",
|
||||
];
|
||||
optionsCopy.ignoredClasses = optionsCopy.ignoredClasses || [];
|
||||
optionsCopy.errorCallback = optionsCopy.errorCallback || console.error;
|
||||
|
||||
// Enable sharing of global macros defined via `\gdef` between different
|
||||
// math elements within a single call to `renderMathInElement`.
|
||||
optionsCopy.macros = optionsCopy.macros || {};
|
||||
|
||||
return renderMathInText(text, optionsCopy);
|
||||
};
|
||||
|
||||
export default renderMath;
|
@ -0,0 +1,85 @@
|
||||
/* eslint no-constant-condition:0 */
|
||||
const findEndOfMath = function(delimiter, text, startIndex) {
|
||||
// Adapted from
|
||||
// https://github.com/Khan/perseus/blob/master/src/perseus-markdown.jsx
|
||||
let index = startIndex;
|
||||
let braceLevel = 0;
|
||||
|
||||
const delimLength = delimiter.length;
|
||||
|
||||
while (index < text.length) {
|
||||
const character = text[index];
|
||||
|
||||
if (braceLevel <= 0 &&
|
||||
text.slice(index, index + delimLength) === delimiter) {
|
||||
return index;
|
||||
} else if (character === "\\") {
|
||||
index++;
|
||||
} else if (character === "{") {
|
||||
braceLevel++;
|
||||
} else if (character === "}") {
|
||||
braceLevel--;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
};
|
||||
|
||||
const escapeRegex = function(string) {
|
||||
return string.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
|
||||
};
|
||||
|
||||
const amsRegex = /^\\begin{/;
|
||||
|
||||
const splitAtDelimiters = function(text, delimiters) {
|
||||
let index;
|
||||
const data = [];
|
||||
|
||||
const regexLeft = new RegExp(
|
||||
"(" + delimiters.map((x) => escapeRegex(x.left)).join("|") + ")"
|
||||
);
|
||||
|
||||
while (true) {
|
||||
index = text.search(regexLeft);
|
||||
if (index === -1) {
|
||||
break;
|
||||
}
|
||||
if (index > 0) {
|
||||
data.push({
|
||||
type: "text",
|
||||
data: text.slice(0, index),
|
||||
});
|
||||
text = text.slice(index); // now text starts with delimiter
|
||||
}
|
||||
// ... so this always succeeds:
|
||||
const i = delimiters.findIndex((delim) => text.startsWith(delim.left));
|
||||
index = findEndOfMath(delimiters[i].right, text, delimiters[i].left.length);
|
||||
if (index === -1) {
|
||||
break;
|
||||
}
|
||||
const rawData = text.slice(0, index + delimiters[i].right.length);
|
||||
const math = amsRegex.test(rawData)
|
||||
? rawData
|
||||
: text.slice(delimiters[i].left.length, index);
|
||||
data.push({
|
||||
type: "math",
|
||||
data: math,
|
||||
rawData,
|
||||
display: delimiters[i].display,
|
||||
});
|
||||
text = text.slice(index + delimiters[i].right.length);
|
||||
}
|
||||
|
||||
if (text !== "") {
|
||||
data.push({
|
||||
type: "text",
|
||||
data: text,
|
||||
});
|
||||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
export default splitAtDelimiters;
|
@ -0,0 +1,9 @@
|
||||
export function createScript(src) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const script = document.createElement('script');
|
||||
script.src = src;
|
||||
script.onload = () => resolve(script);
|
||||
script.onerror = () => reject(new Error(`Script load error for ${src}`));
|
||||
document.head.append(script);
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue